perf: Merge MatchingArticles into RuleForm (#844)

This commit is contained in:
Rémi Marseault 2023-06-01 18:35:35 +02:00 committed by GitHub
parent e458651124
commit 2e3efe7b2a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 100 additions and 148 deletions

View file

@ -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>

View file

@ -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()
}

View file

@ -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 })
}
}
}