Polishing the WebUI code, and reducing bloat.
This commit is contained in:
113
frontend/components/Confirm.vue
Normal file
113
frontend/components/Confirm.vue
Normal 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>
|
||||
@@ -53,44 +53,12 @@
|
||||
<p>There is no undo operation. This action is irreversible.</p>
|
||||
</Message>
|
||||
|
||||
<form @submit.prevent="deleteBackend()">
|
||||
<div class="card">
|
||||
<header class="card-header">
|
||||
<p class="card-header-title">Delete backend</p>
|
||||
<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
|
||||
<Confirm @confirmed="deleteBackend()"
|
||||
title="Delete backend"
|
||||
title-icon="fa-trash"
|
||||
warning="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 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>
|
||||
process is complete. Otherwise, you might end up with a corrupted database."/>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@@ -99,16 +67,15 @@
|
||||
<script setup>
|
||||
import 'assets/css/bulma-switch.css'
|
||||
import request from '~/utils/request'
|
||||
import Message from "~/components/Message"
|
||||
import {makeSecret, notification} from '~/utils/index'
|
||||
import Message from '~/components/Message'
|
||||
import {notification} from '~/utils/index'
|
||||
import Confirm from '~/components/Confirm'
|
||||
|
||||
const id = useRoute().params.backend
|
||||
const error = ref()
|
||||
const type = ref('')
|
||||
const isLoading = ref(false)
|
||||
const isDeleting = ref(false)
|
||||
const random_secret = ref('')
|
||||
const user_secret = ref('')
|
||||
|
||||
const loadBackend = async () => {
|
||||
isLoading.value = true
|
||||
@@ -146,11 +113,6 @@ const loadBackend = 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?')) {
|
||||
return
|
||||
}
|
||||
@@ -193,8 +155,5 @@ const deleteBackend = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await loadBackend()
|
||||
random_secret.value = makeSecret(8)
|
||||
})
|
||||
onMounted(async () => await loadBackend())
|
||||
</script>
|
||||
|
||||
@@ -49,46 +49,11 @@
|
||||
</div>
|
||||
|
||||
<div class="column is-12">
|
||||
<form @submit.prevent="resetSystem()">
|
||||
<div class="card">
|
||||
<header class="card-header">
|
||||
<p class="card-header-title">System reset</p>
|
||||
<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>
|
||||
<Confirm @confirmed="resetSystem()"
|
||||
title="Perform system reset"
|
||||
title-icon="fa-redo"
|
||||
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."
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@@ -98,19 +63,13 @@
|
||||
import 'assets/css/bulma-switch.css'
|
||||
import request from '~/utils/request'
|
||||
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 isResetting = ref(false)
|
||||
const random_secret = ref('')
|
||||
const user_secret = ref('')
|
||||
|
||||
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?')) {
|
||||
return
|
||||
}
|
||||
@@ -150,8 +109,4 @@ const resetSystem = async () => {
|
||||
isResetting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
random_secret.value = makeSecret(8)
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -18,12 +18,26 @@
|
||||
<div class="is-hidden-mobile">
|
||||
<span class="subtitle">
|
||||
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>
|
||||
</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">, </template>
|
||||
</template>
|
||||
are queued to be run in background soon.
|
||||
</p>
|
||||
</Message>
|
||||
</div>
|
||||
|
||||
<div class="column is-12" v-if="isLoading">
|
||||
<Message message_class="has-background-info-90 has-text-dark" title="Loading"
|
||||
icon="fas fa-spinner fa-spin" message="Loading data. Please wait..."/>
|
||||
@@ -96,7 +110,7 @@
|
||||
<button class="button is-info" @click="queueTask(task)"
|
||||
:class="{'is-danger':task.queued,'is-info':!task.queued}">
|
||||
<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>
|
||||
<template v-if="!task.queued">Queue Task</template>
|
||||
<template v-else>Remove from queue</template>
|
||||
@@ -145,9 +159,9 @@
|
||||
import 'assets/css/bulma-switch.css'
|
||||
import moment from 'moment'
|
||||
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 Message from '~/components/Message.vue'
|
||||
import Message from '~/components/Message'
|
||||
import {useStorage} from '@vueuse/core'
|
||||
|
||||
useHead({title: 'Tasks'})
|
||||
@@ -206,6 +220,14 @@ const queueTask = async task => {
|
||||
} else {
|
||||
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) {
|
||||
notification('error', 'Error', `Request error. ${e.message}`)
|
||||
|
||||
Reference in New Issue
Block a user