mirror of
https://github.com/VueTorrent/VueTorrent.git
synced 2025-03-14 12:10:18 +03:00
0.4.2 (#54)
This commit is contained in:
parent
dde4c08f2b
commit
0b4b234b4b
41 changed files with 1143 additions and 734 deletions
8
.github/pull_request_template.md
vendored
Normal file
8
.github/pull_request_template.md
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Features
|
||||
- a
|
||||
# Fixes
|
||||
- b
|
||||
# Improvements
|
||||
- c
|
||||
|
||||
|
|
@ -71,6 +71,14 @@ The sleekest looking WEBUI for qBittorrent made with Vuejs!
|
|||
|
||||
- tag & category support
|
||||
|
||||
- Keyboard shortcuts!
|
||||
- select all torrents with ctrl+A
|
||||
- delete selected with delete button
|
||||
- select with ctrl+click or from right-click-menu (regular tap on mobile still works)
|
||||
- shift + click to select from one torrent until another
|
||||
|
||||
- Which torrent properties are shown is configurable in the dashboard (for both busy and completed torrents)
|
||||
|
||||
- works on QBittorrent V4.2 and later
|
||||
|
||||
## Contributing
|
||||
|
|
15
package-lock.json
generated
15
package-lock.json
generated
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "vuetorrent",
|
||||
"version": "0.4.0",
|
||||
"version": "0.4.2",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
@ -10795,6 +10795,11 @@
|
|||
"is-plain-obj": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"sortablejs": {
|
||||
"version": "1.12.0",
|
||||
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.12.0.tgz",
|
||||
"integrity": "sha512-bPn57rCjBRlt2sC24RBsu40wZsmLkSo2XeqG8k6DC1zru5eObQUIPPZAQG7W2SJ8FZQYq+BEJmvuw1Zxb3chqg=="
|
||||
},
|
||||
"source-list-map": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
|
||||
|
@ -12143,6 +12148,14 @@
|
|||
"postcss-import": "^12.0.0"
|
||||
}
|
||||
},
|
||||
"vuedraggable": {
|
||||
"version": "2.24.2",
|
||||
"resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-2.24.2.tgz",
|
||||
"integrity": "sha512-y1NbVhLFOVHHdJl7qsYOtExiTq4zyxF+PxiF9NC8kHEtI6sAFhUHtHYp+ONa8v4S3bAspzGHOHuOq0pNO4fFtA==",
|
||||
"requires": {
|
||||
"sortablejs": "^1.10.1"
|
||||
}
|
||||
},
|
||||
"vuetify": {
|
||||
"version": "2.3.14",
|
||||
"resolved": "https://registry.npmjs.org/vuetify/-/vuetify-2.3.14.tgz",
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
{
|
||||
"name": "vuetorrent",
|
||||
"version": "0.4.1",
|
||||
"version": "0.4.2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start" : "npm run serve",
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
|
@ -24,6 +25,7 @@
|
|||
"vue-router": "^3.4.7",
|
||||
"vue-toastification": "^1.7.8",
|
||||
"vue2-perfect-scrollbar": "^1.5.0",
|
||||
"vuedraggable": "^2.24.2",
|
||||
"vuetify": "^2.3.14",
|
||||
"vuex": "^3.5.1",
|
||||
"vuex-persist": "^3.1.3"
|
||||
|
|
|
@ -30,7 +30,7 @@ export default {
|
|||
const res = await qbit.login()
|
||||
const authenticated = res === 'Ok.'
|
||||
this.$store.commit('LOGIN', authenticated)
|
||||
if (!authenticated && this.$router.currentRoute.name !== 'login') this.$router.push('login')
|
||||
if (!authenticated && !this.$router.currentRoute.name.includes('login')) this.$router.push('login')
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
|
@ -10,39 +10,45 @@
|
|||
<v-container>
|
||||
<v-row no-gutters>
|
||||
<v-col ref="fileZone">
|
||||
<v-file-input
|
||||
v-model="files"
|
||||
color="deep-purple accent-4"
|
||||
counter
|
||||
label="File input"
|
||||
multiple
|
||||
placeholder="Select your files"
|
||||
prepend-icon="mdi-paperclip"
|
||||
outlined
|
||||
:show-size="1000"
|
||||
<div
|
||||
@drop.prevent="addDropFile"
|
||||
@dragover.prevent
|
||||
>
|
||||
<template
|
||||
v-slot:selection="{ index, text }"
|
||||
<v-file-input
|
||||
v-if="!urls"
|
||||
v-model="files"
|
||||
color="deep-purple accent-4"
|
||||
counter
|
||||
label="File input"
|
||||
multiple
|
||||
placeholder="Select your files"
|
||||
prepend-icon="mdi-paperclip"
|
||||
:rules="fileInputRules"
|
||||
outlined
|
||||
:show-size="1000"
|
||||
>
|
||||
<v-chip
|
||||
v-if="index < 2"
|
||||
color="deep-purple accent-4"
|
||||
dark
|
||||
label
|
||||
small
|
||||
>{{ text }}</v-chip
|
||||
<template
|
||||
v-slot:selection="{ index, text }"
|
||||
>
|
||||
|
||||
<span
|
||||
v-else-if="index === 2"
|
||||
class="overline grey--text text--darken-3 mx-2"
|
||||
>+{{
|
||||
files.length - 2
|
||||
}}
|
||||
File(s)</span
|
||||
>
|
||||
</template>
|
||||
</v-file-input>
|
||||
<v-chip
|
||||
v-if="index < 2"
|
||||
color="deep-purple accent-4"
|
||||
dark
|
||||
label
|
||||
small
|
||||
>{{ text }}</v-chip
|
||||
>
|
||||
<span
|
||||
v-else-if="index === 2"
|
||||
class="overline grey--text text--darken-3 mx-2"
|
||||
>+{{
|
||||
files.length - 2
|
||||
}}
|
||||
File(s)</span
|
||||
>
|
||||
</template>
|
||||
</v-file-input>
|
||||
</div>
|
||||
<v-textarea
|
||||
label="URL"
|
||||
prepend-icon="mdi-link"
|
||||
|
@ -123,12 +129,11 @@ export default {
|
|||
directory: '',
|
||||
autoTMM: true,
|
||||
skip_checking: false,
|
||||
inputRules: [
|
||||
v =>
|
||||
v.indexOf('magnet') > -1 ||
|
||||
v.indexOf('http') > -1 ||
|
||||
this.validFile ||
|
||||
'Not a valid magnet link'
|
||||
fileInputRules: [
|
||||
v => {
|
||||
const result = v.every(f => f.type === 'application/x-bittorrent' )
|
||||
return result ? result : 'One or more files is not a valid torrent'
|
||||
}
|
||||
],
|
||||
loading: false,
|
||||
urls: null,
|
||||
|
@ -136,6 +141,10 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
addDropFile(e)
|
||||
{
|
||||
this.files.push(...Array.from(e.dataTransfer.files))
|
||||
},
|
||||
submit() {
|
||||
if (this.files.length || this.urls) {
|
||||
let torrents = []
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<v-dialog
|
||||
v-model="dialog"
|
||||
scrollable
|
||||
:width="dialogWidth"
|
||||
width="85%"
|
||||
:fullscreen="phoneLayout"
|
||||
>
|
||||
<v-card style="min-height: 400px; overflow: hidden !important">
|
||||
|
@ -102,9 +102,6 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
...mapGetters(['getSettings']),
|
||||
dialogWidth() {
|
||||
return this.phoneLayout ? '100%' : '750px'
|
||||
},
|
||||
dialogHeight() {
|
||||
return this.phoneLayout ? '79vh' : '70vh'
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<v-container>
|
||||
<v-container class="pa-3 ma-2">
|
||||
<v-card flat>
|
||||
<v-card-text>
|
||||
<v-card-text :style="{ minHeight: phoneLayout ? '' : '75vh'}">
|
||||
<h3>Privacy</h3>
|
||||
<div class="settings_content ml-5 mr-5">
|
||||
<v-checkbox
|
||||
|
@ -144,11 +144,11 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import SettingsTab from '@/mixins/SettingsTab'
|
||||
import {SettingsTab, FullScreenModal} from '@/mixins'
|
||||
|
||||
export default {
|
||||
name: 'BitTorrent',
|
||||
mixins: [SettingsTab]
|
||||
mixins: [SettingsTab, FullScreenModal]
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<v-container>
|
||||
<v-container class="pa-3 ma-2">
|
||||
<v-card flat>
|
||||
<v-card-text>
|
||||
<v-card-text :style="{ minHeight: phoneLayout ? '' : '75vh'}">
|
||||
<h3>When adding a torrent</h3>
|
||||
<div class="settings_content ml-5 mr-5">
|
||||
<v-checkbox
|
||||
|
@ -69,11 +69,11 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import SettingsTab from '@/mixins/SettingsTab'
|
||||
import {FullScreenModal, SettingsTab} from '@/mixins'
|
||||
|
||||
export default {
|
||||
name: 'Downloads',
|
||||
mixins: [SettingsTab]
|
||||
mixins: [SettingsTab, FullScreenModal]
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
<v-card flat>
|
||||
<v-card-text
|
||||
class="mx-auto mt-5"
|
||||
style="font-size: 1.1em; max-height: 500px; min-height: 300px"
|
||||
style="font-size: 1.1em;"
|
||||
:style="{ minHeight: phoneLayout ? '' : '75vh'}"
|
||||
>
|
||||
<v-layout class="mx-auto" row wrap>
|
||||
<v-flex xs12 sm12>
|
||||
|
@ -72,11 +73,11 @@ import { mapGetters } from 'vuex'
|
|||
|
||||
import qbit from '@/services/qbit'
|
||||
|
||||
import { Tab, General } from '@/mixins'
|
||||
import { Tab, General,FullScreenModal } from '@/mixins'
|
||||
|
||||
export default {
|
||||
name: 'TagsAndCategories',
|
||||
mixins: [Tab, General],
|
||||
mixins: [Tab, General, FullScreenModal],
|
||||
props: {
|
||||
hash: String
|
||||
},
|
||||
|
|
|
@ -1,190 +1,45 @@
|
|||
<template>
|
||||
<v-container>
|
||||
<v-card flat>
|
||||
<v-card-text class="pa-0" style="font-size: 1.1em">
|
||||
<div class="box">
|
||||
<v-subheader
|
||||
>These settings are for the custom WebUI
|
||||
itself</v-subheader
|
||||
>
|
||||
<v-form class="px-6 mt-3">
|
||||
<v-container>
|
||||
<v-switch
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
v-model="showCurrentSpeed"
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label> Show Current Speed </template>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
v-model="showSpeedGraph"
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label> Show Speed Graph</template>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
v-model="showSessionStat"
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label> Show Session Stats </template>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
v-model="freeSpace"
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label> Show Free Space </template>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
v-model="showGlobalRemoveResumePause"
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label>
|
||||
Global Remove/Resume/Pause Buttons</template
|
||||
>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
v-model="denseDashboard"
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label>
|
||||
Dense version of the dasbhoard</template
|
||||
>
|
||||
</v-switch>
|
||||
<v-row dense>
|
||||
<v-col cols="10" sm="10" md="10">
|
||||
<p class="subtitle-1">Pagination size:</p>
|
||||
</v-col>
|
||||
<v-col cols="2" sm="2" md="2">
|
||||
<v-select
|
||||
class="pa-0 ma-0"
|
||||
color="green_accent"
|
||||
:items="paginationSizes"
|
||||
v-model="paginationSize"
|
||||
></v-select>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row dense>
|
||||
<v-col cols="10" sm="10" md="11">
|
||||
<p class="subtitle-1">Current Version:</p>
|
||||
</v-col>
|
||||
<v-col cols="2" sm="2" md="1">
|
||||
<p class="mb-2">{{ version }}</p>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-form>
|
||||
</div>
|
||||
</v-card-text>
|
||||
<div class="ma-1">
|
||||
<v-card flat style="width: 100vh">
|
||||
<v-card-text :style="{ minHeight: phoneLayout ? '' : '75vh'}">
|
||||
<v-tabs v-model="tab">
|
||||
<v-tab href="#general">General</v-tab>
|
||||
<v-tab href="#dashboard">Dashboard</v-tab>
|
||||
</v-tabs>
|
||||
<v-tabs-items
|
||||
v-model="tab"
|
||||
:touch="updateTab(tab)"
|
||||
>
|
||||
<v-tab-item style="width: 100vh" value="general">
|
||||
<General :is-active="tab === 'downloads'" />
|
||||
</v-tab-item>
|
||||
<v-tab-item style="width: 100vh" value="dashboard">
|
||||
<Dashboard :is-active="tab === 'bittorrent'" />
|
||||
</v-tab-item>
|
||||
</v-tabs-items>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapGetters } from 'vuex'
|
||||
import General from './Vuetorrent/General'
|
||||
import Dashboard from './Vuetorrent/Dashboard'
|
||||
import {FullScreenModal} from '@/mixins'
|
||||
|
||||
export default {
|
||||
name: 'VueTorrent',
|
||||
data() {
|
||||
return {
|
||||
paginationSizes: [5, 15, 30, 50]
|
||||
}
|
||||
components: {
|
||||
General, Dashboard
|
||||
},
|
||||
computed: {
|
||||
...mapState(['webuiSettings']),
|
||||
...mapGetters(['getAppVersion']),
|
||||
freeSpace: {
|
||||
get() {
|
||||
return this.webuiSettings.showFreeSpace
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showFreeSpace = val
|
||||
}
|
||||
},
|
||||
showCurrentSpeed: {
|
||||
get() {
|
||||
return this.webuiSettings.showCurrentSpeed
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showCurrentSpeed = val
|
||||
}
|
||||
},
|
||||
showSpeedGraph: {
|
||||
get() {
|
||||
return this.webuiSettings.showSpeedGraph
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showSpeedGraph = val
|
||||
}
|
||||
},
|
||||
showSessionStat: {
|
||||
get() {
|
||||
return this.webuiSettings.showSessionStat
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showSessionStat = val
|
||||
}
|
||||
},
|
||||
showGlobalRemoveResumePause: {
|
||||
get() {
|
||||
return this.webuiSettings.showGlobalRemoveResumePause
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showGlobalRemoveResumePause = val
|
||||
}
|
||||
},
|
||||
denseDashboard: {
|
||||
get() {
|
||||
return this.webuiSettings.denseDashboard
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.denseDashboard = val
|
||||
}
|
||||
},
|
||||
paginationSize: {
|
||||
get() {
|
||||
return this.webuiSettings.paginationSize
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.paginationSize = val
|
||||
}
|
||||
},
|
||||
version() {
|
||||
return this.getAppVersion()
|
||||
mixins: [FullScreenModal],
|
||||
data : () => ({
|
||||
tab: null
|
||||
}),
|
||||
methods: {
|
||||
updateTab(tab) {
|
||||
this.tab = tab
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/assets/styles/SettingsTab.scss';
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// Reversed input variant
|
||||
::v-deep .v-input--reverse .v-input__slot {
|
||||
flex-direction: row-reverse;
|
||||
justify-content: flex-end;
|
||||
.v-application--is-ltr & {
|
||||
.v-input--selection-controls__input {
|
||||
margin-right: 0;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
.v-application--is-rtl & {
|
||||
.v-input--selection-controls__input {
|
||||
margin-left: 0;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</script>
|
|
@ -0,0 +1,81 @@
|
|||
<template>
|
||||
<div class="ma-3 pa-2">
|
||||
<v-card flat>
|
||||
<v-card-text class="pa-0">
|
||||
<v-layout row wrap align-center justify-center>
|
||||
<v-flex class="box ma-1" style="width:50px !important;" xs12 md5>
|
||||
<v-subheader>
|
||||
Properties to display for busy torrents
|
||||
</v-subheader>
|
||||
<v-row dense >
|
||||
<v-list flat class="ma-0 pa-0">
|
||||
<draggable
|
||||
:list="busyTorrentProperties"
|
||||
tag="tbody"
|
||||
>
|
||||
<v-list-item
|
||||
v-for="(item, index) in busyTorrentProperties"
|
||||
:key="index"
|
||||
style="width: 30vh"
|
||||
>
|
||||
<v-checkbox v-model="item.active" dense class="pa-0 ma-0 mt-3"/>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="truncate" v-text="item.name"/>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</draggable>
|
||||
</v-list>
|
||||
</v-row>
|
||||
</v-flex>
|
||||
<v-flex class="box ma-1" xs12 md5>
|
||||
<v-subheader>
|
||||
Properties to display for completed torrents
|
||||
</v-subheader>
|
||||
<v-row dense>
|
||||
<v-list flat class="ma-0 pa-0">
|
||||
<draggable
|
||||
:list="doneTorrentProperties"
|
||||
tag="tbody"
|
||||
>
|
||||
<v-list-item
|
||||
v-for="(item, index) in doneTorrentProperties"
|
||||
:key="index"
|
||||
style="width: 30vh"
|
||||
>
|
||||
<v-checkbox v-model="item.active" dense class="pa-0 ma-0 mt-3"/>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="truncate" v-text="item.name"/>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</draggable>
|
||||
</v-list>
|
||||
</v-row>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import draggable from 'vuedraggable'
|
||||
|
||||
export default {
|
||||
name: 'Dashboard',
|
||||
components: {
|
||||
draggable
|
||||
},
|
||||
computed : {
|
||||
busyTorrentProperties(){
|
||||
return this.$store.state.webuiSettings.busyTorrentProperties
|
||||
},
|
||||
doneTorrentProperties(){
|
||||
return this.$store.state.webuiSettings.doneTorrentProperties
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/assets/styles/SettingsTab.scss';
|
||||
</style>
|
190
src/components/Modals/SettingsModal/Tabs/Vuetorrent/General.vue
Normal file
190
src/components/Modals/SettingsModal/Tabs/Vuetorrent/General.vue
Normal file
|
@ -0,0 +1,190 @@
|
|||
<template>
|
||||
<div class="ma-2">
|
||||
<v-card flat style="width: 100vh">
|
||||
<v-card-text class="pa-0" style="font-size: 1.1em">
|
||||
<div class="box">
|
||||
<v-subheader
|
||||
>These settings are for the custom WebUI
|
||||
itself</v-subheader
|
||||
>
|
||||
<v-form class="px-6 mt-3">
|
||||
<v-container>
|
||||
<v-switch
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
v-model="showCurrentSpeed"
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label> Show Current Speed </template>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
v-model="showSpeedGraph"
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label> Show Speed Graph</template>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
v-model="showSessionStat"
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label> Show Session Stats </template>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
v-model="freeSpace"
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label> Show Free Space </template>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
v-model="showGlobalRemoveResumePause"
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label>
|
||||
Global Remove/Resume/Pause Buttons</template
|
||||
>
|
||||
</v-switch>
|
||||
<v-switch
|
||||
class="v-input--reverse v-input--expand pa-0 ma-0"
|
||||
inset
|
||||
v-model="denseDashboard"
|
||||
color="green_accent"
|
||||
>
|
||||
<template #label>
|
||||
Dense version of the dasbhoard</template
|
||||
>
|
||||
</v-switch>
|
||||
<v-row dense>
|
||||
<v-col cols="10" sm="10" md="10">
|
||||
<p class="subtitle-1">Pagination size:</p>
|
||||
</v-col>
|
||||
<v-col cols="2" sm="2" md="2">
|
||||
<v-select
|
||||
class="pa-0 ma-0"
|
||||
color="green_accent"
|
||||
:items="paginationSizes"
|
||||
v-model="paginationSize"
|
||||
></v-select>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row dense>
|
||||
<v-col cols="10" sm="10" md="11">
|
||||
<p class="subtitle-1">Current Version:</p>
|
||||
</v-col>
|
||||
<v-col cols="2" sm="2" md="1">
|
||||
<p class="mb-2">{{ version }}</p>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-form>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapGetters } from 'vuex'
|
||||
export default {
|
||||
name: 'General',
|
||||
data() {
|
||||
return {
|
||||
paginationSizes: [5, 15, 30, 50]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(['webuiSettings']),
|
||||
...mapGetters(['getAppVersion']),
|
||||
freeSpace: {
|
||||
get() {
|
||||
return this.webuiSettings.showFreeSpace
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showFreeSpace = val
|
||||
}
|
||||
},
|
||||
showCurrentSpeed: {
|
||||
get() {
|
||||
return this.webuiSettings.showCurrentSpeed
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showCurrentSpeed = val
|
||||
}
|
||||
},
|
||||
showSpeedGraph: {
|
||||
get() {
|
||||
return this.webuiSettings.showSpeedGraph
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showSpeedGraph = val
|
||||
}
|
||||
},
|
||||
showSessionStat: {
|
||||
get() {
|
||||
return this.webuiSettings.showSessionStat
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showSessionStat = val
|
||||
}
|
||||
},
|
||||
showGlobalRemoveResumePause: {
|
||||
get() {
|
||||
return this.webuiSettings.showGlobalRemoveResumePause
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.showGlobalRemoveResumePause = val
|
||||
}
|
||||
},
|
||||
denseDashboard: {
|
||||
get() {
|
||||
return this.webuiSettings.denseDashboard
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.denseDashboard = val
|
||||
}
|
||||
},
|
||||
paginationSize: {
|
||||
get() {
|
||||
return this.webuiSettings.paginationSize
|
||||
},
|
||||
set(val) {
|
||||
this.webuiSettings.paginationSize = val
|
||||
}
|
||||
},
|
||||
version() {
|
||||
return this.getAppVersion()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/assets/styles/SettingsTab.scss';
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// Reversed input variant
|
||||
::v-deep .v-input--reverse .v-input__slot {
|
||||
flex-direction: row-reverse;
|
||||
justify-content: flex-end;
|
||||
.v-application--is-ltr & {
|
||||
.v-input--selection-controls__input {
|
||||
margin-right: 0;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
.v-application--is-rtl & {
|
||||
.v-input--selection-controls__input {
|
||||
margin-left: 0;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,7 +1,9 @@
|
|||
<template>
|
||||
<v-container>
|
||||
<div class="ma-3 pa-2">
|
||||
<v-card flat>
|
||||
<v-card-text class="pa-0" style="font-size: 1.1em">
|
||||
<v-card-text class="pa-0" style="font-size: 1.1em"
|
||||
:style="{ minHeight: phoneLayout ? '' : '75vh'}"
|
||||
>
|
||||
<div class="box">
|
||||
<v-subheader>Use Alternative WebUI</v-subheader>
|
||||
<div class="ml-5 mr-5">
|
||||
|
@ -49,15 +51,15 @@
|
|||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SettingsTab from '@/mixins/SettingsTab'
|
||||
import {FullScreenModal, SettingsTab} from '@/mixins'
|
||||
|
||||
export default {
|
||||
name: 'WebUI',
|
||||
mixins: [SettingsTab]
|
||||
mixins: [SettingsTab, FullScreenModal]
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,77 +1,77 @@
|
|||
<template>
|
||||
<v-card flat>
|
||||
<perfect-scrollbar>
|
||||
<v-card-text style="max-height: 500px; min-height: 400px">
|
||||
<v-treeview
|
||||
v-model="selected"
|
||||
:items="fileTree"
|
||||
:open.sync="opened"
|
||||
activatable
|
||||
selectable
|
||||
item-key="fullName"
|
||||
open-all
|
||||
>
|
||||
<template v-slot:prepend="{ item, open }">
|
||||
<v-icon v-if="!item.icon">
|
||||
{{ open ? 'mdi-folder-open' : 'mdi-folder' }}
|
||||
</v-icon>
|
||||
<v-icon v-else>{{ item.icon }}</v-icon>
|
||||
</template>
|
||||
<template v-slot:label="{ item }">
|
||||
<span v-if="!item.editing">{{item.name}}</span>
|
||||
<v-text-field
|
||||
autofocus
|
||||
v-if="item.editing"
|
||||
v-model="item.newName"
|
||||
/>
|
||||
</template>
|
||||
<template v-slot:append="{ item }">
|
||||
<span v-if="!item.icon"
|
||||
>{{ item.children.length }} Files</span
|
||||
>
|
||||
<div v-else>
|
||||
<span>[{{ item.size }}]</span>
|
||||
<span class="ml-4">{{ item.progress }}%</span>
|
||||
<v-btn
|
||||
v-if="!item.editing"
|
||||
class="mb-2 ml-4"
|
||||
x-small
|
||||
fab
|
||||
@click="edit(item)"
|
||||
>
|
||||
<v-icon>mdi-pencil</v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-if="item.editing"
|
||||
class="mb-2 ml-4"
|
||||
x-small
|
||||
fab
|
||||
@click="renameFile(item)"
|
||||
>
|
||||
<v-icon>save</v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-if="item.editing"
|
||||
class="mb-2 ml-2"
|
||||
x-small
|
||||
fab
|
||||
@click="togleEditing(item)"
|
||||
>
|
||||
<v-icon>close</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
</v-treeview>
|
||||
</v-card-text>
|
||||
</perfect-scrollbar>
|
||||
</v-card>
|
||||
<v-card flat>
|
||||
<perfect-scrollbar>
|
||||
<v-card-text :style="{ minHeight: phoneLayout ? '' : '75vh'}">
|
||||
<v-treeview
|
||||
v-model="selected"
|
||||
:items="fileTree"
|
||||
:open.sync="opened"
|
||||
activatable
|
||||
selectable
|
||||
item-key="fullName"
|
||||
open-all
|
||||
>
|
||||
<template v-slot:prepend="{ item, open }">
|
||||
<v-icon v-if="!item.icon">
|
||||
{{ open ? "mdi-folder-open" : "mdi-folder" }}
|
||||
</v-icon>
|
||||
<v-icon v-else>{{ item.icon }}</v-icon>
|
||||
</template>
|
||||
<template v-slot:label="{ item }">
|
||||
<span v-if="!item.editing">{{ item.name }}</span>
|
||||
<v-text-field
|
||||
autofocus
|
||||
v-if="item.editing"
|
||||
v-model="item.newName"
|
||||
/>
|
||||
</template>
|
||||
<template v-slot:append="{ item }">
|
||||
<span v-if="!item.icon">{{ item.children.length }} Files</span>
|
||||
<div v-else>
|
||||
<span>[{{ item.size }}]</span>
|
||||
<span class="ml-4">{{ item.progress }}%</span>
|
||||
<v-btn
|
||||
v-if="!item.editing"
|
||||
class="mb-2 ml-4"
|
||||
x-small
|
||||
fab
|
||||
@click="edit(item)"
|
||||
>
|
||||
<v-icon>mdi-pencil</v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-if="item.editing"
|
||||
class="mb-2 ml-4"
|
||||
x-small
|
||||
fab
|
||||
@click="renameFile(item)"
|
||||
>
|
||||
<v-icon>save</v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-if="item.editing"
|
||||
class="mb-2 ml-2"
|
||||
x-small
|
||||
fab
|
||||
@click="togleEditing(item)"
|
||||
>
|
||||
<v-icon>close</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
</template>
|
||||
</v-treeview>
|
||||
</v-card-text>
|
||||
</perfect-scrollbar>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import qbit from '@/services/qbit'
|
||||
import { treeify } from '@/helpers'
|
||||
import { FullScreenModal } from '@/mixins'
|
||||
export default {
|
||||
name: 'Content',
|
||||
mixins: [FullScreenModal],
|
||||
props: {
|
||||
hash: String,
|
||||
isActive: Boolean
|
||||
|
@ -102,16 +102,18 @@ export default {
|
|||
},
|
||||
async changeFilePriorities(newValue, oldValue) {
|
||||
if (newValue.length == oldValue.length) return
|
||||
|
||||
const filesToExclude = oldValue.filter(f => !newValue.includes(f))
|
||||
|
||||
const filesToExclude = oldValue
|
||||
.filter(f => !newValue.includes(f))
|
||||
.map(name => this.treeData.find(f => f.name === name))
|
||||
.filter(f => f.priority !== 0)
|
||||
.map(f => f.id)
|
||||
const filesToInclude = newValue.filter(f => !oldValue.includes(f))
|
||||
const filesToInclude = newValue
|
||||
.filter(f => !oldValue.includes(f))
|
||||
.map(name => this.treeData.find(f => f.name === name))
|
||||
.filter(f => f.priority === 0)
|
||||
.map(f => f.id)
|
||||
|
||||
|
||||
if (filesToExclude.length)
|
||||
await qbit.setTorrentFilePriority(this.hash, filesToExclude, 0)
|
||||
if (filesToInclude.length)
|
||||
|
@ -122,7 +124,7 @@ export default {
|
|||
togleEditing(item) {
|
||||
item.editing = !item.editing
|
||||
},
|
||||
edit(item){
|
||||
edit(item) {
|
||||
item.newName = item.name
|
||||
this.togleEditing(item)
|
||||
},
|
||||
|
@ -143,13 +145,16 @@ export default {
|
|||
}
|
||||
},
|
||||
created() {
|
||||
this.getTorrentFiles().then(() => {
|
||||
this.opened = [].concat(
|
||||
...this.treeData.map(file => file.name.split('/'))
|
||||
.filter(f => f.splice(-1, 1)))
|
||||
.filter((f, index, self) => index === self.indexOf(f)
|
||||
)
|
||||
this.selected = this.treeData.filter(file => file.priority !== 0)
|
||||
this.getTorrentFiles().then(() => {
|
||||
this.opened = []
|
||||
.concat(
|
||||
...this.treeData
|
||||
.map(file => file.name.split('/'))
|
||||
.filter(f => f.splice(-1, 1))
|
||||
)
|
||||
.filter((f, index, self) => index === self.indexOf(f))
|
||||
this.selected = this.treeData
|
||||
.filter(file => file.priority !== 0)
|
||||
.map(file => file.name)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,115 +1,113 @@
|
|||
<template>
|
||||
<v-card flat>
|
||||
<perfect-scrollbar>
|
||||
<v-card-text
|
||||
style="font-size: 1.1em; min-height: 400px;"
|
||||
:style="{ maxHeight: phoneLayout ? '' : '500px' }"
|
||||
>
|
||||
<v-simple-table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="grey--text">Torrent title</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.name }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Directory</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.savePath }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="margin-top: 10px !important">
|
||||
<td class="grey--text">hash</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.hash }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Size</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.size }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Done:</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.dloaded }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Uploaded:</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.uploaded }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Ratio</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.ratio }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Download Speed</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.dlspeed }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Upload Speed</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.upspeed }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">ETA</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.eta }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Peers</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.num_leechs
|
||||
}}<span class="grey--text"
|
||||
>/{{ torrent.available_peers }}</span
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Seeds</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.num_seeds
|
||||
}}<span class="grey--text"
|
||||
>/{{ torrent.available_seeds }}</span
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Added on</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.added_on }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Status</td>
|
||||
<v-chip
|
||||
small
|
||||
:class="`${torrent.state.toLowerCase()} white--text my-2 caption`"
|
||||
>{{ torrent.state }}</v-chip
|
||||
>
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-simple-table>
|
||||
</v-card-text>
|
||||
</perfect-scrollbar>
|
||||
</v-card>
|
||||
<v-card flat>
|
||||
<perfect-scrollbar>
|
||||
<v-card-text
|
||||
style="font-size: 1.1em"
|
||||
:style="{ minHeight: phoneLayout ? '' : '75vh'}"
|
||||
>
|
||||
<v-simple-table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="grey--text">Torrent title</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.name }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Directory</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.savePath }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="margin-top: 10px !important">
|
||||
<td class="grey--text">hash</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.hash }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Size</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.size }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Done:</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.dloaded }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Uploaded:</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.uploaded }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Ratio</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.ratio }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Download Speed</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.dlspeed }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Upload Speed</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.upspeed }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">ETA</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.eta }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Peers</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.num_leechs
|
||||
}}<span class="grey--text">/{{ torrent.available_peers }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Seeds</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.num_seeds
|
||||
}}<span class="grey--text">/{{ torrent.available_seeds }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Added on</td>
|
||||
<td class="torrentmodaltext--text">
|
||||
{{ torrent.added_on }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="grey--text">Status</td>
|
||||
<v-chip
|
||||
small
|
||||
:class="`${torrent.state.toLowerCase()} white--text my-2 caption`"
|
||||
>{{ torrent.state }}</v-chip
|
||||
>
|
||||
</tr>
|
||||
</tbody>
|
||||
</v-simple-table>
|
||||
</v-card-text>
|
||||
</perfect-scrollbar>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import { FullScreenModal } from '@/mixins'
|
||||
export default {
|
||||
name: 'Info',
|
||||
mixins: [FullScreenModal],
|
||||
props: {
|
||||
hash: String
|
||||
},
|
||||
|
@ -117,9 +115,6 @@ export default {
|
|||
...mapGetters(['getTorrent']),
|
||||
torrent() {
|
||||
return this.getTorrent(this.hash)
|
||||
},
|
||||
phoneLayout() {
|
||||
return this.$vuetify.breakpoint.xsOnly
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -128,16 +123,16 @@ export default {
|
|||
<style lang="scss" scoped>
|
||||
::v-deep .v-data-table thead th,
|
||||
::v-deep .v-data-table tbody td {
|
||||
padding: 0 !important;
|
||||
height: 3em;
|
||||
padding: 0 !important;
|
||||
height: 3em;
|
||||
|
||||
white-space: nowrap;
|
||||
white-space: nowrap;
|
||||
|
||||
&:first-child {
|
||||
padding: 0 0 0 8px !important;
|
||||
}
|
||||
&:last-child {
|
||||
padding-right: 8px !important;
|
||||
}
|
||||
&:first-child {
|
||||
padding: 0 0 0 8px !important;
|
||||
}
|
||||
&:last-child {
|
||||
padding-right: 8px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,54 +1,55 @@
|
|||
<template>
|
||||
<perfect-scrollbar>
|
||||
<v-data-table
|
||||
v-if="peers"
|
||||
:headers="headers"
|
||||
:items="peers"
|
||||
:items-per-page="-1"
|
||||
:hide-default-footer="true"
|
||||
style="max-height: 500px; min-height: 400px"
|
||||
>
|
||||
<template v-slot:item="row">
|
||||
<tr>
|
||||
<td class="ip">
|
||||
<template v-if="row.item.country_code">
|
||||
<img
|
||||
v-if="isWindows"
|
||||
class="country-flag"
|
||||
:title="row.item.country"
|
||||
:alt="codeToFlag(row.item.country_code).char"
|
||||
:src="codeToFlag(row.item.country_code).url"
|
||||
/>
|
||||
<template v-else>{{
|
||||
codeToFlag(row.item.country_code).char
|
||||
}}</template>
|
||||
</template>
|
||||
{{ row.item.ip }}
|
||||
<span class="grey--text">:{{ row.item.port }}</span>
|
||||
</td>
|
||||
<td>{{ row.item.connection }}</td>
|
||||
<td :title="row.item.flags_desc">{{ row.item.flags }}</td>
|
||||
<td>{{ row.item.client }}</td>
|
||||
<td>{{ row.item.progress | progress }}</td>
|
||||
<td>{{ row.item.dl_speed | networkSpeed }}</td>
|
||||
<td>{{ row.item.downloaded | networkSize }}</td>
|
||||
<td>{{ row.item.up_speed | networkSpeed }}</td>
|
||||
<td>{{ row.item.uploaded | networkSize }}</td>
|
||||
<td>{{ row.item.relevance | progress }}</td>
|
||||
<td>{{ row.item.files }}</td>
|
||||
</tr>
|
||||
<perfect-scrollbar>
|
||||
<v-data-table
|
||||
v-if="peers"
|
||||
:headers="headers"
|
||||
:items="peers"
|
||||
:items-per-page="-1"
|
||||
:hide-default-footer="true"
|
||||
:style="{ minHeight: phoneLayout ? '' : '75vh'}"
|
||||
>
|
||||
<template v-slot:item="row">
|
||||
<tr>
|
||||
<td class="ip">
|
||||
<template v-if="row.item.country_code">
|
||||
<img
|
||||
v-if="isWindows"
|
||||
class="country-flag"
|
||||
:title="row.item.country"
|
||||
:alt="codeToFlag(row.item.country_code).char"
|
||||
:src="codeToFlag(row.item.country_code).url"
|
||||
/>
|
||||
<template v-else>{{
|
||||
codeToFlag(row.item.country_code).char
|
||||
}}</template>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</perfect-scrollbar>
|
||||
{{ row.item.ip }}
|
||||
<span class="grey--text">:{{ row.item.port }}</span>
|
||||
</td>
|
||||
<td>{{ row.item.connection }}</td>
|
||||
<td :title="row.item.flags_desc">{{ row.item.flags }}</td>
|
||||
<td>{{ row.item.client }}</td>
|
||||
<td>{{ row.item.progress | progress }}</td>
|
||||
<td>{{ row.item.dl_speed | networkSpeed }}</td>
|
||||
<td>{{ row.item.downloaded | networkSize }}</td>
|
||||
<td>{{ row.item.up_speed | networkSpeed }}</td>
|
||||
<td>{{ row.item.uploaded | networkSize }}</td>
|
||||
<td>{{ row.item.relevance | progress }}</td>
|
||||
<td>{{ row.item.files }}</td>
|
||||
</tr>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</perfect-scrollbar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { map, merge } from 'lodash'
|
||||
import qbit from '@/services/qbit'
|
||||
import { codeToFlag, isWindows } from '@/helpers'
|
||||
|
||||
import { FullScreenModal } from '@/mixins'
|
||||
export default {
|
||||
name: 'Peers',
|
||||
mixins: [FullScreenModal],
|
||||
props: { hash: String, isActive: Boolean },
|
||||
data: () => ({
|
||||
headers: [
|
||||
|
@ -112,30 +113,30 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
::v-deep .ip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
::v-deep .ip .country-flag {
|
||||
width: 1.5em;
|
||||
margin-right: 0.5em;
|
||||
width: 1.5em;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/styles.scss';
|
||||
@import "~@/assets/styles.scss";
|
||||
|
||||
::v-deep .v-data-table thead th,
|
||||
::v-deep .v-data-table tbody td {
|
||||
padding: 0 2px !important;
|
||||
height: auto;
|
||||
padding: 0 2px !important;
|
||||
height: auto;
|
||||
|
||||
white-space: nowrap;
|
||||
white-space: nowrap;
|
||||
|
||||
&:first-child {
|
||||
padding: 0 0 0 8px !important;
|
||||
}
|
||||
&:last-child {
|
||||
padding-right: 8px !important;
|
||||
}
|
||||
&:first-child {
|
||||
padding: 0 0 0 8px !important;
|
||||
}
|
||||
&:last-child {
|
||||
padding-right: 8px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,111 +1,110 @@
|
|||
<template>
|
||||
<v-card flat>
|
||||
<v-card-text
|
||||
class="mx-auto mt-5"
|
||||
style="font-size: 1.1em; max-height: 500px; min-height: 300px"
|
||||
>
|
||||
<v-row>
|
||||
<v-col :cols="12" :lg="6" :md="6" :sm="12">
|
||||
<v-layout class="mx-auto" row wrap>
|
||||
<v-flex xs12 sm12>
|
||||
<h3>Available Tags:</h3>
|
||||
</v-flex>
|
||||
<v-flex class="mt-3 d-flex flex-wrap justify-center" xs12 sm12>
|
||||
<v-chip
|
||||
v-for="tag in availableTags"
|
||||
:key="tag"
|
||||
small
|
||||
class="download white--text caption mx-2 my-1"
|
||||
style="font-size: 0.95em !important"
|
||||
@click="addTag(tag)"
|
||||
>
|
||||
{{ tag }}
|
||||
</v-chip>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout class="mx-auto mt-12" row wrap>
|
||||
<v-flex xs12 sm12>
|
||||
<h3>Current Tags:</h3>
|
||||
</v-flex>
|
||||
<v-flex class="mt-3 d-flex flex-wrap justify-center" xs12 sm12>
|
||||
<div v-if="torrent.tags">
|
||||
<v-chip
|
||||
v-for="tag in torrent.tags"
|
||||
:key="tag"
|
||||
small
|
||||
close
|
||||
class="download white--text caption mx-2 my-1"
|
||||
style="font-size: 0.95em !important"
|
||||
@click="deleteTag(tag)"
|
||||
@click:close="deleteTag(tag)"
|
||||
>{{ tag }}</v-chip
|
||||
>
|
||||
</div>
|
||||
<div v-else>None</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-col>
|
||||
<v-col :cols="12" :lg="6" :md="6" :sm="12">
|
||||
<v-layout
|
||||
class="mx-auto"
|
||||
:class="
|
||||
this.$vuetify.breakpoint.smAndDown ? 'mt-12' : ''
|
||||
"
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex xs12 sm12>
|
||||
<h3>Available Categories:</h3>
|
||||
</v-flex>
|
||||
<v-flex class="mt-3 d-flex flex-wrap justify-center" xs12 sm12>
|
||||
<v-chip
|
||||
v-for="cat in availableCategories"
|
||||
:key="cat.name"
|
||||
small
|
||||
class="upload white--text caption mx-2 my-1"
|
||||
style="font-size: 0.95em !important"
|
||||
@click="setCategory(cat.name)"
|
||||
>
|
||||
{{ cat.name }}
|
||||
</v-chip>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout class="mx-auto mt-12" row wrap>
|
||||
<v-flex xs12 sm12>
|
||||
<h3>Current Category:</h3>
|
||||
</v-flex>
|
||||
<v-flex class="mt-3 d-flex justify-center" xs12 sm12>
|
||||
<v-chip
|
||||
v-if="torrent.category"
|
||||
small
|
||||
close
|
||||
class="upload white--text caption mx-2"
|
||||
style="font-size: 0.95em !important"
|
||||
@click="deleteCategory"
|
||||
@click:close="deleteCategory"
|
||||
>{{ torrent.category }}</v-chip
|
||||
>
|
||||
<div v-else>None</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
<v-card flat>
|
||||
<v-card-text
|
||||
class="mx-auto mt-4"
|
||||
style="font-size: 1.1em"
|
||||
:style="{ minHeight: phoneLayout ? '' : '75vh'}"
|
||||
>
|
||||
<v-row>
|
||||
<v-col :cols="12" :lg="6" :md="6" :sm="12">
|
||||
<v-layout class="mx-auto" row wrap>
|
||||
<v-flex xs12 sm12>
|
||||
<h3>Available Tags:</h3>
|
||||
</v-flex>
|
||||
<v-flex class="mt-3 d-flex flex-wrap justify-center" xs12 sm12>
|
||||
<v-chip
|
||||
v-for="tag in availableTags"
|
||||
:key="tag"
|
||||
small
|
||||
class="download white--text caption mx-2 my-1"
|
||||
style="font-size: 0.95em !important"
|
||||
@click="addTag(tag)"
|
||||
>
|
||||
{{ tag }}
|
||||
</v-chip>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout class="mx-auto mt-12" row wrap>
|
||||
<v-flex xs12 sm12>
|
||||
<h3>Current Tags:</h3>
|
||||
</v-flex>
|
||||
<v-flex class="mt-3 d-flex flex-wrap justify-center" xs12 sm12>
|
||||
<div v-if="torrent.tags">
|
||||
<v-chip
|
||||
v-for="tag in torrent.tags"
|
||||
:key="tag"
|
||||
small
|
||||
close
|
||||
class="download white--text caption mx-2 my-1"
|
||||
style="font-size: 0.95em !important"
|
||||
@click="deleteTag(tag)"
|
||||
@click:close="deleteTag(tag)"
|
||||
>{{ tag }}</v-chip
|
||||
>
|
||||
</div>
|
||||
<div v-else>None</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-col>
|
||||
<v-col :cols="12" :lg="6" :md="6" :sm="12">
|
||||
<v-layout
|
||||
class="mx-auto"
|
||||
:class="this.$vuetify.breakpoint.smAndDown ? 'mt-12' : ''"
|
||||
row
|
||||
wrap
|
||||
>
|
||||
<v-flex xs12 sm12>
|
||||
<h3>Available Categories:</h3>
|
||||
</v-flex>
|
||||
<v-flex class="mt-3 d-flex flex-wrap justify-center" xs12 sm12>
|
||||
<v-chip
|
||||
v-for="cat in availableCategories"
|
||||
:key="cat.name"
|
||||
small
|
||||
class="upload white--text caption mx-2 my-1"
|
||||
style="font-size: 0.95em !important"
|
||||
@click="setCategory(cat.name)"
|
||||
>
|
||||
{{ cat.name }}
|
||||
</v-chip>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-layout class="mx-auto mt-12" row wrap>
|
||||
<v-flex xs12 sm12>
|
||||
<h3>Current Category:</h3>
|
||||
</v-flex>
|
||||
<v-flex class="mt-3 d-flex justify-center" xs12 sm12>
|
||||
<v-chip
|
||||
v-if="torrent.category"
|
||||
small
|
||||
close
|
||||
class="upload white--text caption mx-2"
|
||||
style="font-size: 0.95em !important"
|
||||
@click="deleteCategory"
|
||||
@click:close="deleteCategory"
|
||||
>{{ torrent.category }}</v-chip
|
||||
>
|
||||
<div v-else>None</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { difference } from 'lodash'
|
||||
import { mapGetters } from 'vuex'
|
||||
import qbit from '@/services/qbit'
|
||||
import { Tab } from '@/mixins'
|
||||
import { FullScreenModal } from '@/mixins'
|
||||
|
||||
export default {
|
||||
name: 'TorrentTagsAndCategories',
|
||||
props: {
|
||||
hash: String
|
||||
},
|
||||
mixins: [Tab],
|
||||
mixins: [FullScreenModal],
|
||||
data: () => ({
|
||||
categories: []
|
||||
}),
|
||||
|
@ -145,6 +144,6 @@ export default {
|
|||
|
||||
<style scoped>
|
||||
h3 {
|
||||
text-align: center;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,32 +1,34 @@
|
|||
<template>
|
||||
<perfect-scrollbar>
|
||||
<v-data-table
|
||||
v-if="trackers"
|
||||
:headers="headers"
|
||||
:items="trackers"
|
||||
:hide-default-footer="true"
|
||||
style="max-height: 500px; min-height: 400px"
|
||||
>
|
||||
<template v-slot:item="row">
|
||||
<tr>
|
||||
<td>{{ row.item.tier }}</td>
|
||||
<td>{{ row.item.url }}</td>
|
||||
<td>{{ row.item.status | formatTrackerStatus }}</td>
|
||||
<td>{{ row.item.num_peers | formatTrackerNum }}</td>
|
||||
<td>{{ row.item.num_seeds | formatTrackerNum }}</td>
|
||||
<td>{{ row.item.num_leeches | formatTrackerNum }}</td>
|
||||
<td>{{ row.item.num_downloaded | formatTrackerNum }}</td>
|
||||
<td>{{ row.item.msg }}</td>
|
||||
</tr>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</perfect-scrollbar>
|
||||
<perfect-scrollbar>
|
||||
<v-data-table
|
||||
v-if="trackers"
|
||||
:headers="headers"
|
||||
:items="trackers"
|
||||
:hide-default-footer="true"
|
||||
:style="{ minHeight: phoneLayout ? '' : '75vh'}"
|
||||
>
|
||||
<template v-slot:item="row">
|
||||
<tr>
|
||||
<td>{{ row.item.tier }}</td>
|
||||
<td>{{ row.item.url }}</td>
|
||||
<td>{{ row.item.status | formatTrackerStatus }}</td>
|
||||
<td>{{ row.item.num_peers | formatTrackerNum }}</td>
|
||||
<td>{{ row.item.num_seeds | formatTrackerNum }}</td>
|
||||
<td>{{ row.item.num_leeches | formatTrackerNum }}</td>
|
||||
<td>{{ row.item.num_downloaded | formatTrackerNum }}</td>
|
||||
<td>{{ row.item.msg }}</td>
|
||||
</tr>
|
||||
</template>
|
||||
</v-data-table>
|
||||
</perfect-scrollbar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import qbit from '@/services/qbit'
|
||||
import { FullScreenModal } from '@/mixins'
|
||||
export default {
|
||||
name: 'Trackers',
|
||||
mixins: [FullScreenModal],
|
||||
props: { hash: String, isActive: Boolean },
|
||||
data: () => ({
|
||||
headers: [
|
||||
|
@ -86,20 +88,20 @@ export default {
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/styles.scss';
|
||||
@import "~@/assets/styles.scss";
|
||||
|
||||
::v-deep .v-data-table thead th,
|
||||
::v-deep .v-data-table tbody td {
|
||||
padding: 0 2px !important;
|
||||
height: auto;
|
||||
padding: 0 2px !important;
|
||||
height: auto;
|
||||
|
||||
white-space: nowrap;
|
||||
white-space: nowrap;
|
||||
|
||||
&:first-child {
|
||||
padding: 0 0 0 8px !important;
|
||||
}
|
||||
&:last-child {
|
||||
padding-right: 8px !important;
|
||||
}
|
||||
&:first-child {
|
||||
padding: 0 0 0 8px !important;
|
||||
}
|
||||
&:last-child {
|
||||
padding-right: 8px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<nav>
|
||||
<!--title-->
|
||||
<v-app-bar app flat color="background">
|
||||
<v-app-bar app flat color="background" @click="resetSelected">
|
||||
<v-app-bar-nav-icon
|
||||
@click.stop="drawer = !drawer"
|
||||
class="grey--text text--lighten-1"
|
||||
|
@ -95,7 +95,11 @@ export default {
|
|||
drawer: this.$vuetify.breakpoint.mdAndUp
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
resetSelected() {
|
||||
this.$store.commit('RESET_SELECTED')
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$vuetify.theme.dark = this.getTheme()
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<template>
|
||||
<div>
|
||||
<v-btn :ripple="false" id="no-background-hover" text>
|
||||
<v-checkbox class="grey--text" v-model="$store.state.selectMode" color="grey" hide-details style="width: 5px;"/>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
text
|
||||
small
|
||||
|
@ -102,3 +105,12 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
#no-background-hover::before {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
#no-background-hover {
|
||||
cursor: default !important;
|
||||
}
|
||||
</style>
|
|
@ -10,6 +10,7 @@
|
|||
showInfo(torrent.hash)"
|
||||
@dblclick.prevent="showInfo(torrent.hash)"
|
||||
@click.ctrl.exact.prevent="selectTorrent(torrent.hash)"
|
||||
@click.shift.exact.prevent="selectUntil(torrent.hash, index)"
|
||||
>
|
||||
<v-tooltip top>
|
||||
<template v-slot:activator="{ on }">
|
||||
|
@ -18,111 +19,7 @@
|
|||
<div class="caption grey--text">Torrent title</div>
|
||||
<div class="truncate">{{ torrent.name }}</div>
|
||||
</v-flex>
|
||||
<v-flex xs6 sm1 md1 class="mr-2">
|
||||
<div class="caption grey--text">Size</div>
|
||||
<div>
|
||||
{{ torrent.size | getDataValue }}
|
||||
<span class="caption grey--text">{{
|
||||
torrent.size | getDataUnit
|
||||
}}</span>
|
||||
</div>
|
||||
</v-flex>
|
||||
<v-flex xs12 sm1 md1 class="mr-4">
|
||||
<div class="caption grey--text">Done</div>
|
||||
<v-progress-linear
|
||||
v-model="torrent.progress"
|
||||
height="20"
|
||||
:style="phoneLayout ? '' : 'width: 80%;'"
|
||||
:color="`torrent-${state}-color`" >
|
||||
<span
|
||||
class="caption"
|
||||
>
|
||||
{{ torrent.progress }}%
|
||||
</span>
|
||||
</v-progress-linear>
|
||||
</v-flex>
|
||||
<v-flex xs6 sm1 md1 class="mr-2" v-if="torrent.progress !== 100" >
|
||||
<div class="caption grey--text">Download</div>
|
||||
<div>
|
||||
{{ torrent.dlspeed | getDataValue }}
|
||||
<span class="caption grey--text">{{
|
||||
torrent.dlspeed | getDataUnit
|
||||
}}</span>
|
||||
</div>
|
||||
</v-flex>
|
||||
<v-flex xs6 sm1 md1 class="mr-2" v-else >
|
||||
<div class="caption grey--text">Ratio</div>
|
||||
<div>{{ torrent.ratio }}</div>
|
||||
</v-flex>
|
||||
<v-flex xs5 sm1 md1 class="mr-2">
|
||||
<div class="caption grey--text">Upload</div>
|
||||
<div>
|
||||
{{ torrent.upspeed | getDataValue }}
|
||||
<span class="caption grey--text">{{
|
||||
torrent.upspeed | getDataUnit
|
||||
}}</span>
|
||||
</div>
|
||||
</v-flex>
|
||||
<v-flex xs6 sm1 md1 class="mr-2">
|
||||
<div class="caption grey--text">ETA</div>
|
||||
<div>
|
||||
{{ torrent.eta }}
|
||||
</div>
|
||||
</v-flex>
|
||||
<v-flex xs5 sm1 md1 class="mr-2">
|
||||
<div class="caption grey--text">Peers</div>
|
||||
<div>
|
||||
{{ torrent.num_leechs }}
|
||||
<span class="grey--text caption"
|
||||
>/{{ torrent.available_peers }}</span
|
||||
>
|
||||
</div>
|
||||
</v-flex>
|
||||
<v-flex xs6 sm1 md1 class="mr-2">
|
||||
<div class="caption grey--text">Seeds</div>
|
||||
<div>
|
||||
{{ torrent.num_seeds }}
|
||||
<span class="grey--text caption"
|
||||
>/{{ torrent.available_seeds }}</span
|
||||
>
|
||||
</div>
|
||||
</v-flex>
|
||||
<v-flex xs5 sm1>
|
||||
<div class="caption grey--text">Status</div>
|
||||
<v-chip
|
||||
small
|
||||
class="caption"
|
||||
:class="
|
||||
theme === 'light'
|
||||
? `${state} white--text `
|
||||
: `${state} black--text`">
|
||||
{{ torrent.state }}
|
||||
</v-chip>
|
||||
</v-flex>
|
||||
<!-- Category -->
|
||||
<v-flex v-if="torrent.category" class="mr-2" xs6 sm1 md1>
|
||||
<div class="caption grey--text">Category</div>
|
||||
<v-chip small class="upload white--text caption">
|
||||
{{ torrent.category }}
|
||||
</v-chip>
|
||||
</v-flex>
|
||||
<!-- Tags -->
|
||||
<v-flex xs5 sm2 v-if="torrent.tags && torrent.tags.length">
|
||||
<div class="caption grey--text">Tags</div>
|
||||
<v-row wrap class="ma-0">
|
||||
<v-chip v-for="tag in torrent.tags" :key="tag"
|
||||
small
|
||||
:class="
|
||||
theme === 'light'
|
||||
? 'white--text'
|
||||
: 'black--text'
|
||||
"
|
||||
class="download caption mb-1 mx-1"
|
||||
>
|
||||
{{ tag }}
|
||||
</v-chip>
|
||||
</v-row>
|
||||
</v-flex>
|
||||
<component :key="'busy' + item.name" v-for="item in properties" :is="item.name" :torrent="torrent" />
|
||||
</v-layout>
|
||||
</template>
|
||||
<span>{{ torrent.name }}</span>
|
||||
|
@ -134,10 +31,35 @@
|
|||
<script>
|
||||
import { General, TorrentSelect } from '@/mixins'
|
||||
import {mapGetters} from 'vuex'
|
||||
|
||||
import {
|
||||
Size,
|
||||
Progress,
|
||||
Download,
|
||||
Ratio,
|
||||
Upload,
|
||||
ETA,
|
||||
Peers,
|
||||
Seeds,
|
||||
Status,
|
||||
Category,
|
||||
Tags
|
||||
} from './Torrent/DashboardItems'
|
||||
|
||||
export default {
|
||||
name: 'Torrent',
|
||||
components: {
|
||||
Size,
|
||||
Progress,
|
||||
Download,
|
||||
Ratio,
|
||||
Upload,
|
||||
ETA,
|
||||
Peers,
|
||||
Seeds,
|
||||
Status,
|
||||
Category,
|
||||
Tags
|
||||
},
|
||||
mixins: [General, TorrentSelect],
|
||||
props: {
|
||||
torrent: Object,
|
||||
|
@ -163,6 +85,12 @@ export default {
|
|||
},
|
||||
denseDashboard(){
|
||||
return this.getWebuiSettings().denseDashboard
|
||||
},
|
||||
properties(){
|
||||
if(this.torrent.progress === 100){
|
||||
return this.getWebuiSettings().doneTorrentProperties.filter(i => i.active)
|
||||
}
|
||||
return this.getWebuiSettings().busyTorrentProperties.filter(i => i.active)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
14
src/components/Torrent/DashboardItems/Category.vue
Normal file
14
src/components/Torrent/DashboardItems/Category.vue
Normal file
|
@ -0,0 +1,14 @@
|
|||
<template>
|
||||
<v-flex v-if="torrent.category" class="mr-2" xs6 sm1 md1>
|
||||
<div class="caption grey--text">Category</div>
|
||||
<v-chip small class="upload white--text caption">
|
||||
{{ torrent.category }}
|
||||
</v-chip>
|
||||
</v-flex>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'Category',
|
||||
props: ['torrent']
|
||||
}
|
||||
</script>
|
17
src/components/Torrent/DashboardItems/Download.vue
Normal file
17
src/components/Torrent/DashboardItems/Download.vue
Normal file
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<v-flex xs6 sm1 md1 class="mr-2" >
|
||||
<div class="caption grey--text">Download</div>
|
||||
<div>
|
||||
{{ torrent.dlspeed | getDataValue }}
|
||||
<span class="caption grey--text">{{
|
||||
torrent.dlspeed | getDataUnit
|
||||
}}</span>
|
||||
</div>
|
||||
</v-flex>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'Download',
|
||||
props: ['torrent']
|
||||
}
|
||||
</script>
|
14
src/components/Torrent/DashboardItems/ETA.vue
Normal file
14
src/components/Torrent/DashboardItems/ETA.vue
Normal file
|
@ -0,0 +1,14 @@
|
|||
<template>
|
||||
<v-flex xs6 sm1 md1 class="mr-2">
|
||||
<div class="caption grey--text">ETA</div>
|
||||
<div>
|
||||
{{ torrent.eta }}
|
||||
</div>
|
||||
</v-flex>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'ETA',
|
||||
props: ['torrent']
|
||||
}
|
||||
</script>
|
17
src/components/Torrent/DashboardItems/Peers.vue
Normal file
17
src/components/Torrent/DashboardItems/Peers.vue
Normal file
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<v-flex xs5 sm1 md1 class="mr-2">
|
||||
<div class="caption grey--text">Peers</div>
|
||||
<div>
|
||||
{{ torrent.num_leechs }}
|
||||
<span class="grey--text caption"
|
||||
>/{{ torrent.available_peers }}</span
|
||||
>
|
||||
</div>
|
||||
</v-flex>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'Peers',
|
||||
props: ['torrent']
|
||||
}
|
||||
</script>
|
24
src/components/Torrent/DashboardItems/Progress.vue
Normal file
24
src/components/Torrent/DashboardItems/Progress.vue
Normal file
|
@ -0,0 +1,24 @@
|
|||
<template>
|
||||
<v-flex xs12 sm1 md1 class="mr-4">
|
||||
<div class="caption grey--text">Done</div>
|
||||
<v-progress-linear
|
||||
v-model="torrent.progress"
|
||||
height="20"
|
||||
:style="phoneLayout ? '' : 'width: 80%;'"
|
||||
:color="`torrent-${state}-color`" >
|
||||
<span
|
||||
class="caption"
|
||||
>
|
||||
{{ torrent.progress }}%
|
||||
</span>
|
||||
</v-progress-linear>
|
||||
</v-flex>
|
||||
</template>
|
||||
<script>
|
||||
import {TorrentDashboardItem} from '@/mixins'
|
||||
export default {
|
||||
name: 'Progress',
|
||||
mixins : [TorrentDashboardItem],
|
||||
props: ['torrent']
|
||||
}
|
||||
</script>
|
12
src/components/Torrent/DashboardItems/Ratio.vue
Normal file
12
src/components/Torrent/DashboardItems/Ratio.vue
Normal file
|
@ -0,0 +1,12 @@
|
|||
<template>
|
||||
<v-flex xs6 sm1 md1 class="mr-2" >
|
||||
<div class="caption grey--text">Ratio</div>
|
||||
<div>{{ torrent.ratio }}</div>
|
||||
</v-flex>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'Ratio',
|
||||
props: ['torrent']
|
||||
}
|
||||
</script>
|
17
src/components/Torrent/DashboardItems/Seeds.vue
Normal file
17
src/components/Torrent/DashboardItems/Seeds.vue
Normal file
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<v-flex xs6 sm1 md1 class="mr-2">
|
||||
<div class="caption grey--text">Seeds</div>
|
||||
<div>
|
||||
{{ torrent.num_seeds }}
|
||||
<span class="grey--text caption"
|
||||
>/{{ torrent.available_seeds }}</span
|
||||
>
|
||||
</div>
|
||||
</v-flex>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'Seeds',
|
||||
props: ['torrent']
|
||||
}
|
||||
</script>
|
17
src/components/Torrent/DashboardItems/Size.vue
Normal file
17
src/components/Torrent/DashboardItems/Size.vue
Normal file
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<v-flex xs6 sm1 md1 class="mr-2">
|
||||
<div class="caption grey--text">Size</div>
|
||||
<div>
|
||||
{{ torrent.size | getDataValue }}
|
||||
<span class="caption grey--text">{{
|
||||
torrent.size | getDataUnit
|
||||
}}</span>
|
||||
</div>
|
||||
</v-flex>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'Size',
|
||||
props: ['torrent']
|
||||
}
|
||||
</script>
|
22
src/components/Torrent/DashboardItems/Status.vue
Normal file
22
src/components/Torrent/DashboardItems/Status.vue
Normal file
|
@ -0,0 +1,22 @@
|
|||
<template>
|
||||
<v-flex xs5 sm1>
|
||||
<div class="caption grey--text">Status</div>
|
||||
<v-chip
|
||||
small
|
||||
class="caption"
|
||||
:class="
|
||||
theme === 'light'
|
||||
? `${state} white--text `
|
||||
: `${state} black--text`">
|
||||
{{ torrent.state }}
|
||||
</v-chip>
|
||||
</v-flex>
|
||||
</template>
|
||||
<script>
|
||||
import {TorrentDashboardItem} from '@/mixins'
|
||||
export default {
|
||||
name: 'Status',
|
||||
mixins : [TorrentDashboardItem],
|
||||
props: ['torrent']
|
||||
}
|
||||
</script>
|
26
src/components/Torrent/DashboardItems/Tags.vue
Normal file
26
src/components/Torrent/DashboardItems/Tags.vue
Normal file
|
@ -0,0 +1,26 @@
|
|||
<template>
|
||||
<v-flex xs5 sm2 v-if="torrent.tags && torrent.tags.length">
|
||||
<div class="caption grey--text">Tags</div>
|
||||
<v-row wrap class="ma-0">
|
||||
<v-chip v-for="tag in torrent.tags" :key="tag"
|
||||
small
|
||||
:class="
|
||||
theme === 'light'
|
||||
? 'white--text'
|
||||
: 'black--text'
|
||||
"
|
||||
class="download caption mb-1 mx-1"
|
||||
>
|
||||
{{ tag }}
|
||||
</v-chip>
|
||||
</v-row>
|
||||
</v-flex>
|
||||
</template>
|
||||
<script>
|
||||
import {TorrentDashboardItem} from '@/mixins'
|
||||
export default {
|
||||
name: 'Tags',
|
||||
mixins : [TorrentDashboardItem],
|
||||
props: ['torrent']
|
||||
}
|
||||
</script>
|
17
src/components/Torrent/DashboardItems/Upload.vue
Normal file
17
src/components/Torrent/DashboardItems/Upload.vue
Normal file
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<v-flex xs5 sm1 md1 class="mr-2">
|
||||
<div class="caption grey--text">Upload</div>
|
||||
<div>
|
||||
{{ torrent.upspeed | getDataValue }}
|
||||
<span class="caption grey--text">{{
|
||||
torrent.upspeed | getDataUnit
|
||||
}}</span>
|
||||
</div>
|
||||
</v-flex>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'Upload',
|
||||
props: ['torrent']
|
||||
}
|
||||
</script>
|
25
src/components/Torrent/DashboardItems/index.js
Normal file
25
src/components/Torrent/DashboardItems/index.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
import Size from './Size'
|
||||
import Progress from './Progress'
|
||||
import Download from './Download'
|
||||
import Ratio from './Ratio'
|
||||
import Upload from './Upload'
|
||||
import ETA from './ETA'
|
||||
import Peers from './Peers'
|
||||
import Seeds from './Seeds'
|
||||
import Status from './Status'
|
||||
import Category from './Category'
|
||||
import Tags from './Tags'
|
||||
|
||||
export {
|
||||
Size,
|
||||
Progress,
|
||||
Download,
|
||||
Ratio,
|
||||
Upload,
|
||||
ETA,
|
||||
Peers,
|
||||
Seeds,
|
||||
Status,
|
||||
Category,
|
||||
Tags
|
||||
}
|
16
src/mixins/TorrentDashboardItem.js
Normal file
16
src/mixins/TorrentDashboardItem.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
import {mapGetters} from 'vuex'
|
||||
|
||||
export default {
|
||||
computed : {
|
||||
...mapGetters(['getTheme']),
|
||||
phoneLayout() {
|
||||
return this.$vuetify.breakpoint.xsOnly
|
||||
},
|
||||
theme() {
|
||||
return this.getTheme() ? 'dark' : 'light'
|
||||
},
|
||||
state() {
|
||||
return this.torrent.state.toLowerCase()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,6 +9,9 @@ export default {
|
|||
} else {
|
||||
this.$store.commit('SET_SELECTED', { type: 'add', hash })
|
||||
}
|
||||
},
|
||||
selectUntil(hash, index){
|
||||
this.$store.commit('SET_SELECTED', { type: 'until', hash, index })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,5 +4,13 @@ import SettingsTab from './SettingsTab'
|
|||
import Tab from './Tab'
|
||||
import General from './General'
|
||||
import TorrentSelect from './TorrentSelect'
|
||||
import TorrentDashboardItem from './TorrentDashboardItem'
|
||||
|
||||
export { FullScreenModal, Modal, SettingsTab, Tab, General, TorrentSelect }
|
||||
export { FullScreenModal,
|
||||
Modal,
|
||||
SettingsTab,
|
||||
Tab,
|
||||
General,
|
||||
TorrentSelect,
|
||||
TorrentDashboardItem
|
||||
}
|
|
@ -48,10 +48,36 @@ export default new Vuex.Store({
|
|||
showCurrentSpeed: true,
|
||||
showGlobalRemoveResumePause: true,
|
||||
denseDashboard: true,
|
||||
paginationSize: 15
|
||||
paginationSize: 15,
|
||||
busyTorrentProperties: [
|
||||
{ name: 'Size', active: true},
|
||||
{ name: 'Progress', active: true},
|
||||
{ name: 'Download', active: true},
|
||||
{ name: 'Upload', active: true},
|
||||
{ name: 'ETA', active: true},
|
||||
{ name: 'Peers', active: true},
|
||||
{ name: 'Seeds', active: true},
|
||||
{ name: 'Status', active: true},
|
||||
{ name: 'Ratio', active: true},
|
||||
{ name: 'Tags', active: true}
|
||||
],
|
||||
doneTorrentProperties: [
|
||||
{ name: 'Size', active: true},
|
||||
{ name: 'Progress', active: true},
|
||||
{ name: 'Download', active: true},
|
||||
{ name: 'Upload', active: true},
|
||||
{ name: 'ETA', active: true},
|
||||
{ name: 'Peers', active: true},
|
||||
{ name: 'Seeds', active: true},
|
||||
{ name: 'Status', active: true},
|
||||
{ name: 'Ratio', active: true},
|
||||
{ name: 'Tags', active: true}
|
||||
]
|
||||
},
|
||||
categories: [],
|
||||
filteredTorrentsCount: 0
|
||||
filteredTorrentsCount: 0,
|
||||
latestSelectedTorrent: null,
|
||||
selectMode: false
|
||||
},
|
||||
getters: {
|
||||
...getters
|
||||
|
|
|
@ -15,13 +15,26 @@ export default {
|
|||
DELETE_MODAL(state, guid) {
|
||||
state.modals = state.modals.filter(m => m.guid !== guid)
|
||||
},
|
||||
SET_SELECTED: (state, payload) => {
|
||||
if (payload.type === 'add') state.selected_torrents.push(payload.hash)
|
||||
if (payload.type === 'remove')
|
||||
SET_SELECTED: (state, {type, hash, index}) => {
|
||||
if (type === 'add') {
|
||||
state.selected_torrents.push(hash)
|
||||
state.latestSelectedTorrent = state.torrents.map(t => t.hash).indexOf(hash)
|
||||
} else if (type === 'remove') {
|
||||
state.selected_torrents.splice(
|
||||
state.selected_torrents.indexOf(payload.hash),
|
||||
state.selected_torrents.indexOf(hash),
|
||||
1
|
||||
)
|
||||
} else if (type === 'until') {
|
||||
let from, until
|
||||
if (state.latestSelectedTorrent > index) {
|
||||
from = index
|
||||
until = state.latestSelectedTorrent + 1 //include latest selected
|
||||
} else {
|
||||
from = state.latestSelectedTorrent
|
||||
until = index + 1
|
||||
}
|
||||
state.selected_torrents = state.torrents.map(t => t.hash).slice(from, until)
|
||||
}
|
||||
},
|
||||
RESET_SELECTED: state => {
|
||||
state.selected_torrents = []
|
||||
|
|
|
@ -34,11 +34,15 @@
|
|||
<p class="grey--text">Nothing to see here!</p>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div
|
||||
<v-layout
|
||||
@contextmenu.prevent="$refs.menu.open($event, { torrent })"
|
||||
v-for="(torrent, index) in paginatedData"
|
||||
:key="torrent.hash"
|
||||
>
|
||||
<v-flex v-if="selectMode">
|
||||
<v-checkbox color="grey" class="mt-10" xs1 :value="selected_torrents.indexOf(torrent.hash) !== -1" @click="selectTorrent(torrent.hash)" />
|
||||
</v-flex>
|
||||
<v-flex :class="selectMode ? 'xs11' : ''">
|
||||
<Torrent
|
||||
:class="{
|
||||
topBorderRadius: index === 0,
|
||||
|
@ -50,7 +54,8 @@
|
|||
:index="index"
|
||||
:length="torrents.length - 1"
|
||||
/>
|
||||
</div>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
<v-row v-if="pageCount > 1" xs12 justify="center">
|
||||
<v-col>
|
||||
<v-container>
|
||||
|
@ -98,6 +103,7 @@ export default {
|
|||
|
||||
const options = {
|
||||
threshold: 0.3,
|
||||
shouldSort: false,
|
||||
keys: [
|
||||
'name',
|
||||
'size',
|
||||
|
@ -126,6 +132,9 @@ export default {
|
|||
},
|
||||
torrentCountString() {
|
||||
return this.getTorrentCountString()
|
||||
},
|
||||
selectMode(){
|
||||
return this.$store.state.selectMode
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -29,7 +29,7 @@ module.exports = {
|
|||
port: 8000,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://127.0.0.1:8080'
|
||||
target: 'http://localhost:8080'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue