Polishing the WebUI code, and reducing bloat.

This commit is contained in:
abdulmohsen
2024-07-01 01:13:51 +03:00
parent 11474316da
commit 6afe125b76
4 changed files with 157 additions and 108 deletions

View File

@@ -0,0 +1,113 @@
<template>
<form @submit.prevent="checkSecret">
<div class="card">
<header class="card-header">
<p class="card-header-title">{{ props.title }}</p>
<p class="card-header-icon"><span class="icon"><i class="fas" :class="props.titleIcon"></i></span></p>
</header>
<div class="card-content">
<div class="field">
<label class="label">
To proceed, please write '<code>{{ randomSecret }}</code>' in the box below.
</label>
<div class="control">
<input class="input" type="text" v-model="userSecret" placeholder="Enter the secret key."/>
</div>
<p class="help" v-if="props.warning">
<span class="icon" :class="props.warningIconClass">
<i class="fas" :class="props.warningIcon"></i>
</span>
{{ props.warning }}
</p>
</div>
</div>
<footer class="card-footer">
<div class="card-footer-item">
<button class="button is-fullwidth" type="submit" :disabled="userSecret !== randomSecret"
:class="userSecret !== randomSecret ? 'is-primary' : 'is-danger'">
<span class="icon">
<i class="fas" :class="userSecret !== randomSecret ? props.lockedButtonIcon : props.unlockedButton "></i>
</span>
<span>
{{ userSecret !== randomSecret ? props.lockedButton : props.unlockedButton }}
</span>
</button>
</div>
</footer>
</div>
</form>
</template>
<script setup>
import {makeSecret, notification} from '~/utils/index'
const props = defineProps({
warning: {
type: String,
required: false
},
warningIcon: {
type: String,
required: false,
default: 'fa-info-circle',
},
warningIconClass: {
type: String,
required: false,
default: 'has-text-warning',
},
title: {
type: String,
required: false,
default: 'Confirm action.',
},
titleIcon: {
type: String,
required: false,
default: 'fa-exclamation-triangle',
},
lockedButton: {
type: String,
required: false,
default: 'Action is locked.',
},
lockedButtonIcon: {
type: String,
required: false,
default: 'fa-lock',
},
unlockedButton: {
type: String,
required: false,
default: 'Perform the requested action.',
},
unlockedButtonIcon: {
type: String,
required: false,
default: 'fa-unlock',
},
length: {
type: Number,
required: false,
default: 8,
},
})
const emit = defineEmits(['confirmed'])
const randomSecret = ref('')
const userSecret = ref('')
const checkSecret = () => {
if (userSecret.value !== randomSecret.value) {
notification('error', 'Error', 'Invalid secret key. Please try again.')
return
}
userSecret.value = ''
emit('confirmed')
}
onMounted(() => randomSecret.value = makeSecret(props.length))
</script>

View File

@@ -53,44 +53,12 @@
<p>There is no undo operation. This action is irreversible.</p> <p>There is no undo operation. This action is irreversible.</p>
</Message> </Message>
<form @submit.prevent="deleteBackend()"> <Confirm @confirmed="deleteBackend()"
<div class="card"> title="Delete backend"
<header class="card-header"> title-icon="fa-trash"
<p class="card-header-title">Delete backend</p> warning="Depending on your hardware speed, the delete operation might take long time. do not interrupt the
<p class="card-header-icon"><span class="icon"><i class="fas fa-trash"></i></span></p>
</header>
<div class="card-content">
<div class="field">
<label class="label">
To confirm, please write '<code>{{ random_secret }}</code>' in the box below.
</label>
<div class="control">
<input class="input" type="text" v-model="user_secret" placeholder="Enter the secret key"/>
</div>
<p class="help">
<span class="icon has-text-warning"><i class="fas fa-info-circle"></i></span>
Depending on your hardware speed, the delete operation might take long time. do not interrupt the
process, or close the browser tab. You will be redirected to the backends page automatically once the process, or close the browser tab. You will be redirected to the backends page automatically once the
process is complete. Otherwise, you might end up with a corrupted database. process is complete. Otherwise, you might end up with a corrupted database."/>
</p>
</div>
</div>
<footer class="card-footer">
<div class="card-footer-item">
<NuxtLink to="/backends/" class="button is-fullwidth is-primary">
<span class="icon"><i class="fas fa-cancel"></i></span>
<span>Cancel</span>
</NuxtLink>
</div>
<div class="card-footer-item">
<button class="button is-danger is-fullwidth" type="submit" :disabled="user_secret !== random_secret">
<span class="icon"><i class="fas fa-redo"></i></span>
<span>Proceed</span>
</button>
</div>
</footer>
</div>
</form>
</div> </div>
</template> </template>
</div> </div>
@@ -99,16 +67,15 @@
<script setup> <script setup>
import 'assets/css/bulma-switch.css' import 'assets/css/bulma-switch.css'
import request from '~/utils/request' import request from '~/utils/request'
import Message from "~/components/Message" import Message from '~/components/Message'
import {makeSecret, notification} from '~/utils/index' import {notification} from '~/utils/index'
import Confirm from '~/components/Confirm'
const id = useRoute().params.backend const id = useRoute().params.backend
const error = ref() const error = ref()
const type = ref('') const type = ref('')
const isLoading = ref(false) const isLoading = ref(false)
const isDeleting = ref(false) const isDeleting = ref(false)
const random_secret = ref('')
const user_secret = ref('')
const loadBackend = async () => { const loadBackend = async () => {
isLoading.value = true isLoading.value = true
@@ -146,11 +113,6 @@ const loadBackend = async () => {
} }
const deleteBackend = async () => { const deleteBackend = async () => {
if (user_secret.value !== random_secret.value) {
notification('error', 'Error', 'Invalid secret key. Please try again.')
return
}
if (!confirm('Last chance! Are you sure you want to delete the backend?')) { if (!confirm('Last chance! Are you sure you want to delete the backend?')) {
return return
} }
@@ -193,8 +155,5 @@ const deleteBackend = async () => {
} }
} }
onMounted(async () => { onMounted(async () => await loadBackend())
await loadBackend()
random_secret.value = makeSecret(8)
})
</script> </script>

View File

@@ -49,46 +49,11 @@
</div> </div>
<div class="column is-12"> <div class="column is-12">
<form @submit.prevent="resetSystem()"> <Confirm @confirmed="resetSystem()"
<div class="card"> title="Perform system reset"
<header class="card-header"> title-icon="fa-redo"
<p class="card-header-title">System reset</p> warning="Depending on your hardware speed, the reset operation might take long time. do not interrupt the process, or close the browser tab. You will be redirected to the index page automatically once the process is complete. Otherwise, you might end up with a corrupted database and/or state."
<p class="card-header-icon"><span class="icon"><i class="fas fa-redo"></i></span></p> />
</header>
<div class="card-content">
<div class="field">
<label class="label">
To confirm, please write '<code>{{ random_secret }}</code>' in the box below.
</label>
<div class="control">
<input class="input" type="text" v-model="user_secret" placeholder="Enter the secret key"/>
</div>
<p class="help">
<span class="icon has-text-warning">
<i class="fas fa-info-circle"></i>
</span>
Depending on your hardware speed, the reset operation might take long time. do not interrupt the
process, or close the browser tab. You will be redirected to the index page automatically once the
process is complete. Otherwise, you might end up with a corrupted database and/or state.
</p>
</div>
</div>
<footer class="card-footer">
<div class="card-footer-item">
<NuxtLink to="/" class="button is-fullwidth is-primary">
<span class="icon"><i class="fas fa-cancel"></i></span>
<span>Cancel</span>
</NuxtLink>
</div>
<div class="card-footer-item">
<button class="button is-danger is-fullwidth" type="submit" :disabled="user_secret !== random_secret">
<span class="icon"><i class="fas fa-redo"></i></span>
<span>Proceed</span>
</button>
</div>
</footer>
</div>
</form>
</div> </div>
</template> </template>
</div> </div>
@@ -98,19 +63,13 @@
import 'assets/css/bulma-switch.css' import 'assets/css/bulma-switch.css'
import request from '~/utils/request' import request from '~/utils/request'
import Message from '~/components/Message' import Message from '~/components/Message'
import {makeSecret, notification} from '~/utils/index' import {notification} from '~/utils/index'
import Confirm from '~/components/Confirm'
const error = ref() const error = ref()
const isResetting = ref(false) const isResetting = ref(false)
const random_secret = ref('')
const user_secret = ref('')
const resetSystem = async () => { const resetSystem = async () => {
if (user_secret.value !== random_secret.value) {
notification('error', 'Error', 'Invalid secret key. Please try again.')
return
}
if (!confirm('Last chance! Are you sure you want to reset the system state?')) { if (!confirm('Last chance! Are you sure you want to reset the system state?')) {
return return
} }
@@ -150,8 +109,4 @@ const resetSystem = async () => {
isResetting.value = false isResetting.value = false
} }
} }
onMounted(() => {
random_secret.value = makeSecret(8)
})
</script> </script>

View File

@@ -18,12 +18,26 @@
<div class="is-hidden-mobile"> <div class="is-hidden-mobile">
<span class="subtitle"> <span class="subtitle">
This page contains all the tasks that are currently configured. This page contains all the tasks that are currently configured.
<template v-if="queued.length > 0">
<p>The following tasks <code>{{ queued.join(', ') }}</code> are queued to be run in background soon.</p>
</template>
</span> </span>
</div> </div>
</div> </div>
<div id="queued_tasks" class="column is-12" v-if="queued.length > 0">
<Message message_class="has-background-success-90 has-text-dark" title="Queued Tasks"
icon="fas fa-circle-notch fa-spin">
<p>
The following tasks
<template v-for="(task, index) in queued" :key="`queued-${index}`">
<NuxtLink :to="`#${task}`">
<span class="tag has-text-dark is-capitalized">{{ task }}</span>
</NuxtLink>
<template v-if="queued.length > index+1">,&nbsp;</template>
</template>
are queued to be run in background soon.
</p>
</Message>
</div>
<div class="column is-12" v-if="isLoading"> <div class="column is-12" v-if="isLoading">
<Message message_class="has-background-info-90 has-text-dark" title="Loading" <Message message_class="has-background-info-90 has-text-dark" title="Loading"
icon="fas fa-spinner fa-spin" message="Loading data. Please wait..."/> icon="fas fa-spinner fa-spin" message="Loading data. Please wait..."/>
@@ -96,7 +110,7 @@
<button class="button is-info" @click="queueTask(task)" <button class="button is-info" @click="queueTask(task)"
:class="{'is-danger':task.queued,'is-info':!task.queued}"> :class="{'is-danger':task.queued,'is-info':!task.queued}">
<span class="icon-text"> <span class="icon-text">
<span class="icon"><i class="fas fa-clock"></i></span> <span class="icon"><i class="fas fa-clock" :class="{ 'fa-spin': task.queued }"></i></span>
<span> <span>
<template v-if="!task.queued">Queue Task</template> <template v-if="!task.queued">Queue Task</template>
<template v-else>Remove from queue</template> <template v-else>Remove from queue</template>
@@ -145,9 +159,9 @@
import 'assets/css/bulma-switch.css' import 'assets/css/bulma-switch.css'
import moment from 'moment' import moment from 'moment'
import request from '~/utils/request' import request from '~/utils/request'
import {notification, TOOLTIP_DATE_FORMAT} from '~/utils/index' import {awaitElement, notification, TOOLTIP_DATE_FORMAT} from '~/utils/index'
import cronstrue from 'cronstrue' import cronstrue from 'cronstrue'
import Message from '~/components/Message.vue' import Message from '~/components/Message'
import {useStorage} from '@vueuse/core' import {useStorage} from '@vueuse/core'
useHead({title: 'Tasks'}) useHead({title: 'Tasks'})
@@ -206,6 +220,14 @@ const queueTask = async task => {
} else { } else {
queued.value = queued.value.filter(t => t !== task.name) queued.value = queued.value.filter(t => t !== task.name)
} }
if (true === task.queued) {
awaitElement('#queued_tasks', (_, e) => e.scrollIntoView({
behavior: 'smooth',
block: 'start',
inline: 'nearest'
}))
}
} }
} catch (e) { } catch (e) {
notification('error', 'Error', `Request error. ${e.message}`) notification('error', 'Error', `Request error. ${e.message}`)