added support for linking to the record preview/update form and some other minor improvements

This commit is contained in:
Gani Georgiev
2023-10-01 12:53:26 +03:00
parent ebf73f5602
commit 8908d03b8c
50 changed files with 407 additions and 165 deletions

View File

@@ -7,7 +7,7 @@
import tooltip from "@/actions/tooltip";
import { setErrors } from "@/stores/errors";
import { confirm } from "@/stores/confirmation";
import { addSuccessToast } from "@/stores/toasts";
import { addSuccessToast, addErrorToast } from "@/stores/toasts";
import Field from "@/components/base/Field.svelte";
import Toggler from "@/components/base/Toggler.svelte";
import ModelDateIcon from "@/components/base/ModelDateIcon.svelte";
@@ -38,14 +38,14 @@
let record = null;
let initialDraft = null;
let isSaving = false;
let confirmClose = false; // prevent close recursion
let confirmHide = false; // prevent close recursion
let uploadedFilesMap = {}; // eg.: {"field1":[File1, File2], ...}
let deletedFileNamesMap = {}; // eg.: {"field1":[0, 1], ...}
let originalSerializedData = JSON.stringify(null);
let originalSerializedData = JSON.stringify(original);
let serializedData = originalSerializedData;
let activeTab = tabFormKey;
let isNew = true;
let isLoaded = false;
let isLoading = true;
$: isAuthCollection = collection?.type === "auth";
@@ -60,16 +60,16 @@
$: isNew = !original || !original.id;
$: canSave = isNew || hasChanges;
$: canSave = !isLoading && (isNew || hasChanges);
$: if (isLoaded) {
$: if (!isLoading) {
updateDraft(serializedData);
}
export function show(model) {
load(model);
confirmClose = true;
confirmHide = true;
activeTab = tabFormKey;
@@ -80,14 +80,49 @@
return recordPanel?.hide();
}
function forceHide() {
confirmHide = false;
hide();
}
async function resolveModel(model) {
if (model && typeof model === "string") {
// load from id
try {
return await ApiClient.collection(collection.id).getOne(model);
} catch (err) {
if (!err.isAbort) {
forceHide();
console.warn("resolveModel:", err);
addErrorToast(`Unable to load record with id "${model}"`);
}
}
return null;
}
return model;
}
async function load(model) {
isLoaded = false;
setErrors({}); // reset errors
original = model || {};
record = structuredClone(original);
isLoading = true;
// resets
setErrors({});
uploadedFilesMap = {};
deletedFileNamesMap = {};
// load the minimum model data if possible to minimize layout shifts
original =
typeof model === "string"
? { id: model, collectionId: collection?.id, collectionName: collection?.name }
: model || {};
record = structuredClone(original);
// resolve the complete model
original = (await resolveModel(model)) || {};
record = structuredClone(original);
// wait to populate the fields to get the normalized values
await tick();
@@ -100,7 +135,8 @@
}
originalSerializedData = JSON.stringify(record);
isLoaded = true;
isLoading = false;
}
async function replaceOriginal(newOriginal) {
@@ -204,8 +240,7 @@
deleteDraft();
if (hidePanel) {
confirmClose = false;
hide();
forceHide();
} else {
replaceOriginal(result);
}
@@ -406,11 +441,13 @@
{hasEditorField ? 'overlay-panel-xl' : 'overlay-panel-lg'}
{isAuthCollection && !isNew ? 'colored-header' : ''}
"
btnClose={!isLoading}
escClose={!isLoading}
overlayClose={!isLoading}
beforeHide={() => {
if (hasChanges && confirmClose) {
if (hasChanges && confirmHide) {
confirm("You have unsaved changes. Do you really want to close the panel?", () => {
confirmClose = false;
hide();
forceHide();
});
return false;
@@ -425,10 +462,15 @@
on:show
>
<svelte:fragment slot="header">
<h4 class="panel-title">
{isNew ? "New" : "Edit"}
<strong>{collection?.name}</strong> record
</h4>
{#if isLoading}
<span class="loader loader-sm" />
<h4 class="panel-title txt-hint">Loading...</h4>
{:else}
<h4 class="panel-title">
{isNew ? "New" : "Edit"}
<strong>{collection?.name}</strong> record
</h4>
{/if}
{#if !isNew}
<div class="flex-fill" />
@@ -502,7 +544,7 @@
on:submit|preventDefault={save}
on:keydown={handleFormKeydown}
>
{#if !hasChanges && initialDraft}
{#if !hasChanges && initialDraft && !isLoading}
<div class="block" out:slide={{ duration: 150 }}>
<div class="alert alert-info m-0">
<div class="icon">
@@ -546,7 +588,7 @@
<input
type="text"
id={uniqueId}
placeholder="Leave empty to auto generate..."
placeholder={!isLoading ? "Leave empty to auto generate..." : ""}
minlength="15"
readonly={!isNew}
bind:value={record.id}
@@ -602,7 +644,12 @@
</div>
<svelte:fragment slot="footer">
<button type="button" class="btn btn-transparent" disabled={isSaving} on:click={() => hide()}>
<button
type="button"
class="btn btn-transparent"
disabled={isSaving || isLoading}
on:click={() => hide()}
>
<span class="txt">Cancel</span>
</button>
@@ -610,7 +657,7 @@
type="submit"
form={formId}
class="btn btn-expanded"
class:btn-loading={isSaving}
class:btn-loading={isSaving || isLoading}
disabled={!canSave || isSaving}
>
<span class="txt">{isNew ? "Create" : "Save changes"}</span>