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" "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": { "node_modules/@typescript-eslint/type-utils": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.1.0.tgz", "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" "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": { "node_modules/@typescript-eslint/utils": {
"version": "6.1.0", "version": "6.1.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.1.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.1.0.tgz",
@ -3116,23 +3059,6 @@
"url": "https://opencollective.com/typescript-eslint" "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": { "node_modules/@vitejs/plugin-vue2": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue2/-/plugin-vue2-2.2.0.tgz", "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 store from '@/store'
import {formatSpeed} from '@/filters'
import {formatProgress} from '@/filters'
import {Torrent} from '@/models'
export class DocumentTitle { export class DocumentTitle {
private static setDefault() { private static setDefault() {
@ -8,25 +10,26 @@ export class DocumentTitle {
private static setGlobalSpeed() { private static setGlobalSpeed() {
const status = store.getters.getStatus() 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() { private static setFirstTorrentStatus() {
const torrents = store.getters.getTorrents() const useBitSpeed = store.state.webuiSettings.useBitSpeed
if (!torrents && !torrents.length) return const torrents: Torrent[] = store.getters.getTorrents()
if (!torrents || !torrents.length) return
const torrent = torrents[0] 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() { public static update() {
const mode = store.getters.getWebuiSettings().title const mode = store.getters.getWebuiSettings().title
switch (mode) { switch (mode) {
case 'Default':
return this.setDefault()
case 'Global Speed': case 'Global Speed':
return this.setGlobalSpeed() return this.setGlobalSpeed()
case 'First Torrent Status': case 'First Torrent Status':
return this.setFirstTorrentStatus() return this.setFirstTorrentStatus()
case 'Default':
default: default:
return this.setDefault() return this.setDefault()
} }

View file

@ -8,41 +8,34 @@
</v-flex> </v-flex>
<v-layout column xs10> <v-layout column xs10>
<v-flex class="text-center font-weight-bold robot-mono"> <v-flex class="text-center font-weight-bold robot-mono">
<span data-testid="SpeedCard-value"> <span data-testid="SpeedCard-value">{{ value | formatSpeedValue(shouldUseBitSpeed()) }}</span>
{{ value | getSpeedValue }}
</span>
</v-flex> </v-flex>
<v-flex class="caption robot-mono text-center mt-n1"> <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-flex>
</v-layout> </v-layout>
</v-layout> </v-layout>
</v-card> </v-card>
</template> </template>
<script> <script lang="ts">
import { defineComponent } from 'vue'
import { mapGetters } from 'vuex'
import { General } from '@/mixins' import { General } from '@/mixins'
export default { export default defineComponent({
name: 'SpeedCard', 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], mixins: [General],
props: ['color', 'icon', 'value'], props: ['color', 'icon', 'value'],
computed: {
...mapGetters(['shouldUseBitSpeed'])
},
methods: { methods: {
open() { open() {
this.createModal('SpeedLimitModal', { mode: this.color }) this.createModal('SpeedLimitModal', { mode: this.color })
} }
} }
} })
</script> </script>
<style scoped> <style scoped>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -127,8 +127,8 @@
{{ $t('modals.detail.pageInfo.downloadLimit') }} {{ $t('modals.detail.pageInfo.downloadLimit') }}
</td> </td>
<td v-if="torrent?.dl_limit > 0"> <td v-if="torrent?.dl_limit > 0">
{{ torrent.dl_limit | getDataValue }} {{ torrent.dl_limit | formatSpeedValue(shouldUseBitSpeed()) }}
{{ torrent.dl_limit | getDataUnit }}<span>/s </span> <span>{{ torrent.dl_limit | formatSpeedUnit(shouldUseBitSpeed()) }}</span>
</td> </td>
<td v-else></td> <td v-else></td>
</tr> </tr>
@ -137,8 +137,8 @@
{{ $t('modals.detail.pageInfo.uploadLimit') }} {{ $t('modals.detail.pageInfo.uploadLimit') }}
</td> </td>
<td v-if="torrent?.up_limit > 0"> <td v-if="torrent?.up_limit > 0">
{{ torrent.up_limit | getDataValue }} {{ torrent.up_limit | formatSpeedValue(shouldUseBitSpeed()) }}
{{ torrent.up_limit | getDataUnit }}<span>/s </span> <span>{{ torrent.up_limit | formatSpeedUnit(shouldUseBitSpeed()) }}</span>
</td> </td>
<td v-else></td> <td v-else></td>
</tr> </tr>
@ -163,8 +163,7 @@
{{ $t('modals.detail.pageInfo.wasted_size') | titleCase }} {{ $t('modals.detail.pageInfo.wasted_size') | titleCase }}
</td> </td>
<td> <td>
{{ wastedSize | getDataValue }} {{ wastedSize | formatData(shouldUseBinaryData()) }}
{{ wastedSize | getDataUnit }}
</td> </td>
</tr> </tr>
</tbody> </tbody>
@ -174,18 +173,16 @@
<script lang="ts"> <script lang="ts">
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { FullScreenModal } from '@/mixins' import {FullScreenModal, TorrentDashboardItem} from '@/mixins'
import qbit from '@/services/qbit' import qbit from '@/services/qbit'
import { splitByUrl, stringContainsUrl } from '@/helpers' import { splitByUrl, stringContainsUrl } from '@/helpers'
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import { mapState } from 'vuex' import { mapState } from 'vuex'
export default defineComponent({ export default defineComponent({
name: 'Info', name: 'Info',
mixins: [FullScreenModal], mixins: [FullScreenModal, TorrentDashboardItem],
props: { props: {
torrent: Torrent,
isActive: Boolean isActive: Boolean
}, },
data() { data() {
@ -208,9 +205,6 @@ export default defineComponent({
const content = this.$t('modals.detail.pageInfo.seededFor').toString().replace('$0', this.torrent.seeding_time) const content = this.$t('modals.detail.pageInfo.seededFor').toString().replace('$0', this.torrent.seeding_time)
return `(${content})` return `(${content})`
},
torrentStateClass() {
return this.torrent?.state ? this.torrent.state.toLowerCase() : ''
} }
}, },
methods: { 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-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-icon color="torrent-seeding">{{ mdiCheck }}</v-icon>
</v-progress-circular> </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>
<v-col cols="8" md="9" class="d-flex align-center justify-center flex-column"> <v-col cols="8" md="9" class="d-flex align-center justify-center flex-column">
<div v-if="isFetchingMetadata"> <div v-if="isFetchingMetadata">
@ -36,14 +36,14 @@
<span>{{ $t('modals.detail.pageOverview.canvasRefreshDisabled') }}</span> <span>{{ $t('modals.detail.pageOverview.canvasRefreshDisabled') }}</span>
</div> </div>
<div v-if="torrentPieceCount !== -1"> <div v-if="torrentPieceCount !== -1">
<span>{{ torrentPieceOwned }} / {{ torrentPieceCount }} ({{ torrentPieceSize | getData }})</span> <span>{{ torrentPieceOwned }} / {{ torrentPieceCount }} ({{ pieceSize }})</span>
</div> </div>
<div> <div>
<v-icon>{{ mdiArrowDown }}</v-icon> <v-icon>{{ mdiArrowDown }}</v-icon>
{{ torrent?.dlspeed | networkSpeed }} {{ torrent?.dlspeed | formatSpeed(shouldUseBitSpeed()) }}
<v-icon>{{ mdiArrowUp }}</v-icon> <v-icon>{{ mdiArrowUp }}</v-icon>
{{ torrent?.upspeed | networkSpeed }} {{ torrent?.upspeed | formatSpeed(shouldUseBitSpeed()) }}
</div> </div>
</v-col> </v-col>
</v-row> </v-row>
@ -100,7 +100,7 @@
<v-row> <v-row>
<v-col cols="6"> <v-col cols="6">
<div>{{ $t('modals.detail.pageOverview.selectedFileSize') }}:</div> <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>
<v-col cols="6"> <v-col cols="6">
<div>{{ $t('ratio') }}:</div> <div>{{ $t('ratio') }}:</div>
@ -110,21 +110,21 @@
<v-row> <v-row>
<v-col cols="6"> <v-col cols="6">
<div>{{ $t('downloaded') }}:</div> <div>{{ $t('downloaded') }}:</div>
<div>{{ torrent?.downloaded | getData }}</div> <div>{{ torrent?.downloaded | formatData(shouldUseBinaryData()) }}</div>
</v-col> </v-col>
<v-col cols="6"> <v-col cols="6">
<div>{{ $t('uploaded') }}:</div> <div>{{ $t('uploaded') }}:</div>
<div>{{ torrent?.uploaded | getData }}</div> <div>{{ torrent?.uploaded | formatData(shouldUseBinaryData()) }}</div>
</v-col> </v-col>
</v-row> </v-row>
<v-row> <v-row>
<v-col cols="6"> <v-col cols="6">
<div>{{ $t('modals.detail.pageOverview.dlSpeedAverage') }}:</div> <div>{{ $t('modals.detail.pageOverview.dlSpeedAverage') }}:</div>
<div>{{ downloadSpeedAvg | networkSpeed }}</div> <div>{{ downloadSpeedAvg | formatSpeed(shouldUseBitSpeed()) }}</div>
</v-col> </v-col>
<v-col cols="6"> <v-col cols="6">
<div>{{ $t('modals.detail.pageOverview.upSpeedAverage') }}:</div> <div>{{ $t('modals.detail.pageOverview.upSpeedAverage') }}:</div>
<div>{{ uploadSpeedAvg | networkSpeed }}</div> <div>{{ uploadSpeedAvg | formatSpeed(shouldUseBitSpeed()) }}</div>
</v-col> </v-col>
</v-row> </v-row>
</v-card-text> </v-card-text>
@ -136,22 +136,21 @@
<script lang="ts"> <script lang="ts">
import dayjs from 'dayjs' import dayjs from 'dayjs'
import {FullScreenModal, General} from '@/mixins' import {FullScreenModal, General, TorrentDashboardItem} from '@/mixins'
import qbit from '@/services/qbit' import qbit from '@/services/qbit'
import { getDomainBody, splitByUrl, stringContainsUrl } from '@/helpers' import { getDomainBody, splitByUrl, stringContainsUrl } from '@/helpers'
import { defineComponent } from 'vue' import { defineComponent } from 'vue'
import { Torrent } from '@/models'
import { mapState } from 'vuex' import { mapState } from 'vuex'
import { mdiArrowDown, mdiArrowUp, mdiCheck, mdiClose, mdiPencil } from '@mdi/js' import { mdiArrowDown, mdiArrowUp, mdiCheck, mdiClose, mdiPencil } from '@mdi/js'
import { TorrentState } from '@/enums/vuetorrent' import { TorrentState } from '@/enums/vuetorrent'
import { Priority } from '@/enums/qbit' import { Priority } from '@/enums/qbit'
import {TorrentFile} from '@/types/qbit/models' import {TorrentFile} from '@/types/qbit/models'
import {formatDataUnit, formatDataValue} from '@/filters'
export default defineComponent({ export default defineComponent({
name: 'Overflow', name: 'Overflow',
mixins: [General, FullScreenModal], mixins: [General, FullScreenModal, TorrentDashboardItem],
props: { props: {
torrent: Torrent,
isActive: Boolean isActive: Boolean
}, },
data() { data() {
@ -185,8 +184,8 @@ export default defineComponent({
}, },
computed: { computed: {
...mapState(['webuiSettings']), ...mapState(['webuiSettings']),
torrentStateClass() { pieceSize() {
return this.torrent?.state ? this.torrent.state.toLowerCase() : '' return `${parseInt(formatDataValue(this.torrentPieceSize, true))} ${formatDataUnit(this.torrentPieceSize, true)}`
}, },
isFetchingMetadata() { isFetchingMetadata() {
return this.torrent?.state === TorrentState.METADATA 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) 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 { export function formatProgress(progress: number): string {
progress *= 100 return `${toPrecision(progress, 3)} %`
return `${toPrecision(progress, 3)}%`
} }
Vue.filter('progress', formatProgress) Vue.filter('progress', formatProgress)
export function formatNetworkSpeed(speed: number): string | null { export function formatDataValue(data: number, isBinary: boolean) {
return `${formatSize(speed)}/s` const base = isBinary ? 1024 : 1000
} if (!data || data === 0) return '0'
Vue.filter('networkSpeed', formatNetworkSpeed) let i = 1
while (data >= base ** i) {
export function networkSize(size: number) { i++
if (size === 0) {
return null
} }
return toPrecision(data / base ** (i - 1), i > 1 ? 3 : 1)
return formatSize(size)
} }
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 === 0) return 'B'
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))
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 formatData(data: number, isBinary: boolean) {
return `${formatDataValue(data, isBinary)} ${formatDataUnit(data, isBinary)}`
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))}`
} }
Vue.filter('formatData', formatData)
Vue.filter('getDataValue', getDataValue) export function formatSpeedValue(speed: number, isBits: boolean) {
if (isBits) speed *= 8
export function getData(data: number, precision: number = 2) { return formatDataValue(speed, false)
return `${getDataValue(data, precision)} ${getDataUnit(data)}`
} }
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 { export function titleCase(str: string): string {
if (str.length == 0) return str if (str.length == 0) return str

View file

@ -1,22 +1,6 @@
import * as _ from 'lodash' import * as _ from 'lodash'
import { isProduction } from './utils' 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') export const isWindows = navigator.userAgent.includes('Windows')
/** /**

View file

@ -270,6 +270,8 @@
"dateFormat": "Date Format", "dateFormat": "Date Format",
"openSideBarOnStart": "Open Side Bar on launch", "openSideBarOnStart": "Open Side Bar on launch",
"showShutdownButton": "Show shutdown button", "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", "refreshInterval": "qBittorrent API refresh interval",
"refreshIntervalHint": "In milliseconds", "refreshIntervalHint": "In milliseconds",
"contentInterval": "Torrent file content refresh interval", "contentInterval": "Torrent file content refresh interval",

View file

@ -9,7 +9,7 @@ export default defineComponent({
torrent: Torrent torrent: Torrent
}, },
computed: { computed: {
...mapGetters(['getTheme']), ...mapGetters(['getTheme', 'shouldUseBinaryData', 'shouldUseBitSpeed']),
phoneLayout() { phoneLayout() {
return this.$vuetify.breakpoint.xsOnly 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 ..., {}>'. // @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() return this.getTheme()
}, },
state() { torrentStateClass() {
if (!this.torrent) return TorrentState.UNKNOWN.toString().toLowerCase() if (!this.torrent) return TorrentState.UNKNOWN.toString().toLowerCase()
return this.torrent.state.toLowerCase() return this.torrent.state.toLowerCase()
} }

View file

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

View file

@ -1,6 +1,6 @@
import { i18n } from '@/plugins/i18n' import { i18n } from '@/plugins/i18n'
import type { StoreState } from '@/types/vuetorrent' import type { StoreState } from '@/types/vuetorrent'
import { formatSize } from '@/filters' import { formatData } from '@/filters'
import { Torrent } from '@/models' import { Torrent } from '@/models'
export default { export default {
@ -32,12 +32,14 @@ export default {
return i18n return i18n
.tc('dashboard.selectedTorrentsCount', state.filteredTorrentsCount) .tc('dashboard.selectedTorrentsCount', state.filteredTorrentsCount)
.replace('$0', state.selected_torrents.length.toString()) .replace('$0', state.selected_torrents.length.toString())
.replace('$1', formatSize(selectedSize)) .replace('$1', formatData(selectedSize, getters.shouldUseBinaryData()))
} else { } else {
return i18n.tc('dashboard.torrentsCount', state.filteredTorrentsCount) return i18n.tc('dashboard.torrentsCount', state.filteredTorrentsCount)
} }
}, },
getSearchPlugins: (state: StoreState) => () => state.searchPlugins, getSearchPlugins: (state: StoreState) => () => state.searchPlugins,
getApiRefreshInterval: (state: StoreState) => () => state.webuiSettings.refreshInterval, 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', dateFormat: 'DD/MM/YYYY, HH:mm:ss',
openSideBarOnStart: true, openSideBarOnStart: true,
showShutdownButton: true, showShutdownButton: true,
useBitSpeed: false,
useBinaryUnits: false,
refreshInterval: 2000, refreshInterval: 2000,
contentInterval: 5000, contentInterval: 5000,
torrentPieceCountRenderThreshold: 5000, torrentPieceCountRenderThreshold: 5000,

View file

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

View file

@ -3,21 +3,20 @@ import { createLocalVue, mount } from '@vue/test-utils'
import Vuetify from 'vuetify' import Vuetify from 'vuetify'
import { Ripple } from 'vuetify/lib/directives' import { Ripple } from 'vuetify/lib/directives'
import filters from '@/filters'
Vue.use(Vuetify, { Vue.use(Vuetify, {
directives: { directives: {
Ripple 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 localVue = createLocalVue() // because of vuetify, we should use a localVue instance
const vuetify = new Vuetify() const vuetify = new Vuetify()
return mount(component, { return mount(component, {
localVue, localVue,
vuetify, 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 DesktopCard from '@/components/Settings/Tabs/VueTorrent/VDesktopCard.vue'
import { DashboardProperty } from '@/enums/vuetorrent' import { DashboardProperty } from '@/enums/vuetorrent'
let wrapper
const desktopPropertiesTemplate = [ const desktopPropertiesTemplate = [
{ name: DashboardProperty.SIZE, active: true }, { name: DashboardProperty.SIZE, active: true },
{ name: DashboardProperty.PROGRESS, active: true }, { name: DashboardProperty.PROGRESS, active: true },
@ -81,6 +79,7 @@ const desktopPropertiesTemplateExpected = [
{ name: 'GlobalVolume', active: false } { name: 'GlobalVolume', active: false }
] ]
let wrapper
describe('DesktopCard', () => { describe('DesktopCard', () => {
beforeEach(() => { beforeEach(() => {
wrapper = shallowMount(DesktopCard, { wrapper = shallowMount(DesktopCard, {

View file

@ -1,26 +1,31 @@
import { describe, it, expect } from 'vitest' import { describe, beforeEach, it, expect, vi } from 'vitest'
import { setup } from '../helpers' 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 { mdiChevronDown } from '@mdi/js'
import SpeedCard from '@/components/Core/SpeedCard.vue' import SpeedCard from '@/components/Core/SpeedCard.vue'
import {setup} from "../helpers";
describe('SpeedCard.vue', () => { describe('SpeedCard.vue', () => {
it('should render the card', () => { 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) expect(wrapper.find('[data-testid="SpeedCard"]').exists()).toBe(true)
}) })
it("shouldn't render the icon", () => { 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) expect(wrapper.find('[data-testid="SpeedCard-icon"]').exists()).toBe(false)
}) })
it('should render the icon', () => { 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) expect(wrapper.find('[data-testid="SpeedCard-icon"]').exists()).toBe(true)
}) })
it('should render with 0 as value', () => { 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"]').exists()).toBe(true)
expect(wrapper.find('[data-testid="SpeedCard-value"]').text()).toBe('0') 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', () => { it('should render value (0 decimals) and unit & be formatted', () => {
const wrapper = setup(SpeedCard, { value: 26823 }) const wrapper = setup(SpeedCard, { value: 26823 }, { $store: { getters: { shouldUseBitSpeed: vi.fn().mockReturnValue(false) } } })
expect(wrapper.find('[data-testid="SpeedCard-value"]').text()).toBe('26') 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', () => { it('should render value (1 decimals) and unit & be formatted', () => {
const wrapper = setup(SpeedCard, { value: 10899700 }) const wrapper = setup(SpeedCard, { value: 10899700 }, { $store: { getters: { shouldUseBitSpeed: vi.fn().mockReturnValue(false) } } })
expect(wrapper.find('[data-testid="SpeedCard-value"]').text()).toBe('10.4') expect(wrapper.find('[data-testid="SpeedCard-value"]').text()).toBe('10.9')
expect(wrapper.find('[data-testid="SpeedCard-unit"]').text()).toBe('MB/s') expect(wrapper.find('[data-testid="SpeedCard-unit"]').text()).toBe('MB/s')
}) })

View file

@ -1,16 +1,34 @@
import { describe, it, expect } from 'vitest' import { describe, beforeEach, it, expect, vi } from 'vitest'
import { setup } from '../helpers' import { shallowMount } from '@vue/test-utils'
import StorageCard from '@/components/Core/StorageCard.vue' import StorageCard from '@/components/Core/StorageCard.vue'
const label = 'Downloaded'
const value = 10000
const color = 'download'
let wrapper
describe('StorageCard.vue', () => { 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', () => { it('should render the label', () => {
const label = 'Downloaded'
const wrapper = setup(StorageCard, { label })
expect(wrapper.find('[data-testid="StorageCard-label"]').text()).toEqual(label) expect(wrapper.find('[data-testid="StorageCard-label"]').text()).toEqual(label)
}) })
it('should render value and unit & be formatted', () => { 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"]').exists()).toBe(true)
expect(wrapper.find('[data-testid="StorageCard-value"]').text()).toBe('9.77') 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', () => { 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-label"]').classes()).toContain(color + '--text')
expect(wrapper.find('[data-testid="StorageCard-Wrapper"]').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`] = ` exports[`General > render correctly 1`] = `
"<v-card-stub data-v-7da6d3e2=\\"\\" loaderheight=\\"4\\" tag=\\"div\\" flat=\\"true\\"> "<v-card-stub data-v-7da6d3e2=\\"\\" loaderheight=\\"4\\" tag=\\"div\\" flat=\\"true\\">
<v-subheader-stub data-v-7da6d3e2=\\"\\"> </v-subheader-stub> <v-subheader-stub data-v-7da6d3e2=\\"\\"> </v-subheader-stub>
<v-list-item-stub data-v-7da6d3e2=\\"\\" activeclass=\\"\\" tag=\\"div\\"> <v-list-item-stub data-v-7da6d3e2=\\"\\" activeclass=\\"\\" tag=\\"div\\" class=\\"my-3\\">
<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-row-stub data-v-7da6d3e2=\\"\\" tag=\\"div\\">
</v-list-item-stub> <v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<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-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-list-item-stub> <v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<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-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-list-item-stub> <v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<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-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-list-item-stub> <v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<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-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-list-item-stub> <v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<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-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-list-item-stub> <v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<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-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-list-item-stub> <v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<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-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-list-item-stub> <v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<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-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-list-item-stub> <v-col-stub data-v-7da6d3e2=\\"\\" cols=\\"12\\" sm=\\"6\\" tag=\\"div\\">
<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-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-list-item-stub>
<v-divider-stub data-v-7da6d3e2=\\"\\" class=\\"mb-5\\"></v-divider-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\\"> <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 { describe, it, expect } from 'vitest'
import { titleCase, capitalize } from '@/filters' import {titleCase, capitalize, formatData, formatSpeed, toPrecision} from '@/filters'
describe('Filters', () => { describe('Filters', () => {
it('titleCase', () => { it('titleCase', () => {
@ -10,11 +10,63 @@ describe('Filters', () => {
expect(titleCase('hello there')).toEqual('Hello There') expect(titleCase('hello there')).toEqual('Hello There')
}) })
it('capitaliza', () => { it('capitalize', () => {
expect(capitalize('')).toEqual('') expect(capitalize('')).toEqual('')
expect(capitalize('-')).toEqual('-') expect(capitalize('-')).toEqual('-')
expect(capitalize('test')).toEqual('Test') expect(capitalize('test')).toEqual('Test')
expect(capitalize('hello There')).toEqual('Hello there') expect(capitalize('hello There')).toEqual('Hello there')
expect(capitalize('i like vuetorrent')).toEqual('I like vuetorrent') 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')
})
}) })