mirror of
https://github.com/VueTorrent/VueTorrent.git
synced 2025-03-14 12:10:18 +03:00
perf: sort dropdown in dashboard #309
This commit is contained in:
parent
54b345682f
commit
b557db48e8
8 changed files with 109 additions and 152 deletions
14
package-lock.json
generated
14
package-lock.json
generated
|
@ -28,7 +28,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@faker-js/faker": "^7.6.0",
|
||||
"@mdi/js": "^5.9.55",
|
||||
"@mdi/js": "^7",
|
||||
"@types/jsdom": "^20.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5",
|
||||
"@typescript-eslint/parser": "^5",
|
||||
|
@ -1949,9 +1949,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@mdi/js": {
|
||||
"version": "5.9.55",
|
||||
"resolved": "https://registry.npmjs.org/@mdi/js/-/js-5.9.55.tgz",
|
||||
"integrity": "sha512-BbeHMgeK2/vjdJIRnx12wvQ6s8xAYfvMmEAVsUx9b+7GiQGQ9Za8jpwp17dMKr9CgKRvemlAM4S7S3QOtEbp4A==",
|
||||
"version": "7.0.96",
|
||||
"resolved": "https://registry.npmjs.org/@mdi/js/-/js-7.0.96.tgz",
|
||||
"integrity": "sha512-lNqhkV3cpPfYb/Avh+vXLFukUTbHbyHoFo4Jdc7Oc9UvURGVhamFIpgOVvEf2bNA78zvjXTZeVWExUTR+DLBfQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
|
@ -9068,9 +9068,9 @@
|
|||
}
|
||||
},
|
||||
"@mdi/js": {
|
||||
"version": "5.9.55",
|
||||
"resolved": "https://registry.npmjs.org/@mdi/js/-/js-5.9.55.tgz",
|
||||
"integrity": "sha512-BbeHMgeK2/vjdJIRnx12wvQ6s8xAYfvMmEAVsUx9b+7GiQGQ9Za8jpwp17dMKr9CgKRvemlAM4S7S3QOtEbp4A==",
|
||||
"version": "7.0.96",
|
||||
"resolved": "https://registry.npmjs.org/@mdi/js/-/js-7.0.96.tgz",
|
||||
"integrity": "sha512-lNqhkV3cpPfYb/Avh+vXLFukUTbHbyHoFo4Jdc7Oc9UvURGVhamFIpgOVvEf2bNA78zvjXTZeVWExUTR+DLBfQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@nodelib/fs.scandir": {
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@faker-js/faker": "^7.6.0",
|
||||
"@mdi/js": "^5.9.55",
|
||||
"@mdi/js": "^7",
|
||||
"@types/jsdom": "^20.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5",
|
||||
"@typescript-eslint/parser": "^5",
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
</v-btn>
|
||||
<v-dialog v-model="opened" width="50%">
|
||||
<v-card class="pa-0">
|
||||
<v-card-title class="justify-center pa-1" >
|
||||
<v-card-title class="justify-center pa-1">
|
||||
<v-toolbar flat dense class="transparent">
|
||||
<v-toolbar-title>
|
||||
<v-icon>{{ mdiToyBrick }}</v-icon> Plugin manager
|
||||
<v-icon>{{ mdiToyBrick }}</v-icon> Plugin manager
|
||||
</v-toolbar-title>
|
||||
<v-spacer/>
|
||||
<v-spacer />
|
||||
<v-btn fab small class="transparent elevation-0" @click="close">
|
||||
<v-icon>{{ mdiClose }}</v-icon>
|
||||
</v-btn>
|
||||
|
@ -54,7 +54,7 @@ export default {
|
|||
togglePlugin(plugin) {
|
||||
qbit.enableSearchPlugin([plugin.name], plugin.enabled)
|
||||
},
|
||||
close(){
|
||||
close() {
|
||||
this.opened = false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
<template>
|
||||
<v-dialog v-model="dialog" scrollable content-class="rounded-form" max-width="500px">
|
||||
<v-card>
|
||||
<v-card-title class="justify-center primarytext--text">
|
||||
<h2>{{ $t('modals.sort.title') }}</h2>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-form class="px-6 mt-3 justify-center mx-auto">
|
||||
<v-container class="sortmodal">
|
||||
<v-select v-model="sort_options.sort" :value="sortProperty" flat class="ml-2 mr-2" :items="options" item-text="name" item-value="value" dense solo height="55" />
|
||||
<v-switch v-model="sort_options.reverse" class="v-input--reverse v-input--expand pa-0 ma-0" inset color="accent" style="padding-left: 10px !important">
|
||||
<template #label>
|
||||
{{ $t('modals.sort.reverse') }}
|
||||
</template>
|
||||
</v-switch>
|
||||
</v-container>
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import { Modal } from '@/mixins'
|
||||
export default {
|
||||
name: 'Sort',
|
||||
mixins: [Modal],
|
||||
data() {
|
||||
return {
|
||||
sortProperty: { value: 'added_on', name: 'Added On' },
|
||||
reverse: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['sort_options']),
|
||||
options() {
|
||||
return [
|
||||
{ value: 'added_on', name: this.$i18n.t('modals.sort.sortBy.addedOn') },
|
||||
{ value: 'availability', name: this.$i18n.t('modals.sort.sortBy.availability') },
|
||||
{ value: 'category', name: this.$i18n.t('modals.sort.sortBy.category') },
|
||||
{ value: 'completed', name: this.$i18n.t('modals.sort.sortBy.completed') },
|
||||
{ value: 'dlspeed', name: this.$i18n.t('modals.sort.sortBy.downloadSpeed') },
|
||||
{ value: 'downloaded', name: this.$i18n.t('modals.sort.sortBy.downloaded') },
|
||||
{ value: 'eta', name: this.$i18n.t('modals.sort.sortBy.ETA') },
|
||||
{ value: 'name', name: this.$i18n.t('modals.sort.sortBy.name') },
|
||||
{ value: 'num_leechs', name: this.$i18n.t('modals.sort.sortBy.peers') },
|
||||
{ value: 'priority', name: this.$i18n.t('modals.sort.sortBy.priority') },
|
||||
{ value: 'progress', name: this.$i18n.t('modals.sort.sortBy.progress') },
|
||||
{ value: 'ratio', name: this.$i18n.t('modals.sort.sortBy.ratio') },
|
||||
{ value: 'save_path', name: this.$i18n.t('modals.sort.sortBy.save_path') },
|
||||
{ value: 'size', name: this.$i18n.t('modals.sort.sortBy.size') },
|
||||
{ value: 'state', name: this.$i18n.t('modals.sort.sortBy.state') },
|
||||
{ value: 'time_active', name: this.$i18n.t('modals.sort.sortBy.timeActive') },
|
||||
{ value: 'uploaded', name: this.$i18n.t('modals.sort.sortBy.uploaded') },
|
||||
{ value: 'upspeed', name: this.$i18n.t('modals.sort.sortBy.uploadSpeed') }
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.dialog = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.sortmodal .v-select__selection,
|
||||
.v-input__icon i {
|
||||
color: var(--search) !important;
|
||||
}
|
||||
// Reversed input variant
|
||||
:deep(.v-input--reverse .v-input__slot) {
|
||||
@import 'src/styles/styles.scss';
|
||||
@include reverse-switch;
|
||||
}
|
||||
</style>
|
|
@ -71,9 +71,9 @@ export default {
|
|||
methods: {
|
||||
create() {
|
||||
this.$refs.categoryForm.validate()
|
||||
|
||||
|
||||
return
|
||||
|
||||
|
||||
qbit.createCategory(this.category)
|
||||
this.cancel()
|
||||
},
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
<v-subheader>
|
||||
{{ $t('modals.settings.pageConnection.listeningSubHeader') }}
|
||||
</v-subheader>
|
||||
<v-list-item>
|
||||
<v-text-field v-model="settings.listen_port" class="mb-2" outlined dense type="number" hide-details :label="$t('modals.settings.pageConnection.incomingConnectionPort')" />
|
||||
</v-list-item>
|
||||
<v-list-item>
|
||||
<v-checkbox v-model="settings.upnp" hide-details class="ma-0 pa-0" :label="$t('modals.settings.pageConnection.useUPnP')" />
|
||||
</v-list-item>
|
||||
<v-list-item>
|
||||
<v-text-field v-model="settings.listen_port" class="mb-2" outlined dense type="number" hide-details :label="$t('modals.settings.pageConnection.incomingConnectionPort')" />
|
||||
</v-list-item>
|
||||
<v-list-item>
|
||||
<v-checkbox v-model="settings.upnp" hide-details class="ma-0 pa-0" :label="$t('modals.settings.pageConnection.useUPnP')" />
|
||||
</v-list-item>
|
||||
<v-subheader>
|
||||
{{ $t('modals.settings.pageConnection.subHeader') }}
|
||||
</v-subheader>
|
||||
|
@ -133,7 +133,7 @@ export default {
|
|||
bittorrent_protocol: [
|
||||
{ value: 0, text: 'TCP and μTP' },
|
||||
{ value: 1, text: 'TCP' },
|
||||
{ value: 2, text: 'μTP' },
|
||||
{ value: 2, text: 'μTP' }
|
||||
]
|
||||
}
|
||||
},
|
||||
|
|
|
@ -10,7 +10,7 @@ export function formatBytes(a, b) {
|
|||
return `${parseFloat((a / Math.pow(c, f)).toFixed(d))} ${e[f]}`
|
||||
}
|
||||
|
||||
import { mdiLanguageHtml5, mdiFileDocumentOutline, mdiNodejs, mdiFilePdf, mdiFileExcel, mdiCodeJson, mdiFileImage, mdiMovie, mdiLanguageMarkdown, mdiFile } from '@mdi/js'
|
||||
import { mdiLanguageHtml5, mdiFileDocumentOutline, mdiNodejs, mdiFilePdfBox, mdiFileExcel, mdiCodeJson, mdiFileImage, mdiMovie, mdiLanguageMarkdown, mdiFile } from '@mdi/js'
|
||||
|
||||
export function getIconForFileType(type) {
|
||||
const types = {
|
||||
|
@ -18,7 +18,7 @@ export function getIconForFileType(type) {
|
|||
js: mdiNodejs,
|
||||
json: mdiCodeJson,
|
||||
md: mdiLanguageMarkdown,
|
||||
pdf: mdiFilePdf,
|
||||
pdf: mdiFilePdfBox,
|
||||
png: mdiFileImage,
|
||||
txt: mdiFileDocumentOutline,
|
||||
sub: mdiFileDocumentOutline,
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<template>
|
||||
<div class="px-1 px-sm-5 pt-4 background noselect" @click.self="resetSelected">
|
||||
<v-row class="ma-0 pa-0" @click.self="resetSelected">
|
||||
<v-row class="ma-0 pa-0 mb-2" @click.self="resetSelected">
|
||||
<v-col v-if="topPagination && isMobile" cols="12" class="align-center justify-center pa-0">
|
||||
<div class="text-center">
|
||||
<v-pagination v-if="pageCount > 1 && !hasSearchFilter" v-model="pageNumber" :length="pageCount" :total-visible="7" @input="toTop" />
|
||||
</div>
|
||||
</v-col>
|
||||
<v-expand-x-transition>
|
||||
<v-card v-show="searchFilterEnabled" id="searchFilter" flat xs7 md3 class="ma-0 pa-0 mt-1 transparent">
|
||||
<v-card v-show="searchFilterEnabled" id="searchFilter" flat xs7 md3 class="ma-0 pa-0 transparent">
|
||||
<v-text-field
|
||||
v-model="input"
|
||||
autofocus
|
||||
|
@ -25,48 +25,62 @@
|
|||
/>
|
||||
</v-card>
|
||||
</v-expand-x-transition>
|
||||
<v-row style="margin-top: 6px" class="mb-1 mx-1">
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-btn text small fab class="mr-0 ml-0" aria-label="Select Mode" v-on="on" @click="searchFilterEnabled = !searchFilterEnabled">
|
||||
<v-icon color="grey">
|
||||
{{ searchFilterEnabled ? mdiChevronLeftCircle : mdiTextBoxSearch }}
|
||||
</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
<span>Toggle Search Filter</span>
|
||||
</v-tooltip>
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-btn text small fab class="mr-0 ml-0" aria-label="Select Mode" v-on="on" @click="toggleSelectMode()">
|
||||
<v-icon color="grey">
|
||||
{{ $store.state.selectMode ? mdiCheckboxMarked : mdiCheckboxBlankOutline }}
|
||||
</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
<span>Select Mode</span>
|
||||
</v-tooltip>
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-btn text small fab class="mr-0 ml-0" aria-label="Sort Torrents" v-on="on" @click="addModal('SortModal')">
|
||||
<v-icon color="grey">
|
||||
{{ mdiSort }}
|
||||
</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
<span>Sort Torrents</span>
|
||||
</v-tooltip>
|
||||
<v-col v-if="topPagination && !isMobile" cols="8" class="align-center justify-center pa-0">
|
||||
<div class="text-center">
|
||||
<v-pagination v-if="pageCount > 1 && !hasSearchFilter" v-model="pageNumber" :length="pageCount" :total-visible="7" @input="toTop" />
|
||||
</div>
|
||||
</v-col>
|
||||
<v-col class="align-center justify-center">
|
||||
<span style="float: right; font-size: 0.8em" class="mr-2 text-uppercase">
|
||||
{{ torrentCountString }}
|
||||
</span>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-btn text small fab class="mr-0 ml-0" aria-label="Select Mode" v-on="on" @click="searchFilterEnabled = !searchFilterEnabled">
|
||||
<v-icon color="grey">
|
||||
{{ searchFilterEnabled ? mdiChevronLeftCircle : mdiTextBoxSearch }}
|
||||
</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
<span>Toggle Search Filter</span>
|
||||
</v-tooltip>
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-btn text small fab class="mr-0 ml-0" aria-label="Select Mode" v-on="on" @click="toggleSelectMode">
|
||||
<v-icon color="grey">
|
||||
{{ $store.state.selectMode ? mdiCheckboxMarked : mdiCheckboxBlankOutline }}
|
||||
</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
<span>Select Mode</span>
|
||||
</v-tooltip>
|
||||
<v-expand-x-transition>
|
||||
<v-card v-show="sortEnabled" flat class="ma-0 pa-0 mt-1 transparent">
|
||||
<v-select
|
||||
v-model="sort_options.sort"
|
||||
flat
|
||||
solo
|
||||
dense
|
||||
height="30"
|
||||
class="ml-2 mr-2"
|
||||
:items="sortOptions"
|
||||
style="max-width: 10em"
|
||||
:prepend-icon="sort_options.reverse ? mdiArrowUpThin : mdiArrowDownThin"
|
||||
@click:prepend="$store.state.sort_options.reverse = !$store.state.sort_options.reverse"
|
||||
/>
|
||||
</v-card>
|
||||
</v-expand-x-transition>
|
||||
<v-tooltip bottom>
|
||||
<template #activator="{ on }">
|
||||
<v-btn text small fab class="mr-0 ml-0" aria-label="Sort Torrents" v-on="on" @click="sortEnabled = !sortEnabled">
|
||||
<v-icon color="grey">
|
||||
{{ sortEnabled ? mdiChevronLeftCircle : mdiSort }}
|
||||
</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
<span>Sort Torrents</span>
|
||||
</v-tooltip>
|
||||
<v-col v-if="topPagination && !isMobile" cols="8" class="align-center justify-center pa-0">
|
||||
<div class="text-center">
|
||||
<v-pagination v-if="pageCount > 1 && !hasSearchFilter" v-model="pageNumber" :length="pageCount" :total-visible="7" @input="toTop" />
|
||||
</div>
|
||||
</v-col>
|
||||
<v-col class="align-center justify-center">
|
||||
<span style="float: right; font-size: 0.8em" class="mr-2 text-uppercase">
|
||||
{{ torrentCountString }}
|
||||
</span>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row id="selectAllTorrents" class="ma-0 pa-0">
|
||||
<v-expand-transition>
|
||||
|
@ -129,8 +143,8 @@
|
|||
|
||||
<script>
|
||||
import { mapState, mapGetters } from 'vuex'
|
||||
import { mdiTextBoxSearch, mdiChevronLeftCircle, mdiMagnify, mdiCheckboxMarked, mdiCheckboxBlankOutline, mdiSort } from '@mdi/js'
|
||||
import { QuickScore } from "quick-score"
|
||||
import { mdiTextBoxSearch, mdiChevronLeftCircle, mdiMagnify, mdiCheckboxMarked, mdiCheckboxBlankOutline, mdiSort, mdiArrowUpThin, mdiArrowDownThin } from '@mdi/js'
|
||||
import { QuickScore } from 'quick-score'
|
||||
|
||||
import Torrent from '@/components/Torrent/Torrent.vue'
|
||||
import TorrentRightClickMenu from '@/components/Torrent/TorrentRightClickMenu.vue'
|
||||
|
@ -157,22 +171,43 @@ export default {
|
|||
},
|
||||
trcMoveTick: 0,
|
||||
searchFilterEnabled: false,
|
||||
sortEnabled: false,
|
||||
sortOptions: [
|
||||
{ value: 'added_on', text: this.$i18n.t('modals.sort.sortBy.addedOn') },
|
||||
{ value: 'availability', text: this.$i18n.t('modals.sort.sortBy.availability') },
|
||||
{ value: 'category', text: this.$i18n.t('modals.sort.sortBy.category') },
|
||||
{ value: 'completed', text: this.$i18n.t('modals.sort.sortBy.completed') },
|
||||
{ value: 'dlspeed', text: this.$i18n.t('modals.sort.sortBy.downloadSpeed') },
|
||||
{ value: 'downloaded', text: this.$i18n.t('modals.sort.sortBy.downloaded') },
|
||||
{ value: 'eta', text: this.$i18n.t('modals.sort.sortBy.ETA') },
|
||||
{ value: 'name', text: this.$i18n.t('modals.sort.sortBy.name') },
|
||||
{ value: 'num_leechs', text: this.$i18n.t('modals.sort.sortBy.peers') },
|
||||
{ value: 'priority', text: this.$i18n.t('modals.sort.sortBy.priority') },
|
||||
{ value: 'progress', text: this.$i18n.t('modals.sort.sortBy.progress') },
|
||||
{ value: 'ratio', text: this.$i18n.t('modals.sort.sortBy.ratio') },
|
||||
{ value: 'save_path', text: this.$i18n.t('modals.sort.sortBy.save_path') },
|
||||
{ value: 'size', text: this.$i18n.t('modals.sort.sortBy.size') },
|
||||
{ value: 'state', text: this.$i18n.t('modals.sort.sortBy.state') },
|
||||
{ value: 'time_active', text: this.$i18n.t('modals.sort.sortBy.timeActive') },
|
||||
{ value: 'uploaded', text: this.$i18n.t('modals.sort.sortBy.uploaded') },
|
||||
{ value: 'upspeed', text: this.$i18n.t('modals.sort.sortBy.uploadSpeed') }
|
||||
],
|
||||
mdiTextBoxSearch,
|
||||
mdiChevronLeftCircle,
|
||||
mdiMagnify,
|
||||
mdiCheckboxBlankOutline,
|
||||
mdiCheckboxMarked,
|
||||
mdiSort
|
||||
mdiSort,
|
||||
mdiArrowUpThin,
|
||||
mdiArrowDownThin
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['mainData', 'selected_torrents', 'dashboard']),
|
||||
...mapState(['mainData', 'selected_torrents', 'dashboard', 'sort_options']),
|
||||
...mapGetters(['getTorrents', 'getTorrentCountString', 'getWebuiSettings']),
|
||||
torrents() {
|
||||
if (!this.hasSearchFilter) return this.getTorrents()
|
||||
|
||||
// return this.getTorrents()
|
||||
|
||||
const qs = new QuickScore(this.getTorrents(), ['name', 'size', 'state', 'hash', 'savePath', 'tags', 'category'])
|
||||
return qs.search(this.input).map(el => el.item)
|
||||
},
|
||||
|
@ -249,7 +284,7 @@ export default {
|
|||
created() {
|
||||
this.$store.dispatch('INIT_INTERVALS')
|
||||
this.$store.commit('FETCH_CATEGORIES')
|
||||
if(this.input) this.searchFilterEnabled = true
|
||||
if (this.input) this.searchFilterEnabled = true
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$store.commit('REMOVE_INTERVALS')
|
||||
|
|
Loading…
Add table
Reference in a new issue