improve the simple view flow and change settings render to work on both
This commit is contained in:
parent
4d16618cfb
commit
1fd7477a9c
15 changed files with 159 additions and 88 deletions
|
|
@ -358,6 +358,10 @@ div.is-centered {
|
|||
justify-content: center;
|
||||
}
|
||||
|
||||
.is-overflow-visible {
|
||||
overflow: visible !important
|
||||
}
|
||||
|
||||
.modal-content-max {
|
||||
width: calc(100% - 20px);
|
||||
max-width: 1344px;
|
||||
|
|
|
|||
|
|
@ -268,6 +268,7 @@ import { useStorage } from '@vueuse/core'
|
|||
import TextareaAutocomplete from '~/components/TextareaAutocomplete.vue'
|
||||
import type { AutoCompleteOptions } from '~/types/autocomplete';
|
||||
import type { ConditionItem, ImportedConditionItem } from '~/types/conditions'
|
||||
import {useConfirm} from '~/composables/useConfirm'
|
||||
|
||||
const emitter = defineEmits<{
|
||||
(e: 'cancel'): void
|
||||
|
|
@ -410,7 +411,7 @@ const importItem = async (): Promise<void> => {
|
|||
return
|
||||
}
|
||||
|
||||
if ((form.filter || form.cli || Object.keys(form.extras).length > 0) && !(await box.confirm('Overwrite the current form fields?', true))) {
|
||||
if ((form.filter || form.cli || Object.keys(form.extras).length > 0) && !(await box.confirm('Overwrite the current form fields?'))) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -450,6 +450,7 @@
|
|||
import moment from 'moment'
|
||||
import { useStorage } from '@vueuse/core'
|
||||
import type { StoreItem } from '~/types/store'
|
||||
import {useConfirm} from '~/composables/useConfirm'
|
||||
|
||||
const emitter = defineEmits<{
|
||||
(e: 'getInfo', url: string, preset: string, cli: string): void
|
||||
|
|
@ -588,7 +589,7 @@ const deleteSelectedItems = async () => {
|
|||
if (true === config.app.remove_files) {
|
||||
msg += ' This will remove any associated files if they exists.'
|
||||
}
|
||||
if (false === (await box.confirm(msg, config.app.remove_files))) {
|
||||
if (false === (await box.confirm(msg))) {
|
||||
return
|
||||
}
|
||||
for (const key in selectedElms.value) {
|
||||
|
|
@ -750,7 +751,7 @@ const removeItem = async (item: StoreItem) => {
|
|||
if (item.status === 'finished' && config.app.remove_files) {
|
||||
msg += ' This will remove any associated files if they exists.'
|
||||
}
|
||||
if (false === (await box.confirm(msg, Boolean(item.filename && config.app.remove_files)))) {
|
||||
if (false === (await box.confirm(msg))) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -308,6 +308,7 @@
|
|||
<script setup lang="ts">
|
||||
import { useStorage } from '@vueuse/core'
|
||||
import type { notification, notificationImport } from '~/types/notification'
|
||||
import {useConfirm} from '~/composables/useConfirm'
|
||||
|
||||
const emitter = defineEmits(['cancel', 'submit'])
|
||||
const toast = useNotification()
|
||||
|
|
@ -412,7 +413,7 @@ const importItem = async () => {
|
|||
}
|
||||
|
||||
if (form.name || form.request?.url) {
|
||||
if (false === (await box.confirm('Overwrite the current form fields?', true))) {
|
||||
if (false === (await box.confirm('Overwrite the current form fields?'))) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -313,6 +313,7 @@
|
|||
import moment from 'moment'
|
||||
import { useStorage } from '@vueuse/core'
|
||||
import type { StoreItem } from '~/types/store'
|
||||
import {useConfirm} from '~/composables/useConfirm'
|
||||
|
||||
const emitter = defineEmits<{
|
||||
(e: 'getInfo', url: string, preset: string, cli: string): void
|
||||
|
|
|
|||
|
|
@ -12,6 +12,26 @@
|
|||
<div class="columns is-multiline">
|
||||
<div class="column is-6">
|
||||
|
||||
<div class="field">
|
||||
<label class="label is-unselectable">Page View</label>
|
||||
<div class="control">
|
||||
<label for="ui_advanced" class="radio">
|
||||
<input id="ui_advanced" type="radio" v-model="simpleMode" :value="false">
|
||||
<span class="icon"><i class="fa-solid fa-computer" /></span>
|
||||
Regular View
|
||||
</label>
|
||||
<label for="ui_simple" class="radio">
|
||||
<input id="ui_simple" type="radio" v-model="simpleMode" :value="true">
|
||||
<span class="icon"><i class="fa-solid fa-mobile-screen-button" /></span>
|
||||
Simple View (Experimental)
|
||||
</label>
|
||||
</div>
|
||||
<p class="help is-bold has-text-danger">
|
||||
<span class="icon"> <i class="fa-solid fa-info-circle" /></span>
|
||||
The simple view is experimental and will change without notice and maybe even deleted in the future.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label is-unselectable">Color scheme</label>
|
||||
<div class="control">
|
||||
|
|
@ -35,7 +55,7 @@
|
|||
|
||||
<div class="field">
|
||||
<label class="label is-unselectable">
|
||||
Backgrounds
|
||||
Show Background
|
||||
<template v-if="bg_enable">
|
||||
<NuxtLink @click="$emit('reload_bg')" class="is-bold">Reload</NuxtLink>
|
||||
<span class="icon" v-if="isLoading"><i class="fa fa-spin fa-spinner" /></span>
|
||||
|
|
@ -44,7 +64,7 @@
|
|||
<div class="control">
|
||||
<input id="random_bg" type="checkbox" class="switch is-success" v-model="bg_enable">
|
||||
<label for="random_bg" class="is-unselectable">
|
||||
{{ bg_enable ? 'Enabled' : 'Disabled' }}
|
||||
{{ bg_enable ? 'Yes' : 'No' }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -59,17 +79,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label is-unselectable" for="show_thumbnail">Show Videos Thumbnail when possible</label>
|
||||
<div class="control">
|
||||
<input id="show_thumbnail" type="checkbox" class="switch is-success" v-model="show_thumbnail">
|
||||
<label for="show_thumbnail" class="is-unselectable">
|
||||
{{ show_thumbnail ? 'Enabled' : 'Disabled' }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<div class="field" v-if="!simpleMode">
|
||||
<label class="label is-unselectable" for="show_thumbnail">URLs Separator</label>
|
||||
<div class="control">
|
||||
<div class="select is-fullwidth">
|
||||
|
|
@ -85,27 +95,28 @@
|
|||
</div>
|
||||
<div class="column is-6">
|
||||
<div class="field">
|
||||
<label class="label is-unselectable" for="reduce_confirm">Reduce confirm box usage</label>
|
||||
<label class="label is-unselectable" for="show_thumbnail">Show Thumbnails</label>
|
||||
<div class="control">
|
||||
<input id="reduce_confirm" type="checkbox" class="switch is-success" v-model="reduce_confirm">
|
||||
<label for="reduce_confirm" class="is-unselectable">
|
||||
{{ reduce_confirm ? 'Enabled' : 'Disabled' }}
|
||||
<input id="show_thumbnail" type="checkbox" class="switch is-success" v-model="show_thumbnail">
|
||||
<label for="show_thumbnail" class="is-unselectable">
|
||||
{{ show_thumbnail ? 'Yes' : 'No' }}
|
||||
</label>
|
||||
</div>
|
||||
<p class="help is-bold"> Show videos thumbnail if available.</p>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label" for="allow_toasts">Show notifications toasts</label>
|
||||
<label class="label" for="allow_toasts">Show notifications</label>
|
||||
<div class="control">
|
||||
<input id="allow_toasts" type="checkbox" class="switch is-success" v-model="allow_toasts">
|
||||
<label for="allow_toasts" class="is-unselectable">
|
||||
{{ allow_toasts ? 'Enabled' : 'Disabled' }}
|
||||
{{ allow_toasts ? 'Yes' : 'No' }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field" v-if="allow_toasts">
|
||||
<label class="label">Toasts position</label>
|
||||
<label class="label">Notification position</label>
|
||||
<div class="control">
|
||||
<div class="select is-fullwidth">
|
||||
<select v-model="toast_position">
|
||||
|
|
@ -121,12 +132,12 @@
|
|||
</div>
|
||||
|
||||
<div class="field" v-if="allow_toasts">
|
||||
<label class="label" for="dismiss_on_click">Dismiss toasts on click</label>
|
||||
<label class="label" for="dismiss_on_click">Dismiss notification on click</label>
|
||||
<div class="control">
|
||||
<input id="dismiss_on_click" type="checkbox" class="switch is-success"
|
||||
v-model="toast_dismiss_on_click">
|
||||
<label for="dismiss_on_click" class="is-unselectable">
|
||||
{{ toast_dismiss_on_click ? 'Enabled' : 'Disabled' }}
|
||||
{{ toast_dismiss_on_click ? 'Yes' : 'No' }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -142,6 +153,7 @@
|
|||
<script setup lang="ts">
|
||||
import { useStorage } from '@vueuse/core'
|
||||
import { POSITION } from 'vue-toastification'
|
||||
import { useConfigStore } from '~/stores/ConfigStore'
|
||||
|
||||
defineProps<{ isLoading: boolean }>()
|
||||
defineEmits<{ (e: 'reload_bg'): void }>()
|
||||
|
|
@ -150,9 +162,9 @@ const bg_enable = useStorage<boolean>('random_bg', true)
|
|||
const bg_opacity = useStorage<number>('random_bg_opacity', 0.95)
|
||||
const selectedTheme = useStorage<'auto' | 'light' | 'dark'>('theme', 'auto')
|
||||
const allow_toasts = useStorage<boolean>('allow_toasts', true)
|
||||
const reduce_confirm = useStorage<boolean>('reduce_confirm', false)
|
||||
const toast_position = useStorage<POSITION>('toast_position', POSITION.TOP_RIGHT)
|
||||
const toast_dismiss_on_click = useStorage<boolean>('toast_dismiss_on_click', true)
|
||||
const show_thumbnail = useStorage<boolean>('show_thumbnail', true)
|
||||
const separator = useStorage<string>('url_separator', separators[0]?.value ?? ',')
|
||||
const simpleMode = useStorage<boolean>('simple_mode', useConfigStore().app.simple_mode || false)
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -3,8 +3,19 @@
|
|||
<div class="form-container" :class="{ 'is-centered': shouldCenterForm }">
|
||||
<section class="download-form box">
|
||||
<form class="download-form__body" autocomplete="off" @submit.prevent="addDownload">
|
||||
<label class="label" for="download-url">What you would like to download?</label>
|
||||
<label class="label" for="download-url">
|
||||
What you would like to download?
|
||||
<span class="is-pulled-right">
|
||||
<span class="icon has-text-primary is-pointer" @click="$emit('show_settings')" v-tooltip="'Settings'"><i
|
||||
class="fas fa-cogs" /></span>
|
||||
</span>
|
||||
</label>
|
||||
<div class="field has-addons">
|
||||
<div class="control">
|
||||
<button type="button" class="button is-info" @click="() => showPresets = !showPresets">
|
||||
<span class="icon"><i class="fas" :class="showPresets ? 'fa-chevron-up' : 'fa-chevron-down'" /></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="control is-expanded">
|
||||
<input id="download-url" v-model="formUrl" :disabled="!socketStore.isConnected || addInProgress"
|
||||
class="input" placeholder="https://..." type="url" required>
|
||||
|
|
@ -12,11 +23,37 @@
|
|||
<div class="control">
|
||||
<button type="submit" class="button is-primary" :class="{ 'is-loading': addInProgress }"
|
||||
:disabled="!socketStore.isConnected || addInProgress || !formUrl.trim()">
|
||||
<span class="icon"><i class="fa-solid fa-plus" /></span>
|
||||
<span class="icon"><i class="fas fa-plus" /></span>
|
||||
<span>Add</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field has-addons" v-if="showPresets">
|
||||
<div class="control">
|
||||
<label class="button is-static">
|
||||
<span class="icon"><i class="fas fa-sliders" /></span>
|
||||
<span>Preset</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="control is-expanded">
|
||||
<div class="select is-fullwidth">
|
||||
<select id="preset" class="is-fullwidth" :disabled="!socketStore.isConnected || addInProgress"
|
||||
v-model="formPreset.preset">
|
||||
<optgroup label="Custom presets" v-if="presets.filter(p => !p?.default).length > 0">
|
||||
<option v-for="cPreset in filter_presets(false)" :key="cPreset.name" :value="cPreset.name">
|
||||
{{ cPreset.name }}
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup label="Default presets">
|
||||
<option v-for="dPreset in filter_presets(true)" :key="dPreset.name" :value="dPreset.name">
|
||||
{{ dPreset.name }}
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
|
|
@ -26,12 +63,12 @@
|
|||
<TransitionGroup name="queue-card" tag="div" class="columns is-multiline queue-card-columns">
|
||||
<div v-for="entry in displayItems" :key="entry.item._id" class="column is-12-mobile is-6-tablet">
|
||||
<article class="queue-card card" :class="{ 'is-history': 'history' === entry.source }">
|
||||
<div v-if="'queue' === entry.source && shouldShowProgress(entry.item)"
|
||||
class="progress-bar is-unselectable mb-3">
|
||||
<div class="progress-percentage">{{ updateProgress(entry.item) }}</div>
|
||||
<div class="progress" :style="{ width: getProgressWidth(entry.item) }"></div>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div v-if="'queue' === entry.source && shouldShowProgress(entry.item)"
|
||||
class="progress-bar is-unselectable mb-3">
|
||||
<div class="progress-percentage">{{ updateProgress(entry.item) }}</div>
|
||||
<div class="progress" :style="{ width: getProgressWidth(entry.item) }"></div>
|
||||
</div>
|
||||
<article class="media">
|
||||
<figure class="media-left">
|
||||
<figure class="image is-16by9 queue-thumb" :class="{ 'is-clickable': isEmbedable(entry.item.url) }"
|
||||
|
|
@ -40,7 +77,7 @@
|
|||
<span
|
||||
v-if="entry.item.filename && entry.item.status === 'finished' || isEmbedable(entry.item.url)"
|
||||
class="queue-thumb__overlay">
|
||||
<span class="icon has-text-white"><i class="fa-solid fa-play" /></span>
|
||||
<span class="icon has-text-white"><i class="fas fa-play" /></span>
|
||||
</span>
|
||||
</figure>
|
||||
</figure>
|
||||
|
|
@ -48,7 +85,7 @@
|
|||
<p class="title is-6 mb-0 queue-title">
|
||||
<NuxtLink target="_blank" :href="entry.item.url">{{ entry.item.title }}</NuxtLink>
|
||||
</p>
|
||||
<div class="field is-grouped">
|
||||
<div class="field is-grouped is-unselectable">
|
||||
<div class="control">
|
||||
<span class="tag is-size-7 has-text-weight-semibold is-uppercase"
|
||||
:class="getSourceTagClass(entry)">
|
||||
|
|
@ -56,32 +93,32 @@
|
|||
</span>
|
||||
</div>
|
||||
<div class="control">
|
||||
<span class="tag is-size-7 has-text-weight-semibold" :class="getStatusClass(entry.item)">{{
|
||||
getStatusLabel(entry.item) }}</span>
|
||||
<span class="tag is-size-7 has-text-weight-semibold" :class="getStatusClass(entry.item)">
|
||||
{{ getStatusLabel(entry.item) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="control">
|
||||
<span class="tag" :date-datetime="entry.item.datetime" v-rtime="entry.item.datetime" />
|
||||
</div>
|
||||
</div>
|
||||
<p v-if="getDescription(entry.item)" class="content is-size-7 has-text-grey queue-description">
|
||||
{{ getDescription(entry.item) }}
|
||||
<p class="content is-size-7 has-text-grey queue-description">
|
||||
{{ getDescription(entry.item) || 'No description available.' }}
|
||||
</p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<div v-if="'queue' === entry.source" class="buttons are-small is-right is-flex-wrap-wrap mt-3">
|
||||
<button v-if="canStart(entry.item)" class="button is-success is-light" type="button"
|
||||
@click="startQueueItem(entry.item)">
|
||||
<span class="icon"><i class="fa-solid fa-circle-play" /></span>
|
||||
<span class="icon"><i class="fas fa-circle-play" /></span>
|
||||
<span>Start</span>
|
||||
</button>
|
||||
<button v-if="canPause(entry.item)" class="button is-warning is-light" type="button"
|
||||
@click="pauseQueueItem(entry.item)">
|
||||
<span class="icon"><i class="fa-solid fa-pause" /></span>
|
||||
<span class="icon"><i class="fas fa-pause" /></span>
|
||||
<span>Pause</span>
|
||||
</button>
|
||||
<button class="button is-warning" type="button" @click="cancelDownload(entry.item)">
|
||||
<span class="icon"><i class="fa-solid fa-xmark" /></span>
|
||||
<span class="icon"><i class="fas fa-xmark" /></span>
|
||||
<span>Cancel</span>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -89,16 +126,16 @@
|
|||
<div v-else class="buttons are-small is-right is-flex-wrap-wrap mt-3">
|
||||
<a v-if="getDownloadLink(entry.item)" class="button is-link" :href="getDownloadLink(entry.item)"
|
||||
:download="getDownloadName(entry.item)">
|
||||
<span class="icon"><i class="fa-solid fa-download" /></span>
|
||||
<span class="icon"><i class="fas fa-download" /></span>
|
||||
<span>Download</span>
|
||||
</a>
|
||||
<button v-if="entry.item.status != 'finished' || !entry.item.filename" class="button is-info is-light"
|
||||
type="button" @click="requeueItem(entry.item)">
|
||||
<span class="icon"><i class="fa-solid fa-rotate-right" /></span>
|
||||
<span class="icon"><i class="fas fa-rotate-right" /></span>
|
||||
<span>Requeue</span>
|
||||
</button>
|
||||
<button class="button is-danger" type="button" @click="deleteHistoryItem(entry.item)">
|
||||
<span class="icon"><i class="fa-solid fa-trash" /></span>
|
||||
<span class="icon"><i class="fas fa-trash" /></span>
|
||||
<span>Delete</span>
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -132,6 +169,7 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useStorage } from '@vueuse/core'
|
||||
import type { item_request } from '~/types/item'
|
||||
import type { ItemStatus, StoreItem } from '~/types/store'
|
||||
import { useNotification } from '~/composables/useNotification'
|
||||
|
|
@ -142,19 +180,24 @@ import { isEmbedable, getEmbedable } from '~/utils/embedable'
|
|||
import EmbedPlayer from '~/components/EmbedPlayer.vue'
|
||||
import { ag, encodePath, makeDownload, request, stripPath, ucFirst, uri } from '~/utils'
|
||||
|
||||
defineEmits<{ (e: 'show_settings'): void }>()
|
||||
|
||||
const configStore = useConfigStore()
|
||||
const stateStore = useStateStore()
|
||||
const socketStore = useSocketStore()
|
||||
const toast = useNotification()
|
||||
|
||||
const { app, paused } = storeToRefs(configStore)
|
||||
const { app, paused, presets } = storeToRefs(configStore)
|
||||
const { queue, history } = storeToRefs(stateStore)
|
||||
|
||||
const embedUrl = ref<string>('')
|
||||
const videoItem = ref<StoreItem | null>(null)
|
||||
|
||||
const formUrl = ref<string>('')
|
||||
const formPreset = ref<{ preset: string }>({ preset: app.value.default_preset || '' })
|
||||
const addInProgress = ref<boolean>(false)
|
||||
const showPresets = ref<boolean>(false)
|
||||
const show_thumbnail = useStorage<boolean>('show_thumbnail', true)
|
||||
|
||||
const sortByNewest = (items: StoreItem[]): StoreItem[] => items.slice().sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0))
|
||||
|
||||
|
|
@ -189,7 +232,7 @@ const addDownload = async (): Promise<void> => {
|
|||
|
||||
const payload: item_request[] = [{
|
||||
url,
|
||||
preset: app.value.default_preset,
|
||||
preset: formPreset.value.preset || app.value.default_preset,
|
||||
auto_start: true,
|
||||
}]
|
||||
|
||||
|
|
@ -212,8 +255,8 @@ const addDownload = async (): Promise<void> => {
|
|||
return
|
||||
}
|
||||
|
||||
toast.success('Added to queue.')
|
||||
formUrl.value = ''
|
||||
formPreset.value.preset = app.value.default_preset || ''
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : 'Failed to add download.'
|
||||
toast.error(message)
|
||||
|
|
@ -223,6 +266,10 @@ const addDownload = async (): Promise<void> => {
|
|||
}
|
||||
|
||||
const resolveThumbnail = (entry: DisplayEntry): string => {
|
||||
if (!show_thumbnail.value) {
|
||||
return '/images/placeholder.png'
|
||||
}
|
||||
|
||||
const { item, source } = entry
|
||||
|
||||
const sidecarImage = item.sidecar?.image?.[0]?.file
|
||||
|
|
@ -463,6 +510,8 @@ const deleteHistoryItem = (item: StoreItem): void => {
|
|||
socketStore.emit('item_delete', { id: item._id, remove_file: app.value.remove_files })
|
||||
toast.info('Removed from history queue.')
|
||||
}
|
||||
|
||||
const filter_presets = (flag: boolean = true) => presets.value.filter(item => item.default === flag)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
@ -608,4 +657,8 @@ const deleteHistoryItem = (item: StoreItem): void => {
|
|||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
border-radius: 0.75rem 0.75rem 0 0
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -307,6 +307,7 @@ import { CronExpressionParser } from 'cron-parser'
|
|||
import TextareaAutocomplete from '~/components/TextareaAutocomplete.vue'
|
||||
import type { AutoCompleteOptions } from '~/types/autocomplete'
|
||||
import type { exported_task, task_item } from '~/types/tasks'
|
||||
import {useConfirm} from '~/composables/useConfirm'
|
||||
|
||||
const props = defineProps<{
|
||||
reference?: string | null | undefined
|
||||
|
|
@ -408,7 +409,7 @@ const importItem = async (): Promise<void> => {
|
|||
}
|
||||
|
||||
if (form.url || form.timer) {
|
||||
if (false === (await box.confirm('Overwrite the current form fields?', true))) {
|
||||
if (false === (await box.confirm('Overwrite the current form fields?'))) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +1,29 @@
|
|||
import { useStorage } from '@vueuse/core'
|
||||
import { useDialog } from './useDialog'
|
||||
import { useDialog, type ConfirmOptions, type AlertOptions, type PromptOptions } from './useDialog'
|
||||
|
||||
const dialog = useDialog()
|
||||
|
||||
const reduceConfirm = useStorage<boolean>('reduce_confirm', false)
|
||||
|
||||
const confirm = async (msg: string, force: boolean = false) => {
|
||||
if (false === force && true === reduceConfirm.value) {
|
||||
return true
|
||||
}
|
||||
|
||||
const { status } = await dialog.confirmDialog({
|
||||
const confirm = async (msg: string, opts: ConfirmOptions = {}) => {
|
||||
const { status } = await dialog.confirmDialog(Object.assign({
|
||||
title: 'Please Confirm',
|
||||
message: msg,
|
||||
cancelText: 'Cancel',
|
||||
confirmText: 'OK',
|
||||
})
|
||||
} as ConfirmOptions, opts || {}))
|
||||
|
||||
return status
|
||||
}
|
||||
|
||||
const alert = async (msg: string) => {
|
||||
const { status } = await dialog.alertDialog({
|
||||
const alert = async (msg: string, opts: AlertOptions = {}) => {
|
||||
const { status } = await dialog.alertDialog(Object.assign({
|
||||
title: 'Alert',
|
||||
message: msg,
|
||||
confirmText: 'OK',
|
||||
})
|
||||
} as AlertOptions, opts || {}))
|
||||
return status
|
||||
}
|
||||
|
||||
const prompt = async (msg: string, defaultValue: string = '') => {
|
||||
const { status, value } = await dialog.promptDialog({
|
||||
title: 'Input Required',
|
||||
message: msg,
|
||||
initial: defaultValue,
|
||||
cancelText: 'Cancel',
|
||||
confirmText: 'OK',
|
||||
})
|
||||
const prompt = async (msg: string, opts: PromptOptions = {}) => {
|
||||
const { status, value } = await dialog.promptDialog(Object.assign({ message: msg } as PromptOptions, opts || {}))
|
||||
|
||||
if (status) {
|
||||
return value
|
||||
|
|
@ -45,6 +32,4 @@ const prompt = async (msg: string, defaultValue: string = '') => {
|
|||
return null
|
||||
}
|
||||
|
||||
export default function useConfirm() {
|
||||
return { confirm, alert, prompt, reduceConfirm }
|
||||
}
|
||||
export const useConfirm = () => ({ confirm, alert, prompt })
|
||||
|
|
|
|||
|
|
@ -1,8 +1,16 @@
|
|||
<template>
|
||||
<template v-if="config.app.simple_mode">
|
||||
<Simple />
|
||||
|
||||
<template v-if="simpleMode">
|
||||
<Simple @show_settings="() => show_settings = true" />
|
||||
</template>
|
||||
<template v-else>
|
||||
|
||||
<template v-if="show_settings">
|
||||
<Modal @close="show_settings = false" content-class="modal-content-max is-overflow-visible">
|
||||
<Settings v-if="show_settings" :isLoading="loadingImage" @reload_bg="() => loadImage(true)" />
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<template v-if="!simpleMode">
|
||||
<Shutdown v-if="app_shutdown" />
|
||||
<div id="main_container" class="container" v-else>
|
||||
<NewVersion v-if="newVersionIsAvailable" />
|
||||
|
|
@ -124,11 +132,9 @@
|
|||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div>
|
||||
<Settings v-if="show_settings" :isLoading="loadingImage" @reload_bg="() => loadImage(true)" />
|
||||
<NuxtLoadingIndicator />
|
||||
<NuxtPage v-if="!config.app.simple_mode && config.is_loaded" />
|
||||
<NuxtPage v-if="config.is_loaded" />
|
||||
<Message v-if="!config.is_loaded" class="has-background-info-90 has-text-dark mt-5"
|
||||
title="Loading Configuration" icon="fas fa-spinner fa-spin">
|
||||
<p>Loading application configuration. This usually takes less than a second.</p>
|
||||
|
|
@ -197,6 +203,8 @@ const bg_opacity = useStorage('random_bg_opacity', 0.95)
|
|||
const showMenu = ref(false)
|
||||
const isMobile = useMediaQuery({ maxWidth: 1024 })
|
||||
const app_shutdown = ref<boolean>(false)
|
||||
const simpleMode = useStorage<boolean>('simple_mode', config.app.simple_mode || false)
|
||||
|
||||
const doc = ref<{ file: string }>({ file: '' })
|
||||
|
||||
const applyPreferredColorScheme = (scheme: string) => {
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import type { ConditionItem, ImportedConditionItem } from '~/types/conditions'
|
||||
import {useConfirm} from '~/composables/useConfirm'
|
||||
|
||||
type ConditionItemWithUI = ConditionItem & { raw?: boolean }
|
||||
|
||||
|
|
@ -226,7 +227,7 @@ const updateItems = async (newItems: ConditionItem[]): Promise<boolean> => {
|
|||
}
|
||||
|
||||
const deleteItem = async (cond: ConditionItem): Promise<void> => {
|
||||
if (true !== (await box.confirm(`Delete '${cond.name}'?`, true))) {
|
||||
if (true !== (await box.confirm(`Delete '${cond.name}'?`))) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -219,6 +219,7 @@
|
|||
<script setup lang="ts">
|
||||
import { useStorage } from '@vueuse/core'
|
||||
import type { notification, notificationImport } from '~/types/notification'
|
||||
import {useConfirm} from '~/composables/useConfirm'
|
||||
|
||||
const toast = useNotification()
|
||||
const socket = useSocketStore()
|
||||
|
|
|
|||
|
|
@ -204,6 +204,7 @@
|
|||
<script setup lang="ts">
|
||||
import { useStorage } from '@vueuse/core'
|
||||
import type { Preset } from '~/types/presets'
|
||||
import {useConfirm} from '~/composables/useConfirm'
|
||||
|
||||
const toast = useNotification()
|
||||
const config = useConfigStore()
|
||||
|
|
@ -295,7 +296,7 @@ const updatePresets = async (items: Preset[]): Promise<boolean | undefined> => {
|
|||
}
|
||||
|
||||
const deleteItem = async (item: Preset) => {
|
||||
if (true !== (await box.confirm(`Delete preset '${item.name}'?`, true))) {
|
||||
if (true !== (await box.confirm(`Delete preset '${item.name}'?`))) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -402,6 +402,7 @@ import moment from 'moment'
|
|||
import { useStorage } from '@vueuse/core'
|
||||
import { CronExpressionParser } from 'cron-parser'
|
||||
import Modal from '~/components/Modal.vue'
|
||||
import { useConfirm } from '~/composables/useConfirm'
|
||||
import TaskInspect from '~/components/TaskInspect.vue'
|
||||
import type { task_item, exported_task, error_response } from '~/types/tasks'
|
||||
|
||||
|
|
@ -595,7 +596,7 @@ const deleteSelected = async () => {
|
|||
}
|
||||
|
||||
const deleteItem = async (item: task_item) => {
|
||||
if (true !== (await box.confirm(`Delete '${item.name}' task?`, true))) {
|
||||
if (true !== (await box.confirm(`Delete '${item.name}' task?`))) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
6
uv.lock
6
uv.lock
|
|
@ -875,15 +875,15 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "pyinstaller-hooks-contrib"
|
||||
version = "2025.8"
|
||||
version = "2025.9"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "packaging" },
|
||||
{ name = "setuptools" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/71/d6/e5b378b7d4add8c879295c531309b0320e9c07a70458665d091760ffdc87/pyinstaller_hooks_contrib-2025.8.tar.gz", hash = "sha256:3402ad41dfe9b5110af134422e37fc5d421ba342c6cb980bd67cb30b7415641c", size = 164214 }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7d/83/be0f57c0b77b66c33c2283ebd4ea341022b5a743e97c5fb3bebab82b38b9/pyinstaller_hooks_contrib-2025.9.tar.gz", hash = "sha256:56e972bdaad4e9af767ed47d132362d162112260cbe488c9da7fee01f228a5a6", size = 165189 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/48/34/1d973d0dae849683e53fbcda84443ce016f315e6f4dc7605ede4f56a28c3/pyinstaller_hooks_contrib-2025.8-py3-none-any.whl", hash = "sha256:8d0b8cfa0cb689a619294ae200497374234bd4e3994b3ace2a4442274c899064", size = 442346 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/26/23b4cfc77d7f808c69f59070e1e8293a579ec281a547c61562357160b346/pyinstaller_hooks_contrib-2025.9-py3-none-any.whl", hash = "sha256:ccbfaa49399ef6b18486a165810155e5a8d4c59b41f20dc5da81af7482aaf038", size = 444283 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
Loading…
Reference in a new issue