mirror of
https://github.com/VueTorrent/VueTorrent.git
synced 2024-11-24 18:36:14 +03:00
feat(history): Add history to some fields (#1361)
This commit is contained in:
parent
988ecaaa03
commit
ef50c6c341
9 changed files with 142 additions and 30 deletions
41
src/components/Core/HistoryField.vue
Normal file
41
src/components/Core/HistoryField.vue
Normal file
|
@ -0,0 +1,41 @@
|
|||
<script setup lang="ts">
|
||||
import { HistoryKey } from '@/constants/vuetorrent'
|
||||
import { useHistoryStore } from '@/stores'
|
||||
import { computed, ref } from 'vue'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: string
|
||||
historyKey: HistoryKey
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: string]
|
||||
}>()
|
||||
|
||||
const historyStore = useHistoryStore()
|
||||
|
||||
const field = ref<HTMLInputElement>()
|
||||
|
||||
const historyValue = computed(() => historyStore.getHistory(props.historyKey))
|
||||
const _value = computed({
|
||||
get: () => props.modelValue ?? '',
|
||||
set: (value: string) => emit('update:modelValue', value)
|
||||
})
|
||||
|
||||
function saveValueToHistory() {
|
||||
historyStore.pushValueToHistory(props.historyKey, _value.value)
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
saveValueToHistory,
|
||||
focus: () => field.value?.focus()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-combobox v-model="_value" ref="field" :items="historyValue" />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -1,6 +1,8 @@
|
|||
<script lang="ts" setup>
|
||||
import HistoryField from '@/components/Core/HistoryField.vue'
|
||||
import { useDialog } from '@/composables'
|
||||
import { AppPreferences } from '@/constants/qbit'
|
||||
import { HistoryKey } from '@/constants/vuetorrent'
|
||||
import { useAddTorrentStore, useMaindataStore, usePreferenceStore, useTorrentStore, useVueTorrentStore } from '@/stores'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { computed, ref } from 'vue'
|
||||
|
@ -37,6 +39,10 @@ const stopConditionOptions = [
|
|||
|
||||
const isFormValid = computed(() => urls.value.length > 0 || files.value.length > 0)
|
||||
|
||||
const cookieField = ref<typeof HistoryField>()
|
||||
const dlPathField = ref<typeof HistoryField>()
|
||||
const savePathField = ref<typeof HistoryField>()
|
||||
|
||||
const cookie = computed({
|
||||
get: () => form.value.cookie,
|
||||
set: value => form.value.cookie = value || undefined
|
||||
|
@ -145,6 +151,9 @@ function submit() {
|
|||
autoClose: 1500
|
||||
})
|
||||
.then(() => {
|
||||
cookieField.value?.saveValueToHistory()
|
||||
dlPathField.value?.saveValueToHistory()
|
||||
savePathField.value?.saveValueToHistory()
|
||||
addTorrentStore.resetForm()
|
||||
close()
|
||||
})
|
||||
|
@ -197,14 +206,13 @@ const onCategoryChanged = () => {
|
|||
<v-icon color="accent">mdi-link</v-icon>
|
||||
</template>
|
||||
</v-textarea>
|
||||
<v-text-field v-if="!!urls" v-model="cookie" clearable autocomplete="cookie"
|
||||
<HistoryField v-if="!!urls" v-model="cookie" :historyKey="HistoryKey.COOKIE" ref="cookieField" clearable
|
||||
:label="$t('dialogs.add.cookie')" :placeholder="$t('dialogs.add.cookiePlaceholder')">
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="accent">mdi-cookie</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
<v-text-field v-model="rename" clearable hide-details autocomplete="rename"
|
||||
:label="$t('dialogs.add.rename')">
|
||||
</HistoryField>
|
||||
<v-text-field v-model="rename" clearable hide-details :label="$t('dialogs.add.rename')">
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="accent">mdi-rename</v-icon>
|
||||
</template>
|
||||
|
@ -251,21 +259,21 @@ const onCategoryChanged = () => {
|
|||
</v-col>
|
||||
|
||||
<v-col cols="12">
|
||||
<v-text-field v-model="downloadPath" :disabled="form.autoTMM" autocomplete="downloadPath"
|
||||
:label="t('dialogs.add.downloadPath')" hide-details>
|
||||
<HistoryField v-model="downloadPath" :history-key="HistoryKey.TORRENT_PATH" ref="dlPathField"
|
||||
:disabled="form.autoTMM" :label="t('dialogs.add.downloadPath')" hide-details>
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="accent">mdi-tray-arrow-down</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</HistoryField>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12">
|
||||
<v-text-field v-model="form.savepath" :disabled="form.autoTMM" autocomplete="savepath"
|
||||
:label="t('dialogs.add.savePath')" hide-details>
|
||||
<HistoryField v-model="form.savepath" :history-key="HistoryKey.TORRENT_PATH" ref="savePathField"
|
||||
:disabled="form.autoTMM" :label="t('dialogs.add.savePath')" hide-details>
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="accent">mdi-content-save</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</HistoryField>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="6">
|
||||
|
@ -315,7 +323,7 @@ const onCategoryChanged = () => {
|
|||
<v-expansion-panel-text>
|
||||
<v-row>
|
||||
<v-col cols="12" md="6">
|
||||
<v-text-field v-model="dlLimit" :label="$t('dialogs.add.dlLimit')" autocomplete="dlLimit"
|
||||
<v-text-field v-model="dlLimit" :label="$t('dialogs.add.dlLimit')"
|
||||
hide-details suffix="KiB/s">
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="accent">mdi-download</v-icon>
|
||||
|
@ -323,7 +331,7 @@ const onCategoryChanged = () => {
|
|||
</v-text-field>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-text-field v-model="upLimit" :label="$t('dialogs.add.upLimit')" autocomplete="upLimit"
|
||||
<v-text-field v-model="upLimit" :label="$t('dialogs.add.upLimit')"
|
||||
hide-details suffix="KiB/s">
|
||||
<template v-slot:prepend>
|
||||
<v-icon color="accent">mdi-upload</v-icon>
|
||||
|
@ -332,18 +340,18 @@ const onCategoryChanged = () => {
|
|||
</v-col>
|
||||
|
||||
<v-col cols="12" md="4">
|
||||
<v-text-field v-model="ratioLimit" autocomplete="ratioLimit"
|
||||
<v-text-field v-model="ratioLimit"
|
||||
:hint="$t('dialogs.add.limitHint')" :label="$t('dialogs.add.ratioLimit')"
|
||||
type="number" />
|
||||
</v-col>
|
||||
<v-col cols="12" md="4">
|
||||
<v-text-field v-model="seedingTimeLimit" autocomplete="seedingTimeLimit"
|
||||
<v-text-field v-model="seedingTimeLimit"
|
||||
:label="$t('dialogs.add.seedingTimeLimit')"
|
||||
:hint="$t('dialogs.add.limitHint')"
|
||||
:suffix="$t('units.minutes')" type="number" />
|
||||
</v-col>
|
||||
<v-col cols="12" md="4">
|
||||
<v-text-field v-model="inactiveSeedingTimeLimit" autocomplete="inactiveSeedingTimeLimit"
|
||||
<v-text-field v-model="inactiveSeedingTimeLimit"
|
||||
:label="$t('dialogs.add.inactiveSeedingTimeLimit')"
|
||||
:hint="$t('dialogs.add.limitHint')"
|
||||
:suffix="$t('units.minutes')" type="number" />
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import HistoryField from '@/components/Core/HistoryField.vue'
|
||||
import { useDialog } from '@/composables'
|
||||
import { HistoryKey } from '@/constants/vuetorrent'
|
||||
import { useMaindataStore, useTorrentStore } from '@/stores'
|
||||
import { computed, onBeforeMount, reactive, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
@ -17,6 +19,7 @@ const maindataStore = useMaindataStore()
|
|||
const torrentStore = useTorrentStore()
|
||||
|
||||
const form = ref<VForm>()
|
||||
const field = ref<typeof HistoryField>()
|
||||
const isFormValid = ref(false)
|
||||
const formData = reactive({
|
||||
newPath: ''
|
||||
|
@ -41,6 +44,8 @@ async function submit() {
|
|||
await maindataStore.toggleAutoTmm(props.hashes, false)
|
||||
await torrentStore.moveTorrents(props.mode, props.hashes, formData.newPath)
|
||||
|
||||
field.value?.saveValueToHistory()
|
||||
|
||||
close()
|
||||
}
|
||||
|
||||
|
@ -60,7 +65,8 @@ onBeforeMount(() => {
|
|||
<v-card-text>
|
||||
<v-form v-model="isFormValid" ref="form" @submit.prevent>
|
||||
<v-text-field v-if="oldPath" :model-value="oldPath" disabled :label="$t('dialogs.moveTorrent.oldPath')" />
|
||||
<v-text-field v-model="formData.newPath" :rules="rules" autofocus :label="$t('dialogs.moveTorrent.newPath')"
|
||||
<HistoryField v-model="formData.newPath" :historyKey="HistoryKey.TORRENT_PATH" ref="field"
|
||||
:rules="rules" autofocus :label="$t('dialogs.moveTorrent.newPath')"
|
||||
@keydown.enter="submit" />
|
||||
</v-form>
|
||||
</v-card-text>
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import { TitleOptions } from '@/constants/vuetorrent'
|
||||
import { LOCALES } from '@/locales'
|
||||
import { useAppStore, useVueTorrentStore } from '@/stores'
|
||||
import { useAppStore, useHistoryStore, useVueTorrentStore } from '@/stores'
|
||||
import { computed, onBeforeMount, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { toast } from 'vue3-toastify'
|
||||
|
||||
const { t } = useI18n()
|
||||
const appStore = useAppStore()
|
||||
const historyStore = useHistoryStore()
|
||||
const vueTorrentStore = useVueTorrentStore()
|
||||
|
||||
const titleOptionsList = [
|
||||
|
@ -142,14 +143,18 @@ onBeforeMount(() => {
|
|||
|
||||
<v-list-item>
|
||||
<v-row>
|
||||
<v-col cols="12" md="6">
|
||||
<v-col cols="12" md="4">
|
||||
<v-text-field v-model="vueTorrentStore.refreshInterval" type="number" hide-details suffix="ms"
|
||||
:label="t('settings.vuetorrent.general.refreshInterval')" />
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-col cols="12" md="4">
|
||||
<v-text-field v-model="vueTorrentStore.fileContentInterval" type="number" hide-details suffix="ms"
|
||||
:label="t('settings.vuetorrent.general.fileContentInterval')" />
|
||||
</v-col>
|
||||
<v-col cols="12" md="4">
|
||||
<v-text-field v-model="historyStore.historySize" type="number" hide-details
|
||||
:label="t('settings.vuetorrent.general.historySize')" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col cols="12" md="6">
|
||||
|
|
5
src/constants/vuetorrent/HistoryKey.ts
Normal file
5
src/constants/vuetorrent/HistoryKey.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
export enum HistoryKey {
|
||||
COOKIE = 'cookie',
|
||||
SEARCH_ENGINE_QUERY = 'searchEngineQuery',
|
||||
TORRENT_PATH = 'torrentPath'
|
||||
}
|
|
@ -3,6 +3,7 @@ import { propsData, propsMetadata } from './DashboardDefaults'
|
|||
import { DashboardProperty } from './DashboardProperty'
|
||||
import { DashboardPropertyType } from './DashboardPropertyType'
|
||||
import { typesMap, getFileIcon } from './FileIcon'
|
||||
import { HistoryKey } from './HistoryKey'
|
||||
import { TitleOptions } from './TitleOptions'
|
||||
|
||||
export { TorrentProperty, PropertyData, PropertyMetadata, propsData, propsMetadata, DashboardProperty, DashboardPropertyType, typesMap, getFileIcon, TitleOptions }
|
||||
export { TorrentProperty, PropertyData, PropertyMetadata, propsData, propsMetadata, DashboardProperty, DashboardPropertyType, typesMap, getFileIcon, HistoryKey, TitleOptions }
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import HistoryField from '@/components/Core/HistoryField.vue'
|
||||
import PluginManagerDialog from '@/components/Dialogs/PluginManagerDialog.vue'
|
||||
import { useSearchQuery } from '@/composables'
|
||||
import { HistoryKey } from '@/constants/vuetorrent'
|
||||
import { formatData } from '@/helpers'
|
||||
import { useAddTorrentStore, useDialogStore, useSearchEngineStore, useVueTorrentStore } from '@/stores'
|
||||
import { SearchPlugin, SearchResult } from '@/types/qbit/models'
|
||||
|
@ -17,7 +19,7 @@ const dialogStore = useDialogStore()
|
|||
const searchEngineStore = useSearchEngineStore()
|
||||
const vuetorrentStore = useVueTorrentStore()
|
||||
|
||||
const queryInput = ref<HTMLInputElement>()
|
||||
const queryInput = ref<typeof HistoryField>()
|
||||
|
||||
const pluginManagerDialogVisible = ref(false)
|
||||
const tabIndex = ref(0)
|
||||
|
@ -85,6 +87,7 @@ function downloadTorrent(result: SearchResult) {
|
|||
async function runNewSearch() {
|
||||
await searchEngineStore.runNewSearch(selectedTab.value)
|
||||
selectedTab.value.timer = setInterval(() => refreshResults(selectedTab.value), 1000)
|
||||
queryInput.value?.saveValueToHistory()
|
||||
}
|
||||
|
||||
async function stopSearch(tab: SearchData) {
|
||||
|
@ -179,15 +182,9 @@ onBeforeUnmount(() => {
|
|||
<v-list-item>
|
||||
<v-row class="mt-1">
|
||||
<v-col cols="12" md="6">
|
||||
<v-text-field
|
||||
v-model="selectedTab.query"
|
||||
ref="queryInput"
|
||||
autofocus
|
||||
density="compact"
|
||||
hide-details
|
||||
clearable
|
||||
:label="$t('searchEngine.query')"
|
||||
@keydown.enter.prevent="runNewSearch" />
|
||||
<HistoryField v-model="selectedTab.query" :history-key="HistoryKey.SEARCH_ENGINE_QUERY" ref="queryInput"
|
||||
autofocus density="compact" hide-details clearable
|
||||
:label="$t('searchEngine.query')" @keydown.enter.prevent="runNewSearch" />
|
||||
</v-col>
|
||||
|
||||
<v-col cols="6" sm="5" md="2">
|
||||
|
|
47
src/stores/history.ts
Normal file
47
src/stores/history.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
import { HistoryKey } from '@/constants/vuetorrent'
|
||||
import { defineStore } from 'pinia'
|
||||
import { reactive, ref } from 'vue'
|
||||
|
||||
type History = Partial<Record<HistoryKey, string[]>>
|
||||
|
||||
export const useHistoryStore = defineStore('history', () => {
|
||||
const _history = reactive<History>({})
|
||||
const historySize = ref(3)
|
||||
|
||||
function pushValueToHistory(key: HistoryKey, value: string) {
|
||||
const historyValue = getHistory(key)
|
||||
historyValue.splice(0, 0, value)
|
||||
|
||||
const valueIndex = historyValue.indexOf(value, 1)
|
||||
if (valueIndex !== -1) {
|
||||
historyValue.splice(valueIndex, 1)
|
||||
}
|
||||
|
||||
if (historyValue.length > historySize.value) {
|
||||
historyValue.splice(historySize.value, historyValue.length - historySize.value)
|
||||
}
|
||||
|
||||
_history[key] = historyValue
|
||||
}
|
||||
|
||||
function getHistory(key: HistoryKey) {
|
||||
return _history[key] || []
|
||||
}
|
||||
|
||||
return {
|
||||
_history,
|
||||
historySize,
|
||||
pushValueToHistory,
|
||||
getHistory
|
||||
}
|
||||
}, {
|
||||
persist: {
|
||||
enabled: true,
|
||||
strategies: [
|
||||
{
|
||||
storage: localStorage,
|
||||
key: 'vuetorrent_history'
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
|
@ -3,6 +3,7 @@ import { useAppStore } from './app'
|
|||
import { useAuthStore } from './auth'
|
||||
import { useDashboardStore } from './dashboard'
|
||||
import { useDialogStore } from './dialog'
|
||||
import { useHistoryStore } from './history'
|
||||
import { useLogStore } from './logs'
|
||||
import { useMaindataStore } from './maindata'
|
||||
import { useNavbarStore } from './navbar'
|
||||
|
@ -18,6 +19,7 @@ export {
|
|||
useAuthStore,
|
||||
useDashboardStore,
|
||||
useDialogStore,
|
||||
useHistoryStore,
|
||||
useLogStore,
|
||||
useMaindataStore,
|
||||
useNavbarStore,
|
||||
|
|
Loading…
Reference in a new issue