mirror of
https://github.com/VueTorrent/VueTorrent.git
synced 2025-02-18 00:02:02 +03:00
perf: Merge MatchingArticles into RuleForm (#844)
This commit is contained in:
parent
e458651124
commit
2e3efe7b2a
3 changed files with 100 additions and 148 deletions
|
@ -1,82 +0,0 @@
|
|||
<template>
|
||||
<v-dialog v-model="dialog" max-width="500px">
|
||||
<v-card flat>
|
||||
<v-container class="pa-0 project done">
|
||||
<v-card-title class="justify-center">
|
||||
<v-toolbar flat dense class="transparent">
|
||||
<v-toolbar-title class="mx-auto">
|
||||
<h2>{{ $t('modals.matchingArticles.title') }}</h2>
|
||||
</v-toolbar-title>
|
||||
<v-btn fab small class="transparent elevation-0" @click="close">
|
||||
<v-icon>{{ mdiClose }}</v-icon>
|
||||
</v-btn>
|
||||
</v-toolbar>
|
||||
</v-card-title>
|
||||
<v-card-text class="pb-0">
|
||||
<v-list subheader>
|
||||
<template v-for="item in matchingArticles" :key="item">
|
||||
<v-divider inset v-if="item.type === 'divider'" />
|
||||
<v-subheader inset v-else-if="item.type === 'subheader'">{{ item.value }}</v-subheader>
|
||||
<v-list-item v-else class="mb-3">{{ item.value }}</v-list-item>
|
||||
</template>
|
||||
</v-list>
|
||||
</v-card-text>
|
||||
</v-container>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import qbit from '@/services/qbit'
|
||||
import { mdiClose } from '@mdi/js'
|
||||
import { Modal } from '@/mixins'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MatchingArticles',
|
||||
mixins: [Modal],
|
||||
props: {
|
||||
ruleName: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
matchingArticles: [] as { type: string; value?: string }[],
|
||||
mdiClose
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
document.addEventListener('keydown', this.handleKeyboardShortcut)
|
||||
|
||||
if (this.ruleName === undefined) {
|
||||
this.close()
|
||||
return
|
||||
}
|
||||
|
||||
const articles = await qbit.getMatchingArticles(this.ruleName)
|
||||
for (const feedName in articles) {
|
||||
const feedArticles = articles[feedName]
|
||||
if (this.matchingArticles.length > 0) this.matchingArticles.push({ type: 'divider' })
|
||||
|
||||
this.matchingArticles.push({ type: 'subheader', value: feedName })
|
||||
|
||||
for (const i in feedArticles) {
|
||||
const article = feedArticles[i]
|
||||
this.matchingArticles.push({ type: 'item', value: article })
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener('keydown', this.handleKeyboardShortcut)
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.dialog = false
|
||||
},
|
||||
handleKeyboardShortcut(e: KeyboardEvent) {
|
||||
if (e.key === 'Escape') {
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
|
@ -1,11 +1,11 @@
|
|||
<template>
|
||||
<v-dialog v-model="dialog" max-width="500px">
|
||||
<v-card flat>
|
||||
<v-dialog v-model="dialog" max-width="1000px">
|
||||
<v-card flat :loading="loading">
|
||||
<v-container class="pa-0 project done">
|
||||
<v-card-title class="justify-center">
|
||||
<v-toolbar flat dense class="transparent">
|
||||
<v-toolbar-title class="mx-auto">
|
||||
<h2>{{ hasInitialRule ? $t('modals.newRule.titleEdit') : $t('modals.newRule.titleCreate') }}</h2>
|
||||
<h2>{{ this.lastSavedName !== '' ? $t('modals.newRule.titleEdit') : $t('modals.newRule.titleCreate') }}</h2>
|
||||
</v-toolbar-title>
|
||||
<v-btn fab small class="transparent elevation-0" @click="close">
|
||||
<v-icon>{{ mdiClose }}</v-icon>
|
||||
|
@ -13,62 +13,76 @@
|
|||
</v-toolbar>
|
||||
</v-card-title>
|
||||
<v-card-text class="pb-0">
|
||||
<v-form ref="form" v-model="valid">
|
||||
<v-container>
|
||||
<v-text-field v-model="rule.name" :label="$t('modals.newRule.name')" required />
|
||||
<v-row>
|
||||
<v-col cols="12" sm="6">
|
||||
<v-form ref="form">
|
||||
<v-container>
|
||||
<v-text-field v-model="rule.name" :label="$t('modals.newRule.name')" required />
|
||||
|
||||
<v-divider />
|
||||
<v-divider />
|
||||
|
||||
<v-checkbox hide-details v-model="rule.useRegex" :label="$t('modals.newRule.def.useRegex')" />
|
||||
<v-text-field hide-details v-model="rule.mustContain" :label="$t('modals.newRule.def.mustContain')" />
|
||||
<v-text-field hide-details v-model="rule.mustNotContain" :label="$t('modals.newRule.def.mustNotContain')" />
|
||||
<v-checkbox hide-details v-model="rule.smartFilter" :label="$t('modals.newRule.def.smartFilter')" />
|
||||
<v-text-field v-model="rule.episodeFilter" :label="$t('modals.newRule.def.episodeFilter')" />
|
||||
<v-checkbox hide-details v-model="rule.useRegex" :label="$t('modals.newRule.def.useRegex')" />
|
||||
<v-text-field hide-details v-model="rule.mustContain" :label="$t('modals.newRule.def.mustContain')" />
|
||||
<v-text-field hide-details v-model="rule.mustNotContain" :label="$t('modals.newRule.def.mustNotContain')" />
|
||||
<v-checkbox hide-details v-model="rule.smartFilter" :label="$t('modals.newRule.def.smartFilter')" />
|
||||
<v-text-field v-model="rule.episodeFilter" :label="$t('modals.newRule.def.episodeFilter')" />
|
||||
|
||||
<v-divider />
|
||||
<v-divider />
|
||||
|
||||
<v-row>
|
||||
<p class="subtitle-1 mb-1">{{ $t('modals.newRule.def.assignedCategory') }}</p>
|
||||
<v-select flat solo dense hide-details background-color="background" class="rounded-xl" v-model="rule.assignedCategory" :items="availableCategories" />
|
||||
</v-row>
|
||||
<v-text-field hide-details v-model="rule.savePath" :label="$t('modals.newRule.def.savePath')" />
|
||||
<v-text-field hide-details v-model="rule.ignoreDays" :label="$t('modals.newRule.def.ignoreDays')" required type="number" min="0" />
|
||||
<v-text-field disabled :value="lastMatch" :label="$t('modals.newRule.def.lastMatch.title')" />
|
||||
<v-row>
|
||||
<p class="subtitle-1 mb-1">{{ $t('modals.newRule.def.assignedCategory') }}</p>
|
||||
<v-select flat solo dense hide-details background-color="background" class="rounded-xl" v-model="rule.assignedCategory" :items="availableCategories" />
|
||||
</v-row>
|
||||
<v-text-field hide-details v-model="rule.savePath" :label="$t('modals.newRule.def.savePath')" />
|
||||
<v-text-field hide-details v-model="rule.ignoreDays" :label="$t('modals.newRule.def.ignoreDays')" required type="number" min="0" />
|
||||
<v-text-field disabled :value="lastMatch" :label="$t('modals.newRule.def.lastMatch.title')" />
|
||||
|
||||
<v-divider />
|
||||
<v-divider />
|
||||
|
||||
<v-row no-gutters class="my-2 flex-gap">
|
||||
<v-col>
|
||||
<div class="d-flex flex-column align-center">
|
||||
<p class="subtitle-1 mb-1">{{ $t('modals.newRule.def.addPaused.title') }}</p>
|
||||
<v-select v-model="rule.addPaused" flat solo dense hide-details background-color="background" class="rounded-xl" :items="addPausedOptions" />
|
||||
</div>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<div class="d-flex flex-column align-center">
|
||||
<p class="subtitle-1 mb-1">{{ $t('enums.contentLayout.title') }}</p>
|
||||
<v-select v-model="rule.torrentContentLayout" flat solo dense hide-details background-color="background" class="rounded-xl" :items="contentLayoutOptions" />
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row no-gutters class="my-2 flex-gap">
|
||||
<v-col>
|
||||
<div class="d-flex flex-column align-center">
|
||||
<p class="subtitle-1 mb-1">{{ $t('modals.newRule.def.addPaused.title') }}</p>
|
||||
<v-select v-model="rule.addPaused" flat solo dense hide-details background-color="background" class="rounded-xl" :items="addPausedOptions" />
|
||||
</div>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<div class="d-flex flex-column align-center">
|
||||
<p class="subtitle-1 mb-1">{{ $t('enums.contentLayout.title') }}</p>
|
||||
<v-select v-model="rule.torrentContentLayout" flat solo dense hide-details background-color="background" class="rounded-xl" :items="contentLayoutOptions" />
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-subheader class="pa-0">
|
||||
{{ $t('modals.newRule.def.affectedFeeds') }}
|
||||
</v-subheader>
|
||||
<v-checkbox v-for="(item, index) in availableFeeds" :key="index" v-model="rule.affectedFeeds" hide-details :label="item.name" :value="item.url" />
|
||||
</v-container>
|
||||
</v-form>
|
||||
<v-subheader class="pa-0">
|
||||
{{ $t('modals.newRule.def.affectedFeeds') }}
|
||||
</v-subheader>
|
||||
<v-checkbox v-for="(item, index) in availableFeeds" :key="index" v-model="rule.affectedFeeds" hide-details :label="item.name" :value="item.url" />
|
||||
</v-container>
|
||||
</v-form>
|
||||
</v-col>
|
||||
<v-col v-if="$vuetify.breakpoint.smAndUp" cols="6">
|
||||
<h2>{{ $t('modals.matchingArticles.title') }}</h2>
|
||||
<v-list subheader>
|
||||
<template v-for="item in matchingArticles">
|
||||
<v-divider :key="item.value" v-if="item.type === 'divider'" />
|
||||
<v-subheader inset v-else-if="item.type === 'subheader'">{{ item.value }}</v-subheader>
|
||||
<v-list-item v-else class="mb-3">{{ item.value }}</v-list-item>
|
||||
</template>
|
||||
</v-list>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-btn fab color="accent" fixed right bottom @click="setRule">
|
||||
<v-icon>{{ mdiContentSave }}</v-icon>
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
<v-divider />
|
||||
<v-card-actions class="justify-end">
|
||||
<v-btn v-if="!hasInitialRule" class="accent white--text elevation-0 px-4" @click="setRule" :disabled="!valid">
|
||||
{{ $t('create') }}
|
||||
<v-btn class="accent white--text elevation-0 px-4" @click="setRule">
|
||||
{{ $t('save') }}
|
||||
</v-btn>
|
||||
<v-btn v-else class="accent white--text elevation-0 px-4" @click="setRule" :disabled="!valid">
|
||||
{{ $t('edit') }}
|
||||
</v-btn>
|
||||
<v-btn class="error white--text elevation-0 px-4" @click="cancel">
|
||||
{{ $t('cancel') }}
|
||||
<v-btn class="white--text elevation-0 px-4" @click="close">
|
||||
{{ $t('close') }}
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-container>
|
||||
|
@ -81,17 +95,18 @@ import { defineComponent } from 'vue'
|
|||
import { mapGetters } from 'vuex'
|
||||
import qbit from '@/services/qbit'
|
||||
import { Modal } from '@/mixins'
|
||||
import { mdiClose } from '@mdi/js'
|
||||
import { mdiClose, mdiContentSave } from '@mdi/js'
|
||||
import i18n from '@/plugins/i18n'
|
||||
import { AppPreferences } from '@/enums/qbit'
|
||||
import { Category } from '@/types/vuetorrent'
|
||||
|
||||
type FormattedArticle = { type: string; value?: string }
|
||||
|
||||
export default defineComponent({
|
||||
name: 'RuleForm',
|
||||
mixins: [Modal],
|
||||
props: ['initialRule'],
|
||||
data: () => ({
|
||||
valid: false,
|
||||
rule: {
|
||||
addPaused: null,
|
||||
affectedFeeds: [],
|
||||
|
@ -119,7 +134,11 @@ export default defineComponent({
|
|||
{ text: i18n.t('enums.contentLayout.subfolder'), value: AppPreferences.ContentLayout.SUBFOLDER },
|
||||
{ text: i18n.t('enums.contentLayout.nosubfolder'), value: AppPreferences.ContentLayout.NO_SUBFOLDER }
|
||||
],
|
||||
mdiClose
|
||||
loading: false,
|
||||
matchingArticles: [] as FormattedArticle[],
|
||||
lastSavedName: '',
|
||||
mdiClose,
|
||||
mdiContentSave
|
||||
}),
|
||||
computed: {
|
||||
...mapGetters(['getFeeds', 'getCategories']),
|
||||
|
@ -148,32 +167,55 @@ export default defineComponent({
|
|||
this.$store.commit('FETCH_RULES')
|
||||
if (this.hasInitialRule) {
|
||||
this.rule = { ...this.initialRule }
|
||||
this.lastSavedName = this.initialRule.name
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
document.addEventListener('keydown', this.handleKeyboardShortcut)
|
||||
|
||||
this.updateArticles()
|
||||
},
|
||||
beforeDestroy() {
|
||||
document.removeEventListener('keydown', this.handleKeyboardShortcut)
|
||||
},
|
||||
methods: {
|
||||
async setRule() {
|
||||
if (this.hasInitialRule && this.initialRule.name !== this.rule.name) {
|
||||
await qbit.renameRule(this.initialRule.name, this.rule.name)
|
||||
if ((this.hasInitialRule || this.lastSavedName !== '') && this.lastSavedName !== this.rule.name) {
|
||||
await qbit.renameRule(this.lastSavedName, this.rule.name)
|
||||
}
|
||||
await qbit.setRule(this.rule)
|
||||
this.cancel()
|
||||
},
|
||||
cancel() {
|
||||
this.lastSavedName = this.rule.name
|
||||
this.$store.commit('FETCH_RULES')
|
||||
this.close()
|
||||
await this.updateArticles()
|
||||
},
|
||||
async updateArticles() {
|
||||
if (this.lastSavedName === '') return
|
||||
|
||||
this.loading = true
|
||||
|
||||
const formattedArticles = []
|
||||
const articles = await qbit.getMatchingArticles(this.lastSavedName)
|
||||
for (const feedName in articles) {
|
||||
const feedArticles = articles[feedName]
|
||||
if (formattedArticles.length > 0) formattedArticles.push({ type: 'divider' })
|
||||
|
||||
formattedArticles.push({ type: 'subheader', value: feedName })
|
||||
|
||||
for (const i in feedArticles) {
|
||||
const article = feedArticles[i]
|
||||
formattedArticles.push({ type: 'item', value: article })
|
||||
}
|
||||
}
|
||||
|
||||
this.matchingArticles = formattedArticles
|
||||
this.loading = false
|
||||
},
|
||||
close() {
|
||||
this.dialog = false
|
||||
},
|
||||
handleKeyboardShortcut(e: KeyboardEvent) {
|
||||
if (e.key === 'Escape') {
|
||||
this.cancel()
|
||||
this.close()
|
||||
} else if (e.key === 'Enter') {
|
||||
this.setRule()
|
||||
}
|
||||
|
|
|
@ -6,11 +6,6 @@
|
|||
<v-list-item-content>
|
||||
<v-list-item-title v-text="item.name" />
|
||||
</v-list-item-content>
|
||||
<v-list-item-action class="icon">
|
||||
<v-icon @click="previewMatchingArticles(item.name)">
|
||||
{{ mdiEye }}
|
||||
</v-icon>
|
||||
</v-list-item-action>
|
||||
<v-list-item-action class="icon">
|
||||
<v-icon @click="editRule(item)">
|
||||
{{ mdiPencil }}
|
||||
|
@ -71,9 +66,6 @@ export default {
|
|||
},
|
||||
editRule(item) {
|
||||
this.createModal('RuleForm', { initialRule: item })
|
||||
},
|
||||
previewMatchingArticles(ruleName) {
|
||||
this.createModal('MatchingArticles', { ruleName })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue