This is the code that runs https://bandolier.learnjsthehardway.com/ for you to review. It uses the https://git.learnjsthehardway.com/learn-javascript-the-hard-way/bandolier-template to create the documentation for the project.
https://bandolier.learnjsthehardway.com/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
151 lines
4.2 KiB
151 lines
4.2 KiB
<script>
|
|
import { push, link } from 'svelte-spa-router';
|
|
import { onMount } from 'svelte';
|
|
import Layout from "$/admin/Layout.svelte";
|
|
import Icon from "$/client/components/Icon.svelte";
|
|
import Modal from "$/client/components/Modal.svelte";
|
|
import Form from "$/client/components/Form.svelte";
|
|
import api from "$/client/api.js";
|
|
import { log } from "$/client/logging.js";
|
|
import { defer } from "$/client/helpers.js";
|
|
import Toasts from "$/client/components/Toasts.svelte";
|
|
|
|
export let params = {};
|
|
let send_toast;
|
|
|
|
let form_data = {_errors: {}, _valid: false};
|
|
let delete_confirm = false;
|
|
let load_promise = defer();
|
|
let schema = {};
|
|
|
|
const delete_record = async () => {
|
|
let [status, data] = await api.del(`/api/admin/table?name=${params.table}&row_id=${params.row_id}`);
|
|
|
|
if(status === 200) {
|
|
form_data = data;
|
|
form_data._errors = {}; // setup for errors later
|
|
push(`/table/${params.table}/`);
|
|
} else if(status == 401) {
|
|
window.location = "/client/#/login";
|
|
} else {
|
|
send_toast("Failed to delete.");
|
|
}
|
|
}
|
|
|
|
const update_record = async () => {
|
|
let [status, data] = await api.post(`/api/admin/table?name=${params.table}&row_id=${params.row_id}`, form_data);
|
|
|
|
log.debug("update record results", data);
|
|
|
|
if(status == 200) {
|
|
send_toast("Update successful.");
|
|
} else if(status == 401) {
|
|
window.location = "/client/#/login";
|
|
} else {
|
|
send_toast("Update failed.");
|
|
form_data = Object.assign(form_data, data);
|
|
}
|
|
}
|
|
|
|
const json_copy = () => {
|
|
const text = JSON.stringify(form_data, null, 4);
|
|
|
|
navigator.clipboard.writeText(text).then(() => {
|
|
send_toast("JSON data copied to clipboard");
|
|
}, () => {
|
|
send_toast("Failed copying to clipboard.");
|
|
});
|
|
}
|
|
|
|
onMount(async () => {
|
|
schema = await api.schema(params.table);
|
|
|
|
if(schema === undefined) {
|
|
send_toast("Failed to load schema.");
|
|
load_promise.reject();
|
|
} else {
|
|
let [status, data] = await api.get('/api/admin/table', {
|
|
name: params.table, row_id: params.row_id
|
|
});
|
|
|
|
if(status == 200) {
|
|
form_data = data;
|
|
load_promise.resolve();
|
|
} else if(status == 401) {
|
|
window.location = "/client/#/login";
|
|
} else {
|
|
sent_toast("Failed to load table data.");
|
|
load_promise.reject();
|
|
}
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
card {
|
|
background-color: var(--color-bg);
|
|
}
|
|
|
|
card top {
|
|
text-align: center;
|
|
}
|
|
|
|
card middle {
|
|
padding: 1rem;
|
|
}
|
|
</style>
|
|
|
|
<Layout authenticated={ true } testid="page-admin-readupdate">
|
|
{#await load_promise}
|
|
<!-- form already has a spinner -->
|
|
{:then}
|
|
<Form data={form_data} table={params.table} schema={ schema }>
|
|
<a href="/table/{ params.table }" data-testid="button-back" use:link>
|
|
<Icon name="arrow-left-circle" tooltip="Back to table." size="48" />
|
|
</a>
|
|
|
|
<span data-testid="button-copy" on:click={ json_copy }>
|
|
<Icon name="copy" tooltip="Copy JSON." size="48" />
|
|
</span>
|
|
|
|
<span data-testid="button-update" on:click={ update_record }>
|
|
<Icon name="save" tooltip="Update." size="48" />
|
|
</span>
|
|
|
|
<span data-testid="button-delete" on:click={ () => delete_confirm = true }>
|
|
<Icon name="trash" tooltip="Delete!" size="48" />
|
|
</span>
|
|
</Form>
|
|
{:catch}
|
|
<callout class="error">
|
|
<p>Return to the table:
|
|
<a href="/table/{ params.table }" data-testid="button-back" use:link>
|
|
<Icon name="arrow-left-circle" tooltip="Back to table." size="48" />
|
|
</a>
|
|
</p>
|
|
</callout>
|
|
{/await}
|
|
</Layout>
|
|
|
|
<Toasts bind:send_toast orientation="bottom right"/>
|
|
|
|
{#if delete_confirm}
|
|
<Modal on:close={() => delete_confirm = false }>
|
|
<card>
|
|
<top>
|
|
<h1>Really Delete?</h1>
|
|
</top>
|
|
|
|
<middle>
|
|
<p>This action is permanent to make sure it's what you want.</p>
|
|
</middle>
|
|
|
|
<bottom>
|
|
<button-group>
|
|
<button type="button" data-testid="button-delete-no" on:click={() => delete_confirm = false }>Cancel</button>
|
|
<button data-testid="button-delete-yes" on:click={ delete_record }>DELETE</button>
|
|
</button-group>
|
|
</bottom>
|
|
</card>
|
|
</Modal>
|
|
{/if}
|
|
|