feat(units): customizable units (#984)

This commit is contained in:
Rémi Marseault 2023-07-20 13:50:46 +02:00 committed by GitHub
parent b5788a261f
commit 0594af387f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
60 changed files with 444 additions and 518 deletions

74
package-lock.json generated
View file

@ -2876,23 +2876,6 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.0.0.tgz",
"integrity": "sha512-o4q0KHlgCZTqjuaZ25nw5W57NeykZT9LiMEG4do/ovwvOcPnDO1BI5BQdCsUkjxFyrCL0cSzLjvIMfR9uo7cWg==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "6.0.0",
"@typescript-eslint/visitor-keys": "6.0.0"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.1.0.tgz",
@ -2977,46 +2960,6 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/types": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.0.0.tgz",
"integrity": "sha512-Zk9KDggyZM6tj0AJWYYKgF0yQyrcnievdhG0g5FqyU3Y2DRxJn4yWY21sJC0QKBckbsdKKjYDV2yVrrEvuTgxg==",
"dev": true,
"engines": {
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.0.0.tgz",
"integrity": "sha512-2zq4O7P6YCQADfmJ5OTDQTP3ktajnXIRrYAtHM9ofto/CJZV3QfJ89GEaM2BNGeSr1KgmBuLhEkz5FBkS2RQhQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "6.0.0",
"@typescript-eslint/visitor-keys": "6.0.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
"semver": "^7.5.0",
"ts-api-utils": "^1.0.1"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/@typescript-eslint/utils": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.1.0.tgz",
@ -3116,23 +3059,6 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.0.0.tgz",
"integrity": "sha512-cvJ63l8c0yXdeT5POHpL0Q1cZoRcmRKFCtSjNGJxPkcP571EfZMcNbzWAc7oK3D1dRzm/V5EwtkANTZxqvuuUA==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "6.0.0",
"eslint-visitor-keys": "^3.4.1"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@vitejs/plugin-vue2": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue2/-/plugin-vue2-2.2.0.tgz",

View file

@ -1,5 +1,7 @@
import { formatBytes } from '@/helpers'
import store from '@/store'
import {formatSpeed} from '@/filters'
import {formatProgress} from '@/filters'
import {Torrent} from '@/models'
export class DocumentTitle {
private static setDefault() {
@ -8,25 +10,26 @@ export class DocumentTitle {
private static setGlobalSpeed() {
const status = store.getters.getStatus()
this.set(`[D: ${formatBytes(status.dlspeed)}/s, U: ${formatBytes(status.upspeed)}/s] VueTorrent`)
const useBitSpeed = store.state.webuiSettings.useBitSpeed
this.set(`[D: ${formatSpeed(status.dlspeed, useBitSpeed)}, U: ${formatSpeed(status.upspeed, useBitSpeed)}] VueTorrent`)
}
private static setFirstTorrentStatus() {
const torrents = store.getters.getTorrents()
if (!torrents && !torrents.length) return
const useBitSpeed = store.state.webuiSettings.useBitSpeed
const torrents: Torrent[] = store.getters.getTorrents()
if (!torrents || !torrents.length) return
const torrent = torrents[0]
this.set(`[D: ${formatBytes(torrent.dlspeed)}/s, U: ${formatBytes(torrent.upspeed)}/s] ${torrent.progress}%`)
this.set(`[D: ${formatSpeed(torrent.dlspeed, useBitSpeed)}, U: ${formatSpeed(torrent.upspeed, useBitSpeed)}] ${formatProgress(torrent.progress)}`)
}
public static update() {
const mode = store.getters.getWebuiSettings().title
switch (mode) {
case 'Default':
return this.setDefault()
case 'Global Speed':
return this.setGlobalSpeed()
case 'First Torrent Status':
return this.setFirstTorrentStatus()
case 'Default':
default:
return this.setDefault()
}

View file

@ -8,41 +8,34 @@
</v-flex>
<v-layout column xs10>
<v-flex class="text-center font-weight-bold robot-mono">
<span data-testid="SpeedCard-value">
{{ value | getSpeedValue }}
</span>
<span data-testid="SpeedCard-value">{{ value | formatSpeedValue(shouldUseBitSpeed()) }}</span>
</v-flex>
<v-flex class="caption robot-mono text-center mt-n1">
<span data-testid="SpeedCard-unit"> {{ value | getDataUnit(1) }}/s </span>
<span data-testid="SpeedCard-unit">{{ value | formatSpeedUnit(shouldUseBitSpeed()) }}</span>
</v-flex>
</v-layout>
</v-layout>
</v-card>
</template>
<script>
<script lang="ts">
import { defineComponent } from 'vue'
import { mapGetters } from 'vuex'
import { General } from '@/mixins'
export default {
export default defineComponent({
name: 'SpeedCard',
filters: {
getSpeedValue(value) {
if (!value) return '0'
const c = 1024
const d = value > 1048576 ? 1 : 0 // 2 decimals when MB
const f = Math.floor(Math.log(value) / Math.log(c))
return `${parseFloat((value / Math.pow(c, f)).toFixed(d))}`
}
},
mixins: [General],
props: ['color', 'icon', 'value'],
computed: {
...mapGetters(['shouldUseBitSpeed'])
},
methods: {
open() {
this.createModal('SpeedLimitModal', { mode: this.color })
}
}
}
})
</script>
<style scoped>

View file

@ -8,8 +8,8 @@
</v-col>
<v-col cols="6" class="d-flex align-center">
<span data-testid="StorageCard-Wrapper" :class="color + '--text title'">
<span data-testid="StorageCard-value">{{ value | getDataValue(2) }} </span>
<span data-testid="StorageCard-unit" class="caption">{{ value | getDataUnit }}</span>
<span data-testid="StorageCard-value">{{ value | formatDataValue(shouldUseBinaryData()) }} </span>
<span data-testid="StorageCard-unit" class="caption">{{ value | formatDataUnit(shouldUseBinaryData()) }}</span>
</span>
</v-col>
</v-row>
@ -17,8 +17,14 @@
</template>
<script lang="ts">
export default {
import { defineComponent } from 'vue'
import { mapGetters } from 'vuex'
export default defineComponent({
name: 'StorageCard',
props: ['color', 'label', 'value']
}
props: ['color', 'label', 'value'],
computed: {
...mapGetters(['shouldUseBinaryData'])
}
})
</script>

View file

@ -4,12 +4,13 @@
</div>
</template>
<script>
import VueApexCharts from 'vue-apexcharts'
<script lang="ts">
import { defineComponent } from 'vue'
import { mapGetters } from 'vuex'
import { getDataUnit, getDataValue } from '@/filters'
import VueApexCharts from 'vue-apexcharts'
import { formatSpeed } from '@/filters'
export default {
export default defineComponent({
name: 'SpeedGraph',
components: {
apexcharts: VueApexCharts
@ -49,15 +50,15 @@ export default {
tooltip: {
theme: 'light',
x: {
formatter: value => {
formatter: (value: number) => {
const val = 32 - value * 2
return val + ' seconds ago'
}
},
y: {
formatter: value => {
return `${getDataValue(value, 0)} ${getDataUnit(value)}/s`
formatter: (value: number) => {
return formatSpeed(value, this.shouldUseBitSpeed())
}
}
}
@ -65,6 +66,7 @@ export default {
}
},
computed: {
...mapGetters(['getTheme', 'shouldUseBitSpeed']),
series() {
return [
{
@ -79,7 +81,6 @@ export default {
}
]
},
...mapGetters(['getTheme']),
theme() {
return this.getTheme()
}
@ -93,10 +94,10 @@ export default {
this.setChartTooltipTheme(this.theme)
},
methods: {
setChartTooltipTheme(theme) {
setChartTooltipTheme(theme: string) {
this.chartOptions.tooltip.theme = theme.toLowerCase()
this.$refs.chart.updateOptions(this.chartOptions)
}
}
}
})
</script>

View file

@ -4,44 +4,45 @@
{{ $t('modals.settings.vueTorrent.general.tip') }}
</v-subheader>
<v-list-item>
<v-checkbox v-model="settings.showCurrentSpeed" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.currentSpeed')" />
</v-list-item>
<v-list-item>
<v-checkbox v-model="settings.showSpeedGraph" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.speedGraph')" />
</v-list-item>
<v-list-item>
<v-checkbox v-model="settings.showAlltimeStat" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.allTimeStats')" />
</v-list-item>
<v-list-item>
<v-checkbox v-model="settings.showSessionStat" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.sessionStats')" />
</v-list-item>
<v-list-item>
<v-checkbox v-model="settings.showFreeSpace" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.freeSpace')" />
</v-list-item>
<v-list-item>
<v-checkbox v-model="settings.showTrackerFilter" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.trackerFilter')" />
</v-list-item>
<v-list-item>
<v-checkbox v-model="settings.rightDrawer" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.rightDrawer')" />
</v-list-item>
<v-list-item>
<v-checkbox v-model="settings.topPagination" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.topPagination')" />
</v-list-item>
<v-list-item>
<v-checkbox v-model="settings.openSideBarOnStart" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.openSideBarOnStart')" />
</v-list-item>
<v-list-item>
<v-checkbox v-model="settings.showShutdownButton" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.showShutdownButton')" />
<v-list-item class="my-3">
<v-row>
<v-col cols="12" sm="6">
<v-checkbox v-model="settings.showCurrentSpeed" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.currentSpeed')" />
</v-col>
<v-col cols="12" sm="6">
<v-checkbox v-model="settings.showSpeedGraph" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.speedGraph')" />
</v-col>
<v-col cols="12" sm="6">
<v-checkbox v-model="settings.showAlltimeStat" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.allTimeStats')" />
</v-col>
<v-col cols="12" sm="6">
<v-checkbox v-model="settings.showSessionStat" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.sessionStats')" />
</v-col>
<v-col cols="12" sm="6">
<v-checkbox v-model="settings.showFreeSpace" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.freeSpace')" />
</v-col>
<v-col cols="12" sm="6">
<v-checkbox v-model="settings.showTrackerFilter" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.trackerFilter')" />
</v-col>
<v-col cols="12" sm="6">
<v-checkbox v-model="settings.rightDrawer" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.rightDrawer')" />
</v-col>
<v-col cols="12" sm="6">
<v-checkbox v-model="settings.topPagination" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.topPagination')" />
</v-col>
<v-col cols="12" sm="6">
<v-checkbox v-model="settings.openSideBarOnStart" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.openSideBarOnStart')" />
</v-col>
<v-col cols="12" sm="6">
<v-checkbox v-model="settings.showShutdownButton" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.showShutdownButton')" />
</v-col>
<v-col cols="12" sm="6">
<v-checkbox v-model="settings.useBinaryUnits" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.useBinaryUnits')" />
</v-col>
<v-col cols="12" sm="6">
<v-checkbox v-model="settings.useBitSpeed" hide-details class="ma-0 pa-0" :label="$t('modals.settings.vueTorrent.general.useBitSpeed')" />
</v-col>
</v-row>
</v-list-item>
<v-divider class="mb-5" />

View file

@ -8,13 +8,11 @@
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {defineComponent} from 'vue'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'AddedOn',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -4,9 +4,9 @@
{{ $t('torrent.properties.amount_left') | titleCase }}
</div>
<div>
{{ torrent.amount_left | getDataValue(2) }}
{{ torrent.amount_left | formatDataValue(shouldUseBinaryData()) }}
<span class="caption grey--text">
{{ torrent.amount_left | getDataUnit }}
{{ torrent.amount_left | formatDataUnit(shouldUseBinaryData()) }}
</span>
</div>
</v-flex>
@ -14,12 +14,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'AmountLeft',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -11,13 +11,11 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'Availability',
props: {
torrent: Torrent
},
mixins: [TorrentDashboardItem],
computed: {
availability() {
if (this.torrent && this.torrent.availability !== -1) {

View file

@ -1,5 +1,5 @@
<template>
<v-flex v-if="torrent.category" xs6 sm1 md1>
<v-flex v-if="torrent?.category" xs6 sm1 md1>
<div class="caption grey--text">
{{ $t('torrent.properties.category') }}
</div>
@ -11,12 +11,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'Category',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -9,12 +9,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'CompletedOn',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -9,12 +9,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'ContentPath',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -4,20 +4,20 @@
{{ $t('torrent.properties.download_limit') | titleCase }}
</div>
<div>
{{ torrent.dl_limit | getDataValue(1) }}
<span class="caption grey--text"> {{ torrent.dl_limit | getDataUnit }}/s </span>
{{ torrent.dl_limit | formatDataValue(shouldUseBinaryData()) }}
<span class="caption grey--text">
{{ torrent.dl_limit | formatDataUnit(shouldUseBinaryData()) }}
</span>
</div>
</v-flex>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'DownloadLimit',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -9,12 +9,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'DownloadPath',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -4,20 +4,20 @@
{{ $t('torrent.properties.download_speed') }}
</div>
<div>
{{ torrent.dlspeed | getDataValue(1) }}
<span class="caption grey--text"> {{ torrent.dlspeed | getDataUnit }}/s </span>
{{ torrent.dlspeed | formatSpeedValue(shouldUseBitSpeed()) }}
<span class="caption grey--text">
{{ torrent.dlspeed | formatSpeedUnit(shouldUseBitSpeed()) }}
</span>
</div>
</v-flex>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'DownloadSpeed',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -4,9 +4,9 @@
{{ $t('torrent.properties.downloaded') }}
</div>
<div>
{{ torrent.downloaded | getDataValue(2) }}
{{ torrent.downloaded | formatDataValue(shouldUseBinaryData()) }}
<span class="caption grey--text">
{{ torrent.downloaded | getDataUnit }}
{{ torrent.downloaded | formatDataUnit(shouldUseBinaryData()) }}
</span>
</div>
</v-flex>
@ -14,12 +14,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'Downloaded',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -4,9 +4,9 @@
{{ $t('torrent.properties.downloaded_session') | titleCase }}
</div>
<div>
{{ torrent.downloaded_session | getDataValue(2) }}
{{ torrent.downloaded_session | formatDataValue(shouldUseBinaryData()) }}
<span class="caption grey--text">
{{ torrent.downloaded_session | getDataUnit }}
{{ torrent.downloaded_session | formatDataUnit(shouldUseBinaryData()) }}
</span>
</div>
</v-flex>
@ -14,12 +14,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'DownloadedSession',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -11,12 +11,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'ETA',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -4,20 +4,20 @@
{{ $t('torrent.properties.global_speed') }}
</div>
<div>
{{ torrent.globalSpeed | getDataValue(1) }}
<span class="caption grey--text"> {{ torrent.globalSpeed | getDataUnit }}/s </span>
{{ torrent.globalSpeed | formatSpeedValue(shouldUseBitSpeed()) }}
<span class="caption grey--text">
{{ torrent.globalSpeed | formatSpeedUnit(shouldUseBitSpeed()) }}
</span>
</div>
</v-flex>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'GlobalSpeed',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -4,9 +4,9 @@
{{ $t('torrent.properties.global_volume') }}
</div>
<div>
{{ torrent.globalVolume | getDataValue }}
{{ torrent.globalVolume | formatDataValue(shouldUseBinaryData()) }}
<span class="caption grey--text">
{{ torrent.globalVolume | getDataUnit }}
{{ torrent.globalVolume | formatDataUnit(shouldUseBinaryData()) }}
</span>
</div>
</v-flex>
@ -14,12 +14,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'GlobalVolume',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -9,12 +9,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'Hash',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -9,12 +9,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'InfoHashV1',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -9,12 +9,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'InfoHashV2',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -9,12 +9,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'LastActivity',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -12,12 +12,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'Peers',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -3,8 +3,8 @@
<div class="caption grey--text">
{{ $t('torrent.properties.progress') | titleCase }}
</div>
<v-progress-linear :value="torrent.progress" height="20" style="width: 90%" :color="`torrent-${state}`" rounded>
<span class="caption white--text"> {{ torrent.progress }}% </span>
<v-progress-linear :value="torrent?.progress ?? 0" height="20" style="width: 90%" :color="`torrent-${torrentStateClass}`" rounded>
<span class="caption white--text">{{ torrent.progress | progress }}</span>
</v-progress-linear>
</v-flex>
</template>
@ -12,13 +12,9 @@
<script lang="ts">
import { TorrentDashboardItem } from '@/mixins'
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
export default defineComponent({
name: 'Progress',
mixins: [TorrentDashboardItem],
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -9,12 +9,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'Ratio',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -3,7 +3,7 @@
<div class="caption grey--text">
{{ $t('torrent.properties.save_path') | titleCase }}
</div>
<div class="truncate" :title="torrent.savePath">
<div class="truncate" :title="torrent?.savePath">
{{ torrent.savePath }}
</div>
</v-flex>
@ -11,12 +11,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'SavePath',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -12,12 +12,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'Seeds',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -9,12 +9,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'SeenComplete',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -4,9 +4,9 @@
{{ $t('torrent.properties.size') | titleCase }}
</div>
<div>
{{ torrent.size | getDataValue }}
{{ torrent.size | formatDataValue(shouldUseBinaryData()) }}
<span class="caption grey--text">
{{ torrent.size | getDataUnit }}
{{ torrent.size | formatDataUnit(shouldUseBinaryData()) }}
</span>
</div>
</v-flex>
@ -14,12 +14,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'Size',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -3,7 +3,7 @@
<div class="caption grey--text">
{{ $t('torrent.properties.status') }}
</div>
<v-chip style="height: 1.3em" class="caption white--text px-2" :class="state">
<v-chip style="height: 1.3em" class="caption white--text px-2" :class="torrentStateClass">
{{ stateString }}
</v-chip>
</v-flex>
@ -12,15 +12,11 @@
<script lang="ts">
import { TorrentDashboardItem } from '@/mixins'
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import { TorrentState } from '@/enums/vuetorrent'
export default defineComponent({
name: 'Status',
mixins: [TorrentDashboardItem],
props: {
torrent: Torrent
},
computed: {
stateString() {
if (!this.torrent) return TorrentState.UNKNOWN

View file

@ -14,13 +14,9 @@
<script lang="ts">
import { TorrentDashboardItem } from '@/mixins'
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
export default defineComponent({
name: 'Tags',
mixins: [TorrentDashboardItem],
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -9,12 +9,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'TimeActive',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -4,9 +4,9 @@
{{ $t('torrent.properties.total_size') | titleCase }}
</div>
<div>
{{ torrent.total_size | getDataValue }}
{{ torrent.total_size | formatDataValue(shouldUseBinaryData()) }}
<span class="caption grey--text">
{{ torrent.total_size | getDataUnit }}
{{ torrent.total_size | formatDataUnit(shouldUseBinaryData()) }}
</span>
</div>
</v-flex>
@ -14,12 +14,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'TotalSize',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -1,5 +1,5 @@
<template>
<v-flex v-if="torrent.tracker" xs6 sm1 md1>
<v-flex v-if="torrent?.tracker" xs6 sm1 md1>
<div class="caption grey--text">
{{ $t('torrent.properties.tracker') }}
</div>
@ -12,15 +12,11 @@
<script lang="ts">
import { TorrentDashboardItem } from '@/mixins'
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import { getDomainBody } from '@/helpers'
export default defineComponent({
name: 'Tracker',
mixins: [TorrentDashboardItem],
props: {
torrent: Torrent
},
computed: {
trackerString() {
return getDomainBody(this.torrent?.tracker)

View file

@ -9,12 +9,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'TrackersCount',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -4,20 +4,20 @@
{{ $t('torrent.properties.upload_limit') }}
</div>
<div>
{{ torrent.up_limit | getDataValue(1) }}
<span class="caption grey--text"> {{ torrent.up_limit | getDataUnit(1) }}/s </span>
{{ torrent.up_limit | formatDataValue(shouldUseBinaryData()) }}
<span class="caption grey--text">
{{ torrent.up_limit | formatDataUnit(shouldUseBinaryData()) }}
</span>
</div>
</v-flex>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'UploadLimit',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -4,20 +4,20 @@
{{ $t('torrent.properties.upload_speed') }}
</div>
<div>
{{ torrent.upspeed | getDataValue(1) }}
<span class="caption grey--text"> {{ torrent.upspeed | getDataUnit(1) }}/s </span>
{{ torrent.upspeed | formatSpeedValue(shouldUseBitSpeed()) }}
<span class="caption grey--text">
{{ torrent.upspeed | formatSpeedUnit(shouldUseBitSpeed()) }}
</span>
</div>
</v-flex>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'UploadSpeed',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -4,9 +4,9 @@
{{ $t('torrent.properties.uploaded') }}
</div>
<div>
{{ torrent.uploaded | getDataValue }}
{{ torrent.uploaded | formatDataValue(shouldUseBinaryData()) }}
<span class="caption grey--text">
{{ torrent.uploaded | getDataUnit }}
{{ torrent.uploaded | formatDataUnit(shouldUseBinaryData()) }}
</span>
</div>
</v-flex>
@ -14,12 +14,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'Uploaded',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -4,9 +4,9 @@
{{ $t('torrent.properties.uploaded_session') | titleCase }}
</div>
<div>
{{ torrent.uploaded_session | getDataValue }}
{{ torrent.uploaded_session | formatDataValue(shouldUseBinaryData()) }}
<span class="caption grey--text">
{{ torrent.uploaded_session | getDataUnit }}
{{ torrent.uploaded_session | formatDataUnit(shouldUseBinaryData()) }}
</span>
</div>
</v-flex>
@ -14,12 +14,10 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import {TorrentDashboardItem} from '@/mixins'
export default defineComponent({
name: 'UploadedSession',
props: {
torrent: Torrent
}
mixins: [TorrentDashboardItem]
})
</script>

View file

@ -6,34 +6,34 @@
</span>
</v-flex>
<v-flex xs12 row class="ma-1 mt-0 chipgap">
<v-chip v-if="isStatusActive" small class="caption white--text" :class="torrent.state.toLowerCase()" style="height: 20px">
<v-chip v-if="isStatusActive" small class="caption white--text" :class="torrentStateClass" style="height: 20px">
{{ stateString }}
</v-chip>
<v-chip v-if="isTrackerActive && torrent.tracker" small class="trackers caption white--text" style="height: 20px">
<v-chip v-if="isTrackerActive && torrent?.tracker" small class="trackers caption white--text" style="height: 20px">
{{ trackerHost }}
</v-chip>
<v-chip v-if="isCategoryActive && torrent.category" small class="upload caption white--text" style="height: 20px">
<v-chip v-if="isCategoryActive && torrent?.category" small class="upload caption white--text" style="height: 20px">
{{ torrent.category }}
</v-chip>
<v-chip v-if="isTagsActive && torrent.tags" v-for="tag in torrent.tags" :key="tag" small class="tags caption white--text" style="height: 20px">
<v-chip v-if="isTagsActive && torrent?.tags" v-for="tag in torrent.tags" :key="tag" small class="tags caption white--text" style="height: 20px">
{{ tag }}
</v-chip>
</v-flex>
<v-flex xs12 class="pa-0 ma-1 row spangap">
<span v-if="isSizeActive">
<span>
<span class="body-2">{{ torrent.downloaded | getDataValue }} </span>
<span class="grey--text caption">{{ torrent.downloaded | getDataUnit }}</span>
<span class="body-2">{{ torrent.downloaded | formatDataValue(shouldUseBinaryData()) }} </span>
<span class="grey--text caption">{{ torrent.downloaded | formatDataUnit(shouldUseBinaryData()) }}</span>
</span>
<span class="grey--text caption">/</span>
<span class="size">
<span class="body-2">{{ torrent.size | getDataValue }} </span>
<span class="grey--text caption">{{ torrent.size | getDataUnit }}</span>
<span class="body-2">{{ torrent.size | formatDataValue(shouldUseBinaryData()) }} </span>
<span class="grey--text caption">{{ torrent.size | formatDataUnit(shouldUseBinaryData()) }}</span>
</span>
</span>
<span v-if="isSizeActive && isProgressActive" class="grey--text" style="margin-top: 3px"></span>
<span v-if="isProgressActive">
<span class="body-2">{{ torrent.progress }} </span>
<span class="body-2">{{ formattedProgress }} </span>
<span class="grey--text caption">%</span>
</span>
<span v-if="(isSizeActive || isProgressActive) && isRatioActive" class="grey--text" style="margin-top: 3px"></span>
@ -43,14 +43,14 @@
</span>
<span v-if="(isSizeActive || isProgressActive || isRatioActive) && isUploadedActive" class="grey--text" style="margin-top: 3px"></span>
<span v-if="isUploadedActive">
<span class="body-2">{{ torrent.uploaded | getDataValue }} </span>
<span class="grey--text caption">{{ torrent.uploaded | getDataUnit }}</span>
<span class="body-2">{{ torrent.uploaded | formatDataValue(shouldUseBinaryData()) }} </span>
<span class="grey--text caption">{{ torrent.uploaded | formatDataUnit(shouldUseBinaryData()) }}</span>
</span>
<v-spacer />
<span v-if="isEtaActive" class="body-2">{{ torrent.eta }}</span>
</v-flex>
<v-flex xs12 class="ma-1" v-if="isProgressBarActive">
<v-progress-linear rounded color="upload" height="5" :value="torrent.progress" />
<v-progress-linear rounded color="upload" height="5" :value="torrent?.progress" />
</v-flex>
<v-flex row xs12 class="ma-1">
<div v-if="isSeedsActive" class="caption grey--text">{{ torrent.num_seeds }}/{{ torrent.available_seeds }} seeds</div>
@ -58,36 +58,38 @@
<div v-if="isPeersActive" class="caption grey--text">{{ torrent.num_leechs }}/{{ torrent.available_peers }} peers</div>
<v-spacer />
<div>
<span v-if="isDownloadSpeedActive && torrent.dlspeed">
<span v-if="isDownloadSpeedActive && torrent?.dlspeed">
<v-icon small class="grey--text">
{{ mdiChevronDown }}
</v-icon>
<span class="caption font-weight-medium grey--text">{{ torrent.dlspeed | getDataValue(1) }} </span>
<span class="caption grey--text" style="font-size: 0.6em !important"> {{ torrent.dlspeed | getDataUnit }}/s </span>
<span class="caption font-weight-medium grey--text">{{ torrent.dlspeed | formatSpeedValue(shouldUseBitSpeed()) }} </span>
<span class="caption grey--text" style="font-size: 0.6em !important">{{ torrent.dlspeed | formatSpeedUnit(shouldUseBitSpeed()) }}</span>
</span>
<span v-if="isUploadSpeedActive && torrent.upspeed">
<span v-if="isUploadSpeedActive && torrent?.upspeed">
<v-icon small class="grey--text">
{{ mdiChevronUp }}
</v-icon>
<span class="caption font-weight-medium grey--text">{{ torrent.upspeed | getDataValue(1) }} </span>
<span class="caption grey--text" style="font-size: 0.6em !important"> {{ torrent.upspeed | getDataUnit(1) }}/s </span>
<span class="caption font-weight-medium grey--text">{{ torrent.upspeed | formatSpeedValue(shouldUseBitSpeed()) }} </span>
<span class="caption grey--text" style="font-size: 0.6em !important">{{ torrent.upspeed | formatSpeedUnit(shouldUseBitSpeed()) }}</span>
</span>
</div>
</v-flex>
</v-layout>
</template>
<script>
<script lang="ts">
import { defineComponent } from 'vue'
import { mapState } from 'vuex'
import { mdiChevronUp, mdiChevronDown } from '@mdi/js'
import { Torrent } from '@/models'
import { getDomainBody } from '@/helpers'
import { DashboardProperty } from '@/enums/vuetorrent'
import {TorrentDashboardItem} from '@/mixins'
import {toPrecision} from '@/filters'
import {TorrentProperty} from '@/types/vuetorrent'
export default {
export default defineComponent({
name: 'MobileCard',
props: {
torrent: Torrent
},
mixins: [TorrentDashboardItem],
data: () => ({
mdiChevronUp,
mdiChevronDown
@ -98,10 +100,13 @@ export default {
if (this.torrent.forced) return `[F] ${this.torrent.state}`
else return this.torrent.state
},
formattedProgress() {
return toPrecision(this.torrent.progress, 3)
},
trackerHost() {
return getDomainBody(this.torrent.tracker)
},
properties() {
properties(): TorrentProperty[] {
if (this.torrent.progress === 100) {
return this.webuiSettings.doneMobileCardProperties
}
@ -152,14 +157,14 @@ export default {
}
},
methods: {
processProperty(ppt) {
processProperty(ppt: DashboardProperty): boolean {
const value = this.properties.find(e => e.name === ppt)
if (value === undefined) return true
else return value.active
}
}
}
})
</script>
<style>

View file

@ -24,8 +24,8 @@
</v-btn>
</div>
<div v-else>
<span v-if="!$vuetify.breakpoint.xsOnly">[{{ node.size | formatSize }}]</span>
<span v-if="!$vuetify.breakpoint.xsOnly" class="ml-4">{{ node.progress | progress }}</span>
<span v-if="!$vuetify.breakpoint.xsOnly">[{{ node.size | formatData(shouldUseBinaryData()) }}]</span>
<span v-if="!$vuetify.breakpoint.xsOnly" class="ml-4">{{ node.progress }} %</span>
<span v-if="!$vuetify.breakpoint.xsOnly" class="ml-4">[ {{ getNodePriority(node) }} ]</span>
<v-menu open-on-hover offset-y>
<template #activator="{ on }">
@ -113,7 +113,7 @@ export default defineComponent({
}
},
computed: {
...mapGetters(['getContentInterval']),
...mapGetters(['getContentInterval', 'shouldUseBinaryData']),
torrentHash(): string {
return this.hash as string
}

View file

@ -24,10 +24,10 @@
</td>
<td>{{ item.client }}</td>
<td>{{ item.progress | progress }}</td>
<td>{{ item.dl_speed | networkSpeed }}</td>
<td>{{ item.downloaded | networkSize }}</td>
<td>{{ item.up_speed | networkSpeed }}</td>
<td>{{ item.uploaded | networkSize }}</td>
<td>{{ item.dl_speed | formatSpeed(shouldUseBitSpeed()) }}</td>
<td>{{ item.downloaded | formatData(shouldUseBinaryData()) }}</td>
<td>{{ item.up_speed | formatSpeed(shouldUseBitSpeed()) }}</td>
<td>{{ item.uploaded | formatData(shouldUseBinaryData()) }}</td>
<td>{{ item.relevance | progress }}</td>
<td>{{ item.files }}</td>
</tr>
@ -59,13 +59,15 @@
</v-card>
</template>
<script>
<script lang="ts">
import { defineComponent } from 'vue'
import { mapGetters } from 'vuex'
import { map, merge } from 'lodash'
import qbit from '@/services/qbit'
import { codeToFlag, isWindows } from '@/helpers'
import { FullScreenModal } from '@/mixins'
export default {
export default defineComponent({
name: 'DetailPeers',
mixins: [FullScreenModal],
props: { hash: String, isActive: Boolean },
@ -79,6 +81,7 @@ export default {
isWindows
}),
computed: {
...mapGetters(['shouldUseBinaryData', 'shouldUseBitSpeed']),
peers() {
return map(this.peersObj, (value, key) => merge({}, value, { key }))
},
@ -142,7 +145,7 @@ export default {
this.selectedPeers = []
}
}
}
})
</script>
<style scoped>

View file

@ -127,8 +127,8 @@
{{ $t('modals.detail.pageInfo.downloadLimit') }}
</td>
<td v-if="torrent?.dl_limit > 0">
{{ torrent.dl_limit | getDataValue }}
{{ torrent.dl_limit | getDataUnit }}<span>/s </span>
{{ torrent.dl_limit | formatSpeedValue(shouldUseBitSpeed()) }}
<span>{{ torrent.dl_limit | formatSpeedUnit(shouldUseBitSpeed()) }}</span>
</td>
<td v-else></td>
</tr>
@ -137,8 +137,8 @@
{{ $t('modals.detail.pageInfo.uploadLimit') }}
</td>
<td v-if="torrent?.up_limit > 0">
{{ torrent.up_limit | getDataValue }}
{{ torrent.up_limit | getDataUnit }}<span>/s </span>
{{ torrent.up_limit | formatSpeedValue(shouldUseBitSpeed()) }}
<span>{{ torrent.up_limit | formatSpeedUnit(shouldUseBitSpeed()) }}</span>
</td>
<td v-else></td>
</tr>
@ -163,8 +163,7 @@
{{ $t('modals.detail.pageInfo.wasted_size') | titleCase }}
</td>
<td>
{{ wastedSize | getDataValue }}
{{ wastedSize | getDataUnit }}
{{ wastedSize | formatData(shouldUseBinaryData()) }}
</td>
</tr>
</tbody>
@ -174,18 +173,16 @@
<script lang="ts">
import dayjs from 'dayjs'
import { FullScreenModal } from '@/mixins'
import {FullScreenModal, TorrentDashboardItem} from '@/mixins'
import qbit from '@/services/qbit'
import { splitByUrl, stringContainsUrl } from '@/helpers'
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import { mapState } from 'vuex'
export default defineComponent({
name: 'Info',
mixins: [FullScreenModal],
mixins: [FullScreenModal, TorrentDashboardItem],
props: {
torrent: Torrent,
isActive: Boolean
},
data() {
@ -208,9 +205,6 @@ export default defineComponent({
const content = this.$t('modals.detail.pageInfo.seededFor').toString().replace('$0', this.torrent.seeding_time)
return `(${content})`
},
torrentStateClass() {
return this.torrent?.state ? this.torrent.state.toLowerCase() : ''
}
},
methods: {

View file

@ -21,7 +21,7 @@
<v-progress-circular v-else-if="torrent?.progress === 100" :size="100" :width="15" :value="100" color="torrent-seeding">
<v-icon color="torrent-seeding">{{ mdiCheck }}</v-icon>
</v-progress-circular>
<v-progress-circular v-else :rotate="-90" :size="100" :width="15" :value="torrent?.progress ?? 0" color="accent">{{ torrent.progress ?? 0 }} %</v-progress-circular>
<v-progress-circular v-else :rotate="-90" :size="100" :width="15" :value="torrent?.progress ?? 0" color="accent">{{ (torrent.progress ?? 0) | progress }}</v-progress-circular>
</v-col>
<v-col cols="8" md="9" class="d-flex align-center justify-center flex-column">
<div v-if="isFetchingMetadata">
@ -36,14 +36,14 @@
<span>{{ $t('modals.detail.pageOverview.canvasRefreshDisabled') }}</span>
</div>
<div v-if="torrentPieceCount !== -1">
<span>{{ torrentPieceOwned }} / {{ torrentPieceCount }} ({{ torrentPieceSize | getData }})</span>
<span>{{ torrentPieceOwned }} / {{ torrentPieceCount }} ({{ pieceSize }})</span>
</div>
<div>
<v-icon>{{ mdiArrowDown }}</v-icon>
{{ torrent?.dlspeed | networkSpeed }}
{{ torrent?.dlspeed | formatSpeed(shouldUseBitSpeed()) }}
<v-icon>{{ mdiArrowUp }}</v-icon>
{{ torrent?.upspeed | networkSpeed }}
{{ torrent?.upspeed | formatSpeed(shouldUseBitSpeed()) }}
</div>
</v-col>
</v-row>
@ -100,7 +100,7 @@
<v-row>
<v-col cols="6">
<div>{{ $t('modals.detail.pageOverview.selectedFileSize') }}:</div>
<div>{{ torrent?.size | getData }} / {{ torrent?.total_size | getData }}</div>
<div>{{ torrent?.size | formatData(shouldUseBinaryData()) }} / {{ torrent?.total_size | formatData(shouldUseBinaryData()) }}</div>
</v-col>
<v-col cols="6">
<div>{{ $t('ratio') }}:</div>
@ -110,21 +110,21 @@
<v-row>
<v-col cols="6">
<div>{{ $t('downloaded') }}:</div>
<div>{{ torrent?.downloaded | getData }}</div>
<div>{{ torrent?.downloaded | formatData(shouldUseBinaryData()) }}</div>
</v-col>
<v-col cols="6">
<div>{{ $t('uploaded') }}:</div>
<div>{{ torrent?.uploaded | getData }}</div>
<div>{{ torrent?.uploaded | formatData(shouldUseBinaryData()) }}</div>
</v-col>
</v-row>
<v-row>
<v-col cols="6">
<div>{{ $t('modals.detail.pageOverview.dlSpeedAverage') }}:</div>
<div>{{ downloadSpeedAvg | networkSpeed }}</div>
<div>{{ downloadSpeedAvg | formatSpeed(shouldUseBitSpeed()) }}</div>
</v-col>
<v-col cols="6">
<div>{{ $t('modals.detail.pageOverview.upSpeedAverage') }}:</div>
<div>{{ uploadSpeedAvg | networkSpeed }}</div>
<div>{{ uploadSpeedAvg | formatSpeed(shouldUseBitSpeed()) }}</div>
</v-col>
</v-row>
</v-card-text>
@ -136,22 +136,21 @@
<script lang="ts">
import dayjs from 'dayjs'
import {FullScreenModal, General} from '@/mixins'
import {FullScreenModal, General, TorrentDashboardItem} from '@/mixins'
import qbit from '@/services/qbit'
import { getDomainBody, splitByUrl, stringContainsUrl } from '@/helpers'
import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import { mapState } from 'vuex'
import { mdiArrowDown, mdiArrowUp, mdiCheck, mdiClose, mdiPencil } from '@mdi/js'
import { TorrentState } from '@/enums/vuetorrent'
import { Priority } from '@/enums/qbit'
import {TorrentFile} from '@/types/qbit/models'
import {formatDataUnit, formatDataValue} from '@/filters'
export default defineComponent({
name: 'Overflow',
mixins: [General, FullScreenModal],
mixins: [General, FullScreenModal, TorrentDashboardItem],
props: {
torrent: Torrent,
isActive: Boolean
},
data() {
@ -185,8 +184,8 @@ export default defineComponent({
},
computed: {
...mapState(['webuiSettings']),
torrentStateClass() {
return this.torrent?.state ? this.torrent.state.toLowerCase() : ''
pieceSize() {
return `${parseInt(formatDataValue(this.torrentPieceSize, true))} ${formatDataUnit(this.torrentPieceSize, true)}`
},
isFetchingMetadata() {
return this.torrent?.state === TorrentState.METADATA

View file

@ -11,73 +11,59 @@ export function toPrecision(value: number, precision: number): string {
return value.toFixed(precision - 1)
}
export function formatSize(value: number): string {
const units = 'KMGTP'
let index = -1
while (value >= 1000) {
value /= 1024
index++
}
return index < 0 ? `${value} B` : `${toPrecision(value, 3)} ${units[index]}iB`
}
Vue.filter('formatSize', formatSize)
Vue.filter('size', formatSize)
export function formatProgress(progress: number): string {
progress *= 100
return `${toPrecision(progress, 3)}%`
return `${toPrecision(progress, 3)} %`
}
Vue.filter('progress', formatProgress)
export function formatNetworkSpeed(speed: number): string | null {
return `${formatSize(speed)}/s`
}
export function formatDataValue(data: number, isBinary: boolean) {
const base = isBinary ? 1024 : 1000
if (!data || data === 0) return '0'
Vue.filter('networkSpeed', formatNetworkSpeed)
export function networkSize(size: number) {
if (size === 0) {
return null
let i = 1
while (data >= base ** i) {
i++
}
return formatSize(size)
return toPrecision(data / base ** (i - 1), i > 1 ? 3 : 1)
}
Vue.filter('formatDataValue', formatDataValue)
Vue.filter('networkSize', networkSize)
export function formatDataUnit(data: number, isBinary: boolean) {
const base = isBinary ? 1024 : 1000
const units = ['', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
export function getDataUnit(data: number) {
if (data === -1) return null
if (!data) return 'B'
const c = 1024
const e = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
const f = Math.floor(Math.log(data) / Math.log(c))
if (data === 0) return 'B'
return `${e[f]}`
let i = 1
while (data >= base ** i) {
i++
}
return `${units[i - 1]}${isBinary && i > 1 ? 'i' : ''}B`
}
Vue.filter('formatDataUnit', formatDataUnit)
Vue.filter('getDataUnit', getDataUnit)
export function getDataValue(data: number, precision: number = 2) {
if (data === -1) return 'None'
if (!data) return '0'
const c = 1024
const f = Math.floor(Math.log(data) / Math.log(c))
return `${parseFloat((data / Math.pow(c, f)).toFixed(precision))}`
export function formatData(data: number, isBinary: boolean) {
return `${formatDataValue(data, isBinary)} ${formatDataUnit(data, isBinary)}`
}
Vue.filter('formatData', formatData)
Vue.filter('getDataValue', getDataValue)
export function getData(data: number, precision: number = 2) {
return `${getDataValue(data, precision)} ${getDataUnit(data)}`
export function formatSpeedValue(speed: number, isBits: boolean) {
if (isBits) speed *= 8
return formatDataValue(speed, false)
}
Vue.filter('formatSpeedValue', formatSpeedValue)
Vue.filter('getData', getData)
export function formatSpeedUnit(speed: number, isBits: boolean) {
if (isBits) speed *= 8
const unit = formatDataUnit(speed, false).slice(0, -1)
return `${unit}${isBits ? 'bps' : 'B/s'}`
}
Vue.filter('formatSpeedUnit', formatSpeedUnit)
export function formatSpeed(speed: number, isBits: boolean) {
return `${formatSpeedValue(speed, isBits)} ${formatSpeedUnit(speed, isBits)}`
}
Vue.filter('formatSpeed', formatSpeed)
export function titleCase(str: string): string {
if (str.length == 0) return str

View file

@ -1,22 +1,6 @@
import * as _ from 'lodash'
import { isProduction } from './utils'
/**
* Format bytes to human readable string
* @param a {number}
* @param b {number}
* @return {string}
*/
export function formatBytes(a, b) {
if (a === 0) return '0 B'
const c = 1024
const d = b || 2
const e = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
const f = Math.floor(Math.log(a) / Math.log(c))
return `${parseFloat((a / Math.pow(c, f)).toFixed(d))} ${e[f]}`
}
export const isWindows = navigator.userAgent.includes('Windows')
/**

View file

@ -270,6 +270,8 @@
"dateFormat": "Date Format",
"openSideBarOnStart": "Open Side Bar on launch",
"showShutdownButton": "Show shutdown button",
"useBinaryUnits": "Replace data values by binary units (kB -> KiB)",
"useBitSpeed": "Replace speed values by bits (kB/s -> kbps)",
"refreshInterval": "qBittorrent API refresh interval",
"refreshIntervalHint": "In milliseconds",
"contentInterval": "Torrent file content refresh interval",

View file

@ -9,7 +9,7 @@ export default defineComponent({
torrent: Torrent
},
computed: {
...mapGetters(['getTheme']),
...mapGetters(['getTheme', 'shouldUseBinaryData', 'shouldUseBitSpeed']),
phoneLayout() {
return this.$vuetify.breakpoint.xsOnly
},
@ -17,7 +17,7 @@ export default defineComponent({
// @ts-expect-error: TS2339: Property 'getTheme' does not exist on type 'CreateComponentPublicInstance { torrent: typeof Torrent; }>, {}, {}, { phoneLayout(): boolean; theme(): string; state(): string; }, {}, ComponentOptionsMixin, ... 11 more ..., {}>'.
return this.getTheme()
},
state() {
torrentStateClass() {
if (!this.torrent) return TorrentState.UNKNOWN.toString().toLowerCase()
return this.torrent.state.toLowerCase()
}

View file

@ -42,6 +42,8 @@ export const StoreStateSchema: JSONSchemaType<PersistentStoreState> = {
dateFormat: { type: 'string' },
openSideBarOnStart: { type: 'boolean' },
showShutdownButton: { type: 'boolean' },
useBitSpeed: { type: 'boolean' },
useBinaryUnits: { type: 'boolean' },
refreshInterval: { type: 'number' },
contentInterval: { type: 'number' },
torrentPieceCountRenderThreshold: { type: 'number' },
@ -68,6 +70,8 @@ export const StoreStateSchema: JSONSchemaType<PersistentStoreState> = {
'dateFormat',
'openSideBarOnStart',
'showShutdownButton',
'useBitSpeed',
'useBinaryUnits',
'refreshInterval',
'contentInterval',
'torrentPieceCountRenderThreshold',

View file

@ -1,6 +1,6 @@
import { i18n } from '@/plugins/i18n'
import type { StoreState } from '@/types/vuetorrent'
import { formatSize } from '@/filters'
import { formatData } from '@/filters'
import { Torrent } from '@/models'
export default {
@ -32,12 +32,14 @@ export default {
return i18n
.tc('dashboard.selectedTorrentsCount', state.filteredTorrentsCount)
.replace('$0', state.selected_torrents.length.toString())
.replace('$1', formatSize(selectedSize))
.replace('$1', formatData(selectedSize, getters.shouldUseBinaryData()))
} else {
return i18n.tc('dashboard.torrentsCount', state.filteredTorrentsCount)
}
},
getSearchPlugins: (state: StoreState) => () => state.searchPlugins,
getApiRefreshInterval: (state: StoreState) => () => state.webuiSettings.refreshInterval,
getContentInterval: (state: StoreState) => () => state.webuiSettings.contentInterval
getContentInterval: (state: StoreState) => () => state.webuiSettings.contentInterval,
shouldUseBinaryData: (state: StoreState) => () => state.webuiSettings.useBinaryUnits,
shouldUseBitSpeed: (state: StoreState) => () => state.webuiSettings.useBitSpeed
}

View file

@ -135,6 +135,8 @@ export default new Vuex.Store<StoreState>({
dateFormat: 'DD/MM/YYYY, HH:mm:ss',
openSideBarOnStart: true,
showShutdownButton: true,
useBitSpeed: false,
useBinaryUnits: false,
refreshInterval: 2000,
contentInterval: 5000,
torrentPieceCountRenderThreshold: 5000,

View file

@ -28,6 +28,8 @@ export default interface WebUISettings {
dateFormat: string
openSideBarOnStart: boolean
showShutdownButton: boolean
useBitSpeed: boolean
useBinaryUnits: boolean
refreshInterval: number
contentInterval: number
torrentPieceCountRenderThreshold: number

View file

@ -3,21 +3,20 @@ import { createLocalVue, mount } from '@vue/test-utils'
import Vuetify from 'vuetify'
import { Ripple } from 'vuetify/lib/directives'
import filters from '@/filters'
Vue.use(Vuetify, {
directives: {
Ripple
}
})
export function setup(component, propsData) {
export function setup(component, propsData, mocks) {
const localVue = createLocalVue() // because of vuetify, we should use a localVue instance
const vuetify = new Vuetify()
return mount(component, {
localVue,
vuetify,
propsData
propsData,
mocks
})
}

View file

@ -4,8 +4,6 @@ import { shallowMount } from '@vue/test-utils'
import DesktopCard from '@/components/Settings/Tabs/VueTorrent/VDesktopCard.vue'
import { DashboardProperty } from '@/enums/vuetorrent'
let wrapper
const desktopPropertiesTemplate = [
{ name: DashboardProperty.SIZE, active: true },
{ name: DashboardProperty.PROGRESS, active: true },
@ -81,6 +79,7 @@ const desktopPropertiesTemplateExpected = [
{ name: 'GlobalVolume', active: false }
]
let wrapper
describe('DesktopCard', () => {
beforeEach(() => {
wrapper = shallowMount(DesktopCard, {

View file

@ -1,26 +1,31 @@
import { describe, it, expect } from 'vitest'
import { setup } from '../helpers'
import { describe, beforeEach, it, expect, vi } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import Vue from 'vue'
import Vuetify from 'vuetify'
import { Ripple } from 'vuetify/lib/directives'
import { mdiChevronDown } from '@mdi/js'
import SpeedCard from '@/components/Core/SpeedCard.vue'
import {setup} from "../helpers";
describe('SpeedCard.vue', () => {
it('should render the card', () => {
const wrapper = setup(SpeedCard)
const wrapper = setup(SpeedCard, {}, { $store: { getters: { shouldUseBitSpeed: vi.fn().mockReturnValue(true) } } })
expect(wrapper.find('[data-testid="SpeedCard"]').exists()).toBe(true)
})
it("shouldn't render the icon", () => {
const wrapper = setup(SpeedCard)
const wrapper = setup(SpeedCard, {}, { $store: { getters: { shouldUseBitSpeed: vi.fn().mockReturnValue(true) } } })
expect(wrapper.find('[data-testid="SpeedCard-icon"]').exists()).toBe(false)
})
it('should render the icon', () => {
const wrapper = setup(SpeedCard, { icon: mdiChevronDown })
const wrapper = setup(SpeedCard, { icon: mdiChevronDown }, { $store: { getters: { shouldUseBitSpeed: vi.fn().mockReturnValue(true) } } })
expect(wrapper.find('[data-testid="SpeedCard-icon"]').exists()).toBe(true)
})
it('should render with 0 as value', () => {
const wrapper = setup(SpeedCard)
const wrapper = setup(SpeedCard, {}, { $store: { getters: { shouldUseBitSpeed: vi.fn().mockReturnValue(false) } } })
expect(wrapper.find('[data-testid="SpeedCard-value"]').exists()).toBe(true)
expect(wrapper.find('[data-testid="SpeedCard-value"]').text()).toBe('0')
@ -29,15 +34,15 @@ describe('SpeedCard.vue', () => {
})
it('should render value (0 decimals) and unit & be formatted', () => {
const wrapper = setup(SpeedCard, { value: 26823 })
expect(wrapper.find('[data-testid="SpeedCard-value"]').text()).toBe('26')
const wrapper = setup(SpeedCard, { value: 26823 }, { $store: { getters: { shouldUseBitSpeed: vi.fn().mockReturnValue(false) } } })
expect(wrapper.find('[data-testid="SpeedCard-value"]').text()).toBe('26.8')
expect(wrapper.find('[data-testid="SpeedCard-unit"]').text()).toBe('KB/s')
expect(wrapper.find('[data-testid="SpeedCard-unit"]').text()).toBe('kB/s')
})
it('should render value (1 decimals) and unit & be formatted', () => {
const wrapper = setup(SpeedCard, { value: 10899700 })
expect(wrapper.find('[data-testid="SpeedCard-value"]').text()).toBe('10.4')
const wrapper = setup(SpeedCard, { value: 10899700 }, { $store: { getters: { shouldUseBitSpeed: vi.fn().mockReturnValue(false) } } })
expect(wrapper.find('[data-testid="SpeedCard-value"]').text()).toBe('10.9')
expect(wrapper.find('[data-testid="SpeedCard-unit"]').text()).toBe('MB/s')
})

View file

@ -1,16 +1,34 @@
import { describe, it, expect } from 'vitest'
import { setup } from '../helpers'
import { describe, beforeEach, it, expect, vi } from 'vitest'
import { shallowMount } from '@vue/test-utils'
import StorageCard from '@/components/Core/StorageCard.vue'
const label = 'Downloaded'
const value = 10000
const color = 'download'
let wrapper
describe('StorageCard.vue', () => {
beforeEach(() => {
wrapper = shallowMount(StorageCard, {
propsData: {label, value, color},
filters: {
formatDataValue: vi.fn().mockReturnValue('9.77'),
formatDataUnit: vi.fn().mockReturnValue('KB')
},
mocks: {
$store: {
getters: { shouldUseBinaryData: vi.fn().mockReturnValue(true) },
}
}
})
})
it('should render the label', () => {
const label = 'Downloaded'
const wrapper = setup(StorageCard, { label })
expect(wrapper.find('[data-testid="StorageCard-label"]').text()).toEqual(label)
})
it('should render value and unit & be formatted', () => {
const wrapper = setup(StorageCard, { value: 10000 })
expect(wrapper.find('[data-testid="StorageCard-value"]').exists()).toBe(true)
expect(wrapper.find('[data-testid="StorageCard-value"]').text()).toBe('9.77')
@ -19,8 +37,6 @@ describe('StorageCard.vue', () => {
})
it('text should have the passed-in color', () => {
const color = 'download'
const wrapper = setup(StorageCard, { color })
expect(wrapper.find('[data-testid="StorageCard-label"]').classes()).toContain(color + '--text')
expect(wrapper.find('[data-testid="StorageCard-Wrapper"]').classes()).toContain(color + '--text')
})

View file

@ -3,35 +3,45 @@
exports[`General > render correctly 1`] = `
"<v-card-stub data-v-7da6d3e2=\\"\\" loaderheight=\\"4\\" tag=\\"div\\" flat=\\"true\\">
<v-subheader-stub data-v-7da6d3e2=\\"\\"> </v-subheader-stub>
<v-list-item-stub data-v-7da6d3e2=\\"\\" activeclass=\\"\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" inputvalue=\\"100\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-list-item-stub>
<v-list-item-stub data-v-7da6d3e2=\\"\\" activeclass=\\"\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" inputvalue=\\"true\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-list-item-stub>
<v-list-item-stub data-v-7da6d3e2=\\"\\" activeclass=\\"\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" inputvalue=\\"true\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-list-item-stub>
<v-list-item-stub data-v-7da6d3e2=\\"\\" activeclass=\\"\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" inputvalue=\\"true\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-list-item-stub>
<v-list-item-stub data-v-7da6d3e2=\\"\\" activeclass=\\"\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-list-item-stub>
<v-list-item-stub data-v-7da6d3e2=\\"\\" activeclass=\\"\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" inputvalue=\\"true\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-list-item-stub>
<v-list-item-stub data-v-7da6d3e2=\\"\\" activeclass=\\"\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" inputvalue=\\"10\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-list-item-stub>
<v-list-item-stub data-v-7da6d3e2=\\"\\" activeclass=\\"\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-list-item-stub>
<v-list-item-stub data-v-7da6d3e2=\\"\\" activeclass=\\"\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-list-item-stub>
<v-list-item-stub data-v-7da6d3e2=\\"\\" activeclass=\\"\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
<v-list-item-stub data-v-7da6d3e2=\\"\\" activeclass=\\"\\" tag=\\"div\\" class=\\"my-3\\">
<v-row-stub data-v-7da6d3e2=\\"\\" tag=\\"div\\">
<v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" inputvalue=\\"100\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-col-stub>
<v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" inputvalue=\\"true\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-col-stub>
<v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" inputvalue=\\"true\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-col-stub>
<v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" inputvalue=\\"true\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-col-stub>
<v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-col-stub>
<v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" inputvalue=\\"true\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-col-stub>
<v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" inputvalue=\\"10\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-col-stub>
<v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-col-stub>
<v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-col-stub>
<v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-col-stub>
<v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-col-stub>
<v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<v-checkbox-stub data-v-7da6d3e2=\\"\\" errorcount=\\"1\\" errormessages=\\"\\" messages=\\"\\" rules=\\"\\" successmessages=\\"\\" backgroundcolor=\\"\\" hidedetails=\\"true\\" ripple=\\"true\\" valuecomparator=\\"[Function]\\" indeterminateicon=\\"$checkboxIndeterminate\\" officon=\\"$checkboxOff\\" onicon=\\"$checkboxOn\\" class=\\"ma-0 pa-0\\"></v-checkbox-stub>
</v-col-stub>
</v-row-stub>
</v-list-item-stub>
<v-divider-stub data-v-7da6d3e2=\\"\\" class=\\"mb-5\\"></v-divider-stub>
<v-list-item-stub data-v-7da6d3e2=\\"\\" activeclass=\\"\\" tag=\\"div\\" class=\\"my-2\\">

View file

@ -1,5 +1,5 @@
import { describe, it, expect } from 'vitest'
import { titleCase, capitalize } from '@/filters'
import {titleCase, capitalize, formatData, formatSpeed, toPrecision} from '@/filters'
describe('Filters', () => {
it('titleCase', () => {
@ -10,11 +10,63 @@ describe('Filters', () => {
expect(titleCase('hello there')).toEqual('Hello There')
})
it('capitaliza', () => {
it('capitalize', () => {
expect(capitalize('')).toEqual('')
expect(capitalize('-')).toEqual('-')
expect(capitalize('test')).toEqual('Test')
expect(capitalize('hello There')).toEqual('Hello there')
expect(capitalize('i like vuetorrent')).toEqual('I like vuetorrent')
})
it('toPrecision', () => {
expect(toPrecision(1000, 3)).toEqual('1000')
expect(toPrecision(256, 3)).toEqual('256')
expect(toPrecision(25.6, 3)).toEqual('25.6')
expect(toPrecision(2.56, 3)).toEqual('2.56')
expect(toPrecision(0.12345, 3)).toEqual('0.12')
expect(toPrecision(123.45, 3)).toEqual('123')
})
it('formatData: null', () => {
expect(formatData(null, false)).toEqual('0 B')
expect(formatData(null, true)).toEqual('0 B')
})
it('formatData: 0', () => {
expect(formatData(0, false)).toEqual('0 B')
expect(formatData(0, true)).toEqual('0 B')
})
it('formatData: base values', () => {
expect(formatData(1, false)).toEqual('1 B')
expect(formatData(1000, false)).toEqual('1.00 kB')
expect(formatData(1000, true)).toEqual('1000 B')
expect(formatData(1024, false)).toEqual('1.02 kB')
expect(formatData(1024, true)).toEqual('1.00 kiB')
})
it('formatData: non-binary values', () => {
expect(formatData(1_000_000, false)).toEqual('1.00 MB')
expect(formatData(25_600_000, false)).toEqual('25.6 MB')
expect(formatData(256_000_000, false)).toEqual('256 MB')
})
it('formatData: binary values', () => {
expect(formatData(1_000_000, true)).toEqual('977 kiB')
expect(formatData(25_600_000, true)).toEqual('24.4 MiB')
expect(formatData(256_000_000, true)).toEqual('244 MiB')
})
it('formatSpeed: 0', () => {
expect(formatSpeed(0, false)).toEqual('0 B/s')
expect(formatSpeed(0, true)).toEqual('0 bps')
})
it('formatSpeed: base values', () => {
expect(formatSpeed(1, false)).toEqual('1 B/s')
expect(formatSpeed(1, true)).toEqual('8 bps')
expect(formatSpeed(1000, false)).toEqual('1.00 kB/s')
expect(formatSpeed(1000, true)).toEqual('8.00 kbps')
})
})