Added confirmation box to backend delete back.
This commit is contained in:
74
frontend/components/Lazy.vue
Normal file
74
frontend/components/Lazy.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<div ref="targetEl" :style="`min-height:${fixedMinHeight ? fixedMinHeight : (minHeight ?? min_height)}px`">
|
||||
<slot v-if="shouldRender"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {nextTick, ref} from 'vue'
|
||||
import {useIntersectionObserver} from '@vueuse/core'
|
||||
|
||||
function onIdle(cb = () => {
|
||||
}) {
|
||||
if ("requestIdleCallback" in window) {
|
||||
window.requestIdleCallback(cb);
|
||||
} else {
|
||||
setTimeout(() => nextTick(cb), 300);
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
props: {
|
||||
renderOnIdle: Boolean,
|
||||
unrender: Boolean,
|
||||
minHeight: Number,
|
||||
unrenderDelay: {
|
||||
type: Number,
|
||||
default: 6000,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const shouldRender = ref(false);
|
||||
const targetEl = ref();
|
||||
const fixedMinHeight = ref(0);
|
||||
let unrenderTimer;
|
||||
let renderTimer;
|
||||
|
||||
const {stop} = useIntersectionObserver(targetEl, ([{isIntersecting}]) => {
|
||||
if (isIntersecting) {
|
||||
// perhaps the user re-scrolled to a component that was set to unrender. In that case stop the un-rendering timer
|
||||
clearTimeout(unrenderTimer);
|
||||
// if we're dealing underrndering lets add a waiting period of 200ms before rendering.
|
||||
// If a component enters the viewport and also leaves it within 200ms it will not render at all.
|
||||
// This saves work and improves performance when user scrolls very fast
|
||||
renderTimer = setTimeout(() => (shouldRender.value = true), props.unrender ? 200 : 0);
|
||||
shouldRender.value = true;
|
||||
if (!props.unrender) {
|
||||
stop();
|
||||
}
|
||||
} else if (props.unrender) {
|
||||
// if the component was set to render, cancel that
|
||||
clearTimeout(renderTimer);
|
||||
unrenderTimer = setTimeout(() => {
|
||||
fixedMinHeight.value = targetEl.value.clientHeight;
|
||||
shouldRender.value = false;
|
||||
}, props.unrenderDelay);
|
||||
}
|
||||
}, {
|
||||
rootMargin: "600px",
|
||||
}
|
||||
);
|
||||
|
||||
if (props.renderOnIdle) {
|
||||
onIdle(() => {
|
||||
shouldRender.value = true;
|
||||
if (!props.unrender) {
|
||||
stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {targetEl, shouldRender, fixedMinHeight};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -51,31 +51,46 @@
|
||||
</ul>
|
||||
|
||||
<p>There is no undo operation. This action is irreversible.</p>
|
||||
<p class="is-bold">
|
||||
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>
|
||||
</Message>
|
||||
|
||||
<div class="columns is-mobile">
|
||||
<div class="column is-6">
|
||||
<p class="control " v-if="!isDeleting">
|
||||
<NuxtLink to="/backends" class="button is-fullwidth is-primary">
|
||||
<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
|
||||
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>
|
||||
</p>
|
||||
</div>
|
||||
<div class="column">
|
||||
<p class="control">
|
||||
<button class="button is-danger is-fullwidth" @click="deleteBackend">
|
||||
<span class="icon"><i class="fas fa-trash"></i></span>
|
||||
<span>Yes, Delete it!</span>
|
||||
</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>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</Message>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@@ -83,14 +98,17 @@
|
||||
|
||||
<script setup>
|
||||
import 'assets/css/bulma-switch.css'
|
||||
import request from '~/utils/request.js'
|
||||
import Message from "~/components/Message.vue";
|
||||
import request from '~/utils/request'
|
||||
import Message from "~/components/Message"
|
||||
import {makeSecret, notification} from '~/utils/index'
|
||||
|
||||
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
|
||||
@@ -128,6 +146,11 @@ 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
|
||||
}
|
||||
@@ -170,5 +193,8 @@ const deleteBackend = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => await loadBackend())
|
||||
onMounted(async () => {
|
||||
await loadBackend()
|
||||
random_secret.value = makeSecret(8)
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
import 'assets/css/bulma-switch.css'
|
||||
import request from '~/utils/request'
|
||||
import Message from '~/components/Message'
|
||||
import {notification} from '~/utils/index'
|
||||
import {makeSecret, notification} from '~/utils/index'
|
||||
|
||||
const error = ref()
|
||||
const isResetting = ref(false)
|
||||
@@ -152,16 +152,6 @@ const resetSystem = async () => {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const strLength = 8;
|
||||
|
||||
let result = '';
|
||||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
let counter = 0;
|
||||
while (counter < strLength) {
|
||||
result += characters.charAt(Math.floor(Math.random() * characters.length));
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
random_secret.value = result
|
||||
random_secret.value = makeSecret(8)
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -404,6 +404,17 @@ const makePagination = (current, last, delta = 5) => {
|
||||
return pagination;
|
||||
}
|
||||
|
||||
const makeSecret = (len = 8) => {
|
||||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
let result = '';
|
||||
let counter = 0;
|
||||
while (counter < len) {
|
||||
result += characters.charAt(Math.floor(Math.random() * characters.length));
|
||||
counter += 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export {
|
||||
r,
|
||||
ag_set,
|
||||
@@ -422,4 +433,5 @@ export {
|
||||
makeName,
|
||||
makePagination,
|
||||
TOOLTIP_DATE_FORMAT,
|
||||
makeSecret,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user