Added some quick commands to WebUI backends page.
This commit is contained in:
@@ -85,7 +85,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<div class="card-footer">
|
||||
<div class="card-footer-item" v-if="backend.export.enabled">
|
||||
<NuxtLink class="button is-danger is-fullwidth"
|
||||
:to="makeConsoleCommand(`state:export -v -s ${backend.name}`)">
|
||||
@@ -100,8 +100,8 @@
|
||||
<span>Run import now</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</footer>
|
||||
<footer class="card-footer">
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="card-footer-item">
|
||||
<div class="field">
|
||||
<input :id="backend.name+'_export'" type="checkbox" class="switch is-success"
|
||||
@@ -125,6 +125,18 @@
|
||||
<span class="is-hidden-tablet">Webhook</span>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<div class="card-footer-item">
|
||||
<div class="select is-fullwidth">
|
||||
<select v-model="selectedCommand" @change="forwardCommand(backend)">
|
||||
<option value="" disabled>Quick commands</option>
|
||||
<option v-for="(command, index) in usefulCommands" :key="`command_${index}`" :value="index">
|
||||
{{ command.title }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
@@ -151,7 +163,7 @@ import 'assets/css/bulma-switch.css'
|
||||
import moment from 'moment'
|
||||
import request from '~/utils/request.js'
|
||||
import BackendAdd from '~/components/BackendAdd.vue'
|
||||
import {copyText, makeConsoleCommand, notification, TOOLTIP_DATE_FORMAT} from '~/utils/index.js'
|
||||
import {copyText, makeConsoleCommand, notification, r, TOOLTIP_DATE_FORMAT} from '~/utils/index.js'
|
||||
import {useStorage} from "@vueuse/core";
|
||||
import Message from "~/components/Message.vue";
|
||||
|
||||
@@ -162,6 +174,36 @@ const toggleForm = ref(false)
|
||||
const api_url = useStorage('api_url', '')
|
||||
const show_page_tips = useStorage('show_page_tips', true)
|
||||
const isLoading = ref(false)
|
||||
const selectedCommand = ref('')
|
||||
|
||||
const usefulCommands = [
|
||||
{
|
||||
title: "Force export local play state to this backend.",
|
||||
command: 'state:export -fi -v -s {name}'
|
||||
},
|
||||
{
|
||||
title: "Backup this backend play state.",
|
||||
command: "state:backup -v -s {name} --file '{date}.manual_{name}.json'",
|
||||
},
|
||||
{
|
||||
title: "Import backend metadata only.",
|
||||
command: "state:import -v --metadata-only -s {name}",
|
||||
},
|
||||
]
|
||||
|
||||
const forwardCommand = async backend => {
|
||||
if ('' === selectedCommand.value) {
|
||||
return
|
||||
}
|
||||
const Index = selectedCommand.value
|
||||
selectedCommand.value = ''
|
||||
|
||||
const util = {
|
||||
date: moment().format('YYYYMMDD'),
|
||||
}
|
||||
|
||||
await navigateTo(makeConsoleCommand(r(usefulCommands[Index].command, {...backend, ...util})));
|
||||
}
|
||||
|
||||
const loadContent = async () => {
|
||||
backends.value = []
|
||||
@@ -191,5 +233,4 @@ const updateValue = async (backend, key, newValue) => {
|
||||
|
||||
backends.value[backends.value.findIndex(b => b.name === backend.name)] = await response.json()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@@ -379,30 +379,23 @@ const makePagination = (current, last, delta = 5) => {
|
||||
|
||||
const strR = '-'.repeat(9 + `${last}`.length)
|
||||
|
||||
const left = current - delta,
|
||||
right = current + delta + 1;
|
||||
const left = current - delta, right = current + delta + 1;
|
||||
|
||||
for (let i = 1; i <= last; i++) {
|
||||
if (i === 1 || i === last || (i >= left && i < right)) {
|
||||
if (i === left && i > 2) {
|
||||
pagination.push({
|
||||
page: 0,
|
||||
text: strR,
|
||||
selected: false,
|
||||
page: 0, text: strR, selected: false,
|
||||
});
|
||||
}
|
||||
|
||||
pagination.push({
|
||||
page: i,
|
||||
text: `Page #${i}`,
|
||||
selected: i === current
|
||||
page: i, text: `Page #${i}`, selected: i === current
|
||||
});
|
||||
|
||||
if (i === right - 1 && i < last - 1) {
|
||||
pagination.push({
|
||||
page: 0,
|
||||
text: strR,
|
||||
selected: false,
|
||||
page: 0, text: strR, selected: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -412,6 +405,7 @@ const makePagination = (current, last, delta = 5) => {
|
||||
}
|
||||
|
||||
export {
|
||||
r,
|
||||
ag_set,
|
||||
ag,
|
||||
humanFileSize,
|
||||
|
||||
@@ -26,9 +26,9 @@ use Throwable;
|
||||
#[Cli(command: self::ROUTE)]
|
||||
class BackupCommand extends Command
|
||||
{
|
||||
public const ROUTE = 'state:backup';
|
||||
public const string ROUTE = 'state:backup';
|
||||
|
||||
public const TASK_NAME = 'backup';
|
||||
public const string TASK_NAME = 'backup';
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the class.
|
||||
@@ -180,31 +180,35 @@ class BackupCommand extends Command
|
||||
$type = strtolower(ag($backend, 'type', 'unknown'));
|
||||
|
||||
if ($isCustom && $input->getOption('exclude') === in_array($backendName, $selected, true)) {
|
||||
$this->logger->info('SYSTEM: Ignoring [{backend}] as requested by select backends flag.', [
|
||||
'backend' => $backendName,
|
||||
$this->logger->info("SYSTEM: Ignoring '{backend}' as requested by [-s, --select-backend].", [
|
||||
'backend' => $backendName
|
||||
]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (true !== (bool)ag($backend, 'import.enabled')) {
|
||||
$this->logger->info('SYSTEM: Ignoring [{backend}] imports are disabled for this backend.', [
|
||||
'backend' => $backendName,
|
||||
$this->logger->info("SYSTEM: Ignoring '{backend}' as the backend has import disabled.", [
|
||||
'backend' => $backendName
|
||||
]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($supported[$type])) {
|
||||
$this->logger->error('SYSTEM: Ignoring [{backend}] because of the unexpected type [{type}].', [
|
||||
$this->logger->error(
|
||||
"SYSTEM: Ignoring '{backend}' due to unexpected type '{type}'. Expecting '{types}'.",
|
||||
[
|
||||
'type' => $type,
|
||||
'backend' => $backendName,
|
||||
]);
|
||||
'types' => implode(', ', array_keys($supported)),
|
||||
]
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (null === ($url = ag($backend, 'url')) || false === isValidURL($url)) {
|
||||
$this->logger->error('SYSTEM: Ignoring [{backend}] because of invalid URL.', [
|
||||
'backend' => $backendName,
|
||||
$this->logger->error("SYSTEM: Ignoring '{backend}' due to invalid URL. '{url}'.", [
|
||||
'url' => $url ?? 'None',
|
||||
'backend' => $backendName,
|
||||
]);
|
||||
continue;
|
||||
}
|
||||
@@ -221,7 +225,7 @@ class BackupCommand extends Command
|
||||
}
|
||||
|
||||
if (true !== $input->getOption('no-enhance')) {
|
||||
$this->logger->notice('SYSTEM: Preloading {mapper} data.', [
|
||||
$this->logger->notice("SYSTEM: Preloading '{mapper}' data.", [
|
||||
'mapper' => afterLast($this->mapper::class, '\\'),
|
||||
'memory' => [
|
||||
'now' => getMemoryUsage(),
|
||||
@@ -229,10 +233,12 @@ class BackupCommand extends Command
|
||||
],
|
||||
]);
|
||||
|
||||
$start = microtime(true);
|
||||
$this->mapper->loadData();
|
||||
|
||||
$this->logger->notice('SYSTEM: Preloading {mapper} data is complete.', [
|
||||
$this->logger->notice("SYSTEM: Preloading '{mapper}' data completed in '{duration}s'.", [
|
||||
'mapper' => afterLast($this->mapper::class, '\\'),
|
||||
'duration' => round(microtime(true) - $start, 2),
|
||||
'memory' => [
|
||||
'now' => getMemoryUsage(),
|
||||
'peak' => getPeakMemoryUsage(),
|
||||
@@ -243,7 +249,7 @@ class BackupCommand extends Command
|
||||
/** @var array<array-key,ResponseInterface> $queue */
|
||||
$queue = [];
|
||||
|
||||
$this->logger->notice('Using WatchState Version - \'{version}\'.', ['version' => getAppVersion()]);
|
||||
$this->logger->notice("Using WatchState version - '{version}'.", ['version' => getAppVersion()]);
|
||||
|
||||
foreach ($list as $name => &$backend) {
|
||||
$opts = ag($backend, 'options', []);
|
||||
@@ -275,8 +281,8 @@ class BackupCommand extends Command
|
||||
$fileName = Config::get('path') . '/backup/{backend}.json';
|
||||
}
|
||||
|
||||
if (count($list) <= 1 && null === ($file = $input->getOption('file'))) {
|
||||
$fileName = $file;
|
||||
if (count($list) <= 1 && null !== ($file = $input->getOption('file'))) {
|
||||
$fileName = str_starts_with($file, '/') ? $file : Config::get('path') . '/backup' . '/' . $file;
|
||||
}
|
||||
|
||||
if (false === $input->getOption('dry-run')) {
|
||||
@@ -289,6 +295,11 @@ class BackupCommand extends Command
|
||||
touch($fileName);
|
||||
}
|
||||
|
||||
$this->logger->notice("SYSTEM: '{backend}' is using '{file}' as backup target.", [
|
||||
'file' => realpath($fileName),
|
||||
'backend' => $name,
|
||||
]);
|
||||
|
||||
$backend['fp'] = new Stream($fileName, 'wb+');
|
||||
$backend['fp']->write('[');
|
||||
}
|
||||
@@ -308,12 +319,9 @@ class BackupCommand extends Command
|
||||
|
||||
unset($backend);
|
||||
|
||||
$start = makeDate();
|
||||
$this->logger->notice('SYSTEM: Waiting on [{total}] requests.', [
|
||||
$start = microtime(true);
|
||||
$this->logger->notice("SYSTEM: Waiting on '{total}' requests.", [
|
||||
'total' => number_format(count($queue)),
|
||||
'time' => [
|
||||
'start' => $start,
|
||||
],
|
||||
'memory' => [
|
||||
'now' => getMemoryUsage(),
|
||||
'peak' => getPeakMemoryUsage(),
|
||||
@@ -347,13 +355,8 @@ class BackupCommand extends Command
|
||||
}
|
||||
}
|
||||
|
||||
$end = makeDate();
|
||||
$this->logger->notice('SYSTEM: Operation is finished.', [
|
||||
'time' => [
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
'duration' => $end->getTimestamp() - $start->getTimestamp(),
|
||||
],
|
||||
$this->logger->notice("SYSTEM: Backup operation finished in '{duration}s'.", [
|
||||
'duration' => round(microtime(true) - $start, 2),
|
||||
'memory' => [
|
||||
'now' => getMemoryUsage(),
|
||||
'peak' => getPeakMemoryUsage(),
|
||||
|
||||
@@ -42,21 +42,23 @@ final class Stream implements StreamInterface, Stringable
|
||||
$resource = $stream;
|
||||
|
||||
if (is_string($stream)) {
|
||||
set_error_handler(function ($e) use (&$error) {
|
||||
if ($e !== E_WARNING) {
|
||||
set_error_handler(function ($severity, $message, $file, $line) use (&$error) {
|
||||
if ($severity !== E_WARNING) {
|
||||
return;
|
||||
}
|
||||
|
||||
$error = $e;
|
||||
$error = r("Stream: Failed to open stream. '{message}' at '{file}:{line}'", [
|
||||
'message' => trim($message),
|
||||
'file' => $file,
|
||||
'line' => $line
|
||||
]);
|
||||
});
|
||||
$resource = fopen($stream, $mode);
|
||||
restore_error_handler();
|
||||
}
|
||||
|
||||
if ($error) {
|
||||
throw new RuntimeException(r('Stream: Invalid stream reference provided. Error {error}.', [
|
||||
'error' => ag(error_get_last() ?? [], 'message', '??'),
|
||||
]));
|
||||
if (null !== $error) {
|
||||
throw new RuntimeException($error);
|
||||
}
|
||||
|
||||
if (!self::isValidStreamResourceType($resource)) {
|
||||
|
||||
Reference in New Issue
Block a user