mirror of
https://github.com/CzBiX/qb-web.git
synced 2026-04-14 10:19:48 +08:00
Upgrade to vuetify v2.0
This commit is contained in:
@@ -1,272 +1,268 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-btn
|
||||
fab
|
||||
bottom
|
||||
color="primary"
|
||||
fixed
|
||||
right
|
||||
@click="dialog = !dialog"
|
||||
class="btn-add"
|
||||
:class="{'with-footer': $vuetify.breakpoint.smAndUp}"
|
||||
>
|
||||
<v-icon>mdi-link-plus</v-icon>
|
||||
</v-btn>
|
||||
<v-dialog v-model="dialog" persistent width="50em">
|
||||
<v-card>
|
||||
<v-card-title
|
||||
class="headline grey lighten-4"
|
||||
>
|
||||
<v-icon class="mr-2">mdi-link-plus</v-icon>
|
||||
<span>Add Torrents</span>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-form
|
||||
v-model="valid"
|
||||
ref="form"
|
||||
>
|
||||
<v-container pa-0 v-bind="{ [`grid-list-${$vuetify.breakpoint.name}`]: true }">
|
||||
<v-layout wrap>
|
||||
<v-flex
|
||||
xs12
|
||||
ref="fileZone"
|
||||
>
|
||||
<div
|
||||
v-show="files.length"
|
||||
class="files grey lighten-4 align-center justify-space-between subheading font-weight-medium pl-2"
|
||||
@click="selectFiles"
|
||||
>
|
||||
<input ref="file" type="file" multiple class="d-none" @change="onFilesChanged">
|
||||
<span v-if="files.length == 1">Selected file: {{ files[0].name }}</span>
|
||||
<span v-else>Selected {{ files.length }} files.</span>
|
||||
<v-btn icon @click.stop="files = []">
|
||||
<v-icon>mdi-close</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
<v-textarea
|
||||
v-show="!files.length"
|
||||
label="URLs"
|
||||
hint="One link per line"
|
||||
:placeholder="'Upload torrents by drop them here,\nor click attachment button at right to select.'"
|
||||
prepend-icon="mdi-link"
|
||||
append-outer-icon="mdi-attachment"
|
||||
:rules="[v => (!!files.length || !!v || 'URLs is required')]"
|
||||
:rows="$vuetify.breakpoint.xsOnly ? 1 : 3"
|
||||
required
|
||||
autofocus
|
||||
:value="params.urls"
|
||||
@input="setParams('urls', $event)"
|
||||
@click:append-outer="selectFiles"
|
||||
/>
|
||||
</v-flex>
|
||||
<v-flex>
|
||||
<v-combobox
|
||||
label="Category"
|
||||
prepend-icon="mdi-folder"
|
||||
clearable
|
||||
hide-no-data
|
||||
:items="categories"
|
||||
:value="params.category"
|
||||
@input="setParams('category', $event)"
|
||||
/>
|
||||
</v-flex>
|
||||
<v-flex>
|
||||
<v-checkbox
|
||||
v-model="autoStart"
|
||||
label="Start torrent"
|
||||
prepend-icon="mdi-play-pause"
|
||||
/>
|
||||
</v-flex>
|
||||
<v-flex>
|
||||
<v-checkbox
|
||||
prepend-icon="mdi-progress-check"
|
||||
label="Skip hash check"
|
||||
:value="params.skip_checking"
|
||||
@change="setParams('skip_checking', $event)"
|
||||
/>
|
||||
</v-flex>
|
||||
</v-layout>
|
||||
</v-container>
|
||||
</v-form>
|
||||
<v-alert
|
||||
type="warning"
|
||||
:value="error"
|
||||
v-text="error"
|
||||
/>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<!-- <v-btn flat>More</v-btn> -->
|
||||
<v-spacer />
|
||||
<v-btn flat @click="dialog = false">Cancel</v-btn>
|
||||
<v-btn
|
||||
flat
|
||||
@click="submit"
|
||||
color="primary"
|
||||
:disabled="!valid"
|
||||
:loading="submitting"
|
||||
>
|
||||
Submit
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import _ from 'lodash';
|
||||
import Vue from 'vue';
|
||||
import { mapState } from 'vuex';
|
||||
import { api } from '../Api';
|
||||
|
||||
const defaultParams = {
|
||||
urls: null,
|
||||
category: null,
|
||||
paused: false,
|
||||
skip_checking: false,
|
||||
};
|
||||
|
||||
export default Vue.extend({
|
||||
props: {
|
||||
url: String,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
dialog: false,
|
||||
valid: false,
|
||||
files: [],
|
||||
userParams: {},
|
||||
error: null,
|
||||
submitting: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
prefs: 'preferences',
|
||||
categories(state, getters) {
|
||||
return Object.keys(getters.torrentGroupByCategory).filter(_.identity);
|
||||
},
|
||||
}),
|
||||
params() {
|
||||
return Object.assign({}, defaultParams, this.userParams);
|
||||
},
|
||||
autoStart: {
|
||||
get(): boolean {
|
||||
return !this.params.paused;
|
||||
},
|
||||
set(value: boolean) {
|
||||
const paused = !value;
|
||||
const tmp = defaultParams.paused === paused ? null : paused;
|
||||
this.setParams('paused', tmp);
|
||||
},
|
||||
},
|
||||
},
|
||||
created() {
|
||||
defaultParams.paused = this.prefs.start_paused_enabled;
|
||||
},
|
||||
mounted() {
|
||||
this.$refs.fileZone.addEventListener('drop', this.onDrop, true);
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$refs.fileZone.removeEventListener('drop', this.onDrop, true);
|
||||
},
|
||||
|
||||
methods: {
|
||||
setParams(key: string, value: any){
|
||||
if (_.isNil(value)) {
|
||||
Vue.delete(this.userParams, key);
|
||||
} else {
|
||||
Vue.set(this.userParams, key, value);
|
||||
}
|
||||
},
|
||||
async submit() {
|
||||
if (this.submitting) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.submitting = true;
|
||||
this.error = null;
|
||||
let files;
|
||||
if (this.files.length) {
|
||||
files = this.files;
|
||||
Vue.delete(this.userParams, 'urls');
|
||||
} else {
|
||||
files = null;
|
||||
}
|
||||
|
||||
try {
|
||||
const resp = await api.addTorrents(this.userParams, files);
|
||||
|
||||
if (resp !== 'Ok.') {
|
||||
this.error = resp;
|
||||
}
|
||||
} catch (e) {
|
||||
this.error = e.message
|
||||
}
|
||||
|
||||
this.submitting = false;
|
||||
|
||||
if (this.error) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dialog = false;
|
||||
|
||||
Vue.delete(this.userParams, 'urls');
|
||||
this.files = [];
|
||||
|
||||
this.$refs.form.resetValidation();
|
||||
},
|
||||
selectFiles() {
|
||||
this.$refs.file.click();
|
||||
},
|
||||
onFilesChanged() {
|
||||
this.files = this.$refs.file.files;
|
||||
},
|
||||
onDrop(e: DragEvent) {
|
||||
const transfer = e.dataTransfer!;
|
||||
const files = transfer.files;
|
||||
if (!files.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
this.files = files;
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
url(v) {
|
||||
if (!v) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.dialog) {
|
||||
Vue.set(this.userParams, 'urls', v);
|
||||
this.dialog = true;
|
||||
}
|
||||
|
||||
this.$emit('input', null);
|
||||
},
|
||||
files(v) {
|
||||
this.$refs.form.validate();
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.btn-add.with-footer {
|
||||
margin-bottom: 36px;
|
||||
}
|
||||
|
||||
.files {
|
||||
display: flex;
|
||||
height: 3em;
|
||||
|
||||
border: 1px dashed;
|
||||
border-color: grey !important;
|
||||
border-radius: 2px;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<div>
|
||||
<v-btn
|
||||
fab
|
||||
bottom
|
||||
color="primary"
|
||||
fixed
|
||||
right
|
||||
@click="dialog = !dialog"
|
||||
class="btn-add"
|
||||
:class="{'with-footer': $vuetify.breakpoint.smAndUp}"
|
||||
>
|
||||
<v-icon>mdi-link-plus</v-icon>
|
||||
</v-btn>
|
||||
<v-dialog v-model="dialog" eager persistent width="40em">
|
||||
<v-card>
|
||||
<v-card-title
|
||||
class="headline grey lighten-4"
|
||||
>
|
||||
<v-icon class="mr-2">mdi-link-plus</v-icon>
|
||||
<span>Add Torrents</span>
|
||||
</v-card-title>
|
||||
<v-card-text class="pb-0">
|
||||
<v-form
|
||||
v-model="valid"
|
||||
ref="form"
|
||||
>
|
||||
<v-container v-bind="{ [`grid-list-${$vuetify.breakpoint.name}`]: true }">
|
||||
<v-row>
|
||||
<v-col
|
||||
cols="12"
|
||||
ref="fileZone"
|
||||
>
|
||||
<v-file-input
|
||||
v-show="files.length"
|
||||
v-model="files"
|
||||
ref="file"
|
||||
multiple
|
||||
chips
|
||||
outlined
|
||||
label="Files"
|
||||
/>
|
||||
<v-textarea
|
||||
v-show="!files.length"
|
||||
label="URLs"
|
||||
hint="One link per line"
|
||||
:placeholder="placeholder"
|
||||
prepend-icon="mdi-link"
|
||||
append-outer-icon="mdi-attachment"
|
||||
:rules="[v => (!!files.length || !!v || 'URLs is required')]"
|
||||
:rows="$vuetify.breakpoint.xsOnly ? 1 : 3"
|
||||
required
|
||||
autofocus
|
||||
:value="params.urls"
|
||||
@input="setParams('urls', $event)"
|
||||
@click:append-outer="selectFiles"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-combobox
|
||||
label="Category"
|
||||
prepend-icon="mdi-folder"
|
||||
clearable
|
||||
hide-no-data
|
||||
:items="categories"
|
||||
:value="params.category"
|
||||
@input="setParams('category', $event)"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-checkbox
|
||||
v-model="autoStart"
|
||||
label="Start torrent"
|
||||
prepend-icon="mdi-play-pause"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-checkbox
|
||||
prepend-icon="mdi-progress-check"
|
||||
label="Skip hash check"
|
||||
:value="params.skip_checking"
|
||||
@change="setParams('skip_checking', $event)"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-form>
|
||||
<v-alert
|
||||
type="warning"
|
||||
:value="error"
|
||||
v-text="error"
|
||||
/>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<!-- <v-btn flat>More</v-btn> -->
|
||||
<v-spacer />
|
||||
<v-btn text @click="dialog = false">Cancel</v-btn>
|
||||
<v-btn
|
||||
text
|
||||
@click="submit"
|
||||
color="primary"
|
||||
:disabled="!valid"
|
||||
:loading="submitting"
|
||||
>
|
||||
Submit
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import _ from 'lodash';
|
||||
import Vue from 'vue';
|
||||
import { mapState } from 'vuex';
|
||||
import api from '../Api';
|
||||
|
||||
const defaultParams = {
|
||||
urls: null,
|
||||
category: null,
|
||||
paused: false,
|
||||
skip_checking: false,
|
||||
};
|
||||
|
||||
export default Vue.extend({
|
||||
props: {
|
||||
url: String,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
placeholder: 'Upload torrents by drop them here,\nor click attachment button at right to select.',
|
||||
dialog: false,
|
||||
valid: false,
|
||||
files: [],
|
||||
userParams: {},
|
||||
error: null,
|
||||
submitting: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
prefs: 'preferences',
|
||||
categories(state, getters) {
|
||||
return Object.keys(getters.torrentGroupByCategory).filter(_.identity);
|
||||
},
|
||||
}),
|
||||
params() {
|
||||
return Object.assign({}, defaultParams, this.userParams);
|
||||
},
|
||||
autoStart: {
|
||||
get(): boolean {
|
||||
return !this.params.paused;
|
||||
},
|
||||
set(value: boolean) {
|
||||
const paused = !value;
|
||||
const tmp = defaultParams.paused === paused ? null : paused;
|
||||
this.setParams('paused', tmp);
|
||||
},
|
||||
},
|
||||
},
|
||||
created() {
|
||||
defaultParams.paused = this.prefs.start_paused_enabled;
|
||||
},
|
||||
mounted() {
|
||||
this.$refs.fileZone.addEventListener('drop', this.onDrop, true);
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$refs.fileZone.removeEventListener('drop', this.onDrop, true);
|
||||
},
|
||||
|
||||
methods: {
|
||||
setParams(key: string, value: any) {
|
||||
if (_.isNil(value)) {
|
||||
Vue.delete(this.userParams, key);
|
||||
} else {
|
||||
Vue.set(this.userParams, key, value);
|
||||
}
|
||||
},
|
||||
async submit() {
|
||||
if (this.submitting) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.submitting = true;
|
||||
this.error = null;
|
||||
let files;
|
||||
if (this.files.length) {
|
||||
({ files } = this);
|
||||
Vue.delete(this.userParams, 'urls');
|
||||
} else {
|
||||
files = null;
|
||||
}
|
||||
|
||||
try {
|
||||
const resp = await api.addTorrents(this.userParams, files);
|
||||
|
||||
if (resp !== 'Ok.') {
|
||||
this.error = resp;
|
||||
}
|
||||
} catch (e) {
|
||||
this.error = e.message;
|
||||
}
|
||||
|
||||
this.submitting = false;
|
||||
|
||||
if (this.error) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dialog = false;
|
||||
|
||||
Vue.delete(this.userParams, 'urls');
|
||||
this.files = [];
|
||||
|
||||
this.$refs.form.resetValidation();
|
||||
},
|
||||
selectFiles() {
|
||||
const input = this.$refs.file.$el.querySelector('input[type=file]');
|
||||
input.click();
|
||||
},
|
||||
onDrop(e: DragEvent) {
|
||||
const transfer = e.dataTransfer!;
|
||||
const { files } = transfer;
|
||||
if (!files.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
this.files = files;
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
url(v) {
|
||||
if (!v) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.dialog) {
|
||||
Vue.set(this.userParams, 'urls', v);
|
||||
this.dialog = true;
|
||||
}
|
||||
|
||||
this.$emit('input', null);
|
||||
},
|
||||
files(v) {
|
||||
this.$refs.form.validate();
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.btn-add.with-footer {
|
||||
margin-bottom: 36px;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 12px 0 0;
|
||||
|
||||
.col {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user