Added post addBackend options to force export, or import data directly after.

This commit is contained in:
Abdulmhsen B. A. A.
2024-07-08 16:00:44 +03:00
parent 667487602e
commit 2c5c41fc7a
5 changed files with 106 additions and 62 deletions

View File

@@ -237,11 +237,42 @@
</p>
</div>
</div>
<div class="field" v-if="backends.length > 0">
<hr>
<label class="label has-text-danger" for="force_export">
Export current local database state to this backend?
</label>
<div class="control">
<input id="force_export" type="checkbox" class="switch is-success"
v-model="forceExport">
<label for="force_export">Yes</label>
<p class="help">
<span class="icon has-text-danger"><i class="fas fa-exclamation-triangle"></i></span>
If this is a new backend, you need to get it in sync with your current database,
enabling this option will initiate a one time force export the current local database state to the
backend. This will override the backend state to be inline with the local database state.
</p>
</div>
</div>
<div class="field" v-else>
<hr>
<label class="label has-text-danger" for="run_import">
Export current local database state to this backend?
</label>
<div class="control">
<input id="run_import" type="checkbox" class="switch is-success" v-model="runImport">
<label for="run_import">Yes</label>
<p class="help">
<span class="icon has-text-danger"><i class="fas fa-info-circle"></i></span>
Do you want to run a one time import for this backend after adding this backend?
</p>
</div>
</div>
</template>
</div>
<div class="card-footer">
<div class="card-footer-item" v-if="stage < 5">
<div class="card-footer-item" v-if="stage < maxStages">
<button class="button is-fullwidth is-primary" type="submit" @click="changeStep()">
<span class="icon">
<i class="fas fa-arrow-right"></i>
@@ -265,7 +296,7 @@ import 'assets/css/bulma-switch.css'
import request from '~/utils/request'
import {awaitElement, explode, notification} from '~/utils/index'
const emit = defineEmits(['addBackend'])
const emit = defineEmits(['addBackend', 'forceExport', 'runImport'])
const props = defineProps({
backends: {
@@ -299,12 +330,15 @@ const users = ref([])
const supported = ref([])
const servers = ref([])
const maxStages = 5
const stage = ref(0)
const usersLoading = ref(false)
const uuidLoading = ref(false)
const serversLoading = ref(false)
const exposeToken = ref(false)
const error = ref()
const forceExport = ref(false)
const runImport = ref(false)
const isLimited = ref(false)
const accessTokenResponse = ref({})
@@ -593,7 +627,18 @@ const addBackend = async () => {
}
notification('success', 'Information', `Backend ${backend.value.name} added successfully.`)
emit('addBackend', backend)
let event
if (true === Boolean(forceExport?.value ?? false)) {
event = 'forceExport'
} else if (true === Boolean(runImport?.value ?? false)) {
event = 'runImport'
} else {
event = 'addBackend'
}
emit(event, backend)
return true
}

View File

@@ -26,7 +26,8 @@
</div>
<div class="column is-12" v-if="toggleForm">
<BackendAdd @addBackend="toggleForm = false; loadContent()" :backends="backends"/>
<BackendAdd @forceExport="e => handleEvents('forceExport', e)" :backends="backends"
@runImport="e => handleEvents('runImport', e)" @addBackend="e => handleEvents('addBackend', e)"/>
</div>
<template v-else>
<div class="column is-12" v-if="backends.length<1">
@@ -257,4 +258,21 @@ const updateValue = async (backend, key, newValue) => {
backends.value[backends.value.findIndex(b => b.name === backend.name)] = await response.json()
}
const handleEvents = async (event, backend) => {
switch (event) {
case 'forceExport':
notification('warning', 'Warning', `We are going to sync '${backend.value.name}' play state to match the current local database.`, 10000)
await navigateTo(makeConsoleCommand(`state:export -fi -v -s ${backend.value.name}`, true))
break
case 'runImport':
notification('info', 'Info', `We are going to import '${backend.value.name}' play state to the local database.`, 10000)
await navigateTo(makeConsoleCommand(`state:import -v -s ${backend.value.name}`, true))
break
case 'addBackend':
toggleForm.value = false
await loadContent()
break
}
}
</script>

View File

@@ -105,30 +105,22 @@
</template>
<script setup>
import {useStorage} from '@vueuse/core'
import {notification} from '~/utils/index.js'
import Message from '~/components/Message.vue'
const route = useRoute()
const fromTask = route.query.task || '';
let fromCommand = route.query.cmd || '';
if (fromCommand) {
// -- decode base64
fromCommand = atob(fromCommand);
}
import {notification} from '~/utils/index'
import Message from '~/components/Message'
useHead({title: `Console`})
let sse;
const route = useRoute()
const fromCommand = route.query.cmd || false ? atob(route.query.cmd) : ''
const response = ref([]);
const command = ref(fromCommand);
const isLoading = ref(false);
const outputConsole = ref();
const hasPrefix = computed(() => command.value.startsWith('console') || command.value.startsWith('docker'));
const hasPlaceholder = computed(() => command.value && command.value.match(/\[.*\]/));
let sse
const response = ref([])
const command = ref(fromCommand)
const isLoading = ref(false)
const outputConsole = ref()
const hasPrefix = computed(() => command.value.startsWith('console') || command.value.startsWith('docker'))
const hasPlaceholder = computed(() => command.value && command.value.match(/\[.*\]/))
const show_page_tips = useStorage('show_page_tips', true)
const RunCommand = async () => {
@@ -153,60 +145,47 @@ const RunCommand = async () => {
response.value = []
const searchParams = new URLSearchParams();
searchParams.append('apikey', api_token.value);
searchParams.append('json', btoa(JSON.stringify({command: userCommand})));
const searchParams = new URLSearchParams()
searchParams.append('apikey', api_token.value)
searchParams.append('json', btoa(JSON.stringify({command: userCommand})))
sse = new EventSource(`${api_url.value}${api_path.value}/system/command/?${searchParams.toString()}`)
sse = new EventSource(`${api_url.value}${api_path.value}/system/command/?${searchParams.toString()}`);
isLoading.value = true;
isLoading.value = true
sse.addEventListener('data', async e => {
let lines = e.data.split(/\n/g);
let lines = e.data.split(/\n/g)
for (let x = 0; x < lines.length; x++) {
response.value.push(lines[x]);
response.value.push(lines[x])
}
});
})
sse.addEventListener('close', () => finished());
sse.onclose = () => finished();
sse.onerror = () => finished();
sse.addEventListener('close', () => finished())
sse.onclose = () => finished()
sse.onerror = () => finished()
}
const finished = () => {
if (sse) {
sse.close();
sse.close()
}
isLoading.value = false;
isLoading.value = false
const route = useRoute();
const router = useRouter();
const route = useRoute()
if (route.query?.cmd || route.query?.task) {
route.query.cmd = '';
route.query.task = '';
router.push({path: '/console'});
if (route.query?.cmd || route.query?.run) {
route.query.cmd = ''
route.query.run = ''
useRouter().push({path: '/console'})
}
}
onUpdated(() => outputConsole.value.scrollTop = outputConsole.value.scrollHeight);
onUpdated(() => outputConsole.value.scrollTop = outputConsole.value.scrollHeight)
onMounted(async () => {
if (!fromTask && '' === command.value) {
await RunCommand();
return
if (Boolean(route.query?.run ?? '0') || '' === command.value) {
await RunCommand()
}
if (!fromTask) {
return
}
const response = await request(`/tasks/${fromTask}`);
const json = await response.json();
command.value = `${json.command} ${json.args || ''}`;
await RunCommand();
});
})
</script>

View File

@@ -180,7 +180,7 @@
import 'assets/css/bulma-switch.css'
import moment from 'moment'
import request from '~/utils/request'
import {awaitElement, notification, TOOLTIP_DATE_FORMAT} from '~/utils/index'
import {awaitElement, makeConsoleCommand, notification, TOOLTIP_DATE_FORMAT} from '~/utils/index'
import cronstrue from 'cronstrue'
import Message from '~/components/Message'
import {useStorage} from '@vueuse/core'
@@ -272,6 +272,6 @@ const confirmRun = async task => {
if (!confirm(`Run '${task.name}' via web console now?`)) {
return
}
await navigateTo({path: '/console', query: {task: task.name}})
await navigateTo(makeConsoleCommand(`${task.command} ${task.args || ''}`, true));
}
</script>

View File

@@ -302,8 +302,11 @@ const copyText = (str, showNotification = true) => {
notification('success', 'Success', 'Text copied to clipboard.')
}
const makeConsoleCommand = (cmd) => {
const makeConsoleCommand = (cmd, run = false) => {
const params = new URLSearchParams();
if (run) {
params.append('run', 'true');
}
// -- base64 encode the command to prevent XSS
params.append('cmd', btoa(cmd));
return `/console?${params.toString()}`
@@ -311,7 +314,6 @@ const makeConsoleCommand = (cmd) => {
const stringToRegex = (str) => new RegExp(str.match(/\/(.+)\/.*/)[1], str.match(/\/.+\/(.*)/)[1])
/**
* Make history search link.
*