normalized the caster to return always non-null value and fixed minor ui issues
This commit is contained in:
@@ -96,6 +96,8 @@
|
||||
readOnlyCompartment.reconfigure(EditorState.readOnly.of(disabled)),
|
||||
],
|
||||
});
|
||||
|
||||
triggerNativeChange();
|
||||
}
|
||||
|
||||
$: if (editor && value != editor.state.doc.toString()) {
|
||||
@@ -228,7 +230,7 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
let options = [{ label: "null" }, { label: "false" }, { label: "true" }];
|
||||
let options = [{ label: "false" }, { label: "true" }];
|
||||
|
||||
if (!disableIndirectCollectionsKeys) {
|
||||
options.push({ label: "@collection.*", apply: "@collection." });
|
||||
|
||||
@@ -26,11 +26,19 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<OverlayPanel bind:this={panel} class="image-preview" popup on:show on:hide>
|
||||
<OverlayPanel bind:this={panel} class="image-preview" btnClose={false} popup on:show on:hide>
|
||||
<svelte:fragment slot="header">
|
||||
<div class="overlay-close" on:click|preventDefault={hide}>
|
||||
<i class="ri-close-line" />
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
|
||||
<img src={url} alt="Preview" />
|
||||
|
||||
<svelte:fragment slot="footer">
|
||||
<a href={url} class="link-hint txt-ellipsis">/../{url.substring(url.lastIndexOf("/") + 1)}</a>
|
||||
<a href={url} title="Download" class="link-hint txt-ellipsis">
|
||||
/../{url.substring(url.lastIndexOf("/") + 1)}
|
||||
</a>
|
||||
<div class="flex-fill" />
|
||||
<button type="button" class="btn btn-secondary" on:click={hide}>Close</button>
|
||||
</svelte:fragment>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
}
|
||||
.btn.refreshing i:before {
|
||||
animation: refresh 200ms linear;
|
||||
.btn.refreshing i {
|
||||
animation: refresh 200ms ease-out;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
<p>
|
||||
Example rule:
|
||||
<br />
|
||||
<code>@request.user.id!=null && created>"2022-01-01 00:00:00"</code>
|
||||
<code>@request.user.id!="" && created>"2022-01-01 00:00:00"</code>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -166,7 +166,7 @@
|
||||
|
||||
<OverlayPanel
|
||||
bind:this={collectionPanel}
|
||||
class="overlay-panel-lg colored-header collection-panel"
|
||||
class="overlay-panel-lg colored-header compact-header collection-panel"
|
||||
beforeHide={() => {
|
||||
if (hasChanges && confirmClose) {
|
||||
confirm("You have unsaved changes. Do you really want to close the panel?", () => {
|
||||
|
||||
@@ -67,6 +67,10 @@
|
||||
field.toDelete = false; // normalize
|
||||
}
|
||||
|
||||
$: if (field.required) {
|
||||
field.nullable = false;
|
||||
}
|
||||
|
||||
$: interactive = !disabled && !field.system && !field.toDelete && canBeStored;
|
||||
|
||||
$: hasErrors = !CommonHelper.isEmpty(CommonHelper.getNestedVal($errors, `schema.${key}`));
|
||||
@@ -154,7 +158,7 @@
|
||||
{/if}
|
||||
|
||||
{#if expanded && !field.toDelete}
|
||||
<div class="inline-flex flex-gap-sm flex-nowrap" in:fly={{ duration: 200, x: 20, opacity: 0 }}>
|
||||
<div class="inline-flex flex-gap-base flex-nowrap" in:fly={{ duration: 200, x: 20, opacity: 0 }}>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm fade p-l-0 p-r-0"
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
{:else if field.type === "file"}
|
||||
<div class="inline-flex">
|
||||
{#each CommonHelper.toArray(record[field.name]) as filename}
|
||||
<figure class="thumb thumb-sm" use:tooltip={filename}>
|
||||
<figure class="thumb thumb-sm">
|
||||
<RecordFilePreview {record} {filename} />
|
||||
</figure>
|
||||
{/each}
|
||||
|
||||
@@ -1,23 +1,42 @@
|
||||
<script>
|
||||
import ApiClient from "@/utils/ApiClient";
|
||||
import CommonHelper from "@/utils/CommonHelper";
|
||||
import PreviewPopup from "@/components/base/PreviewPopup.svelte";
|
||||
|
||||
export let record;
|
||||
export let filename;
|
||||
|
||||
let previewUrl = "";
|
||||
let previewPopup;
|
||||
let thumbUrl = "";
|
||||
let originalUrl = "";
|
||||
|
||||
$: if (CommonHelper.hasImageExtension(filename)) {
|
||||
previewUrl = ApiClient.Records.getFileUrl(record, `${filename}?thumb=100x100`);
|
||||
$: hasPreview = CommonHelper.hasImageExtension(filename);
|
||||
|
||||
$: if (hasPreview) {
|
||||
originalUrl = ApiClient.Records.getFileUrl(record, `${filename}`);
|
||||
}
|
||||
|
||||
$: thumbUrl = originalUrl ? originalUrl + "?thumb=100x100" : "";
|
||||
|
||||
function onError() {
|
||||
previewUrl = "";
|
||||
thumbUrl = "";
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if previewUrl}
|
||||
<img src={previewUrl} alt={filename} on:error={onError} />
|
||||
{#if hasPreview}
|
||||
<img
|
||||
src={thumbUrl}
|
||||
alt={filename}
|
||||
title="Preview {filename}"
|
||||
class:link-fade={hasPreview}
|
||||
on:click={(e) => {
|
||||
e.stopPropagation();
|
||||
previewPopup?.show(originalUrl);
|
||||
}}
|
||||
on:error={onError}
|
||||
/>
|
||||
{:else}
|
||||
<i class="ri-file-line" />
|
||||
{/if}
|
||||
|
||||
<PreviewPopup bind:this={previewPopup} />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { createEventDispatcher, tick } from "svelte";
|
||||
import { Record } from "pocketbase";
|
||||
import CommonHelper from "@/utils/CommonHelper";
|
||||
import ApiClient from "@/utils/ApiClient";
|
||||
@@ -57,12 +57,13 @@
|
||||
return recordPanel?.hide();
|
||||
}
|
||||
|
||||
function load(model) {
|
||||
async function load(model) {
|
||||
setErrors({}); // reset errors
|
||||
original = model || {};
|
||||
record = model?.clone ? model.clone() : new Record();
|
||||
uploadedFilesMap = {};
|
||||
deletedFileIndexesMap = {};
|
||||
await tick(); // wait to populate the fields to get the normalized values
|
||||
initialFormHash = calculateFormHash(record);
|
||||
}
|
||||
|
||||
@@ -71,7 +72,7 @@
|
||||
}
|
||||
|
||||
function save() {
|
||||
if (isSaving || !hasChanges) {
|
||||
if (isSaving || !canSave) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,17 +5,15 @@
|
||||
import tooltip from "@/actions/tooltip";
|
||||
import Field from "@/components/base/Field.svelte";
|
||||
import UploadedFilePreview from "@/components/base/UploadedFilePreview.svelte";
|
||||
import PreviewPopup from "@/components/base/PreviewPopup.svelte";
|
||||
import RecordFilePreview from "@/components/records/RecordFilePreview.svelte";
|
||||
|
||||
export let record;
|
||||
export let value = null;
|
||||
export let value = "";
|
||||
export let uploadedFiles = []; // Array<File> array
|
||||
export let deletedFileIndexes = []; // Array<int> array
|
||||
export let field = new SchemaField();
|
||||
|
||||
let fileInput;
|
||||
let previewPopup;
|
||||
let filesListElem;
|
||||
|
||||
// normalize uploadedFiles type
|
||||
@@ -30,8 +28,8 @@
|
||||
|
||||
$: isMultiple = field.options?.maxSelect > 1;
|
||||
|
||||
$: if (typeof value === "undefined" || value === null) {
|
||||
value = isMultiple ? [] : null;
|
||||
$: if (CommonHelper.isEmpty(value)) {
|
||||
value = isMultiple ? [] : "";
|
||||
}
|
||||
|
||||
$: valueAsArray = CommonHelper.toArray(value);
|
||||
@@ -81,16 +79,7 @@
|
||||
<div bind:this={filesListElem} class="files-list">
|
||||
{#each valueAsArray as filename, i (filename)}
|
||||
<div class="list-item">
|
||||
<figure
|
||||
class="thumb"
|
||||
class:fade={deletedFileIndexes.includes(i)}
|
||||
class:link-fade={CommonHelper.hasImageExtension(filename)}
|
||||
title={CommonHelper.hasImageExtension(filename) ? "Preview" : ""}
|
||||
on:click={() =>
|
||||
CommonHelper.hasImageExtension(filename)
|
||||
? previewPopup?.show(ApiClient.Records.getFileUrl(record, filename))
|
||||
: false}
|
||||
>
|
||||
<figure class="thumb" class:fade={deletedFileIndexes.includes(i)}>
|
||||
<RecordFilePreview {record} {filename} />
|
||||
</figure>
|
||||
<a
|
||||
@@ -173,5 +162,3 @@
|
||||
{/if}
|
||||
</div>
|
||||
</Field>
|
||||
|
||||
<PreviewPopup bind:this={previewPopup} />
|
||||
|
||||
@@ -18,5 +18,5 @@
|
||||
<i class={CommonHelper.getFieldTypeIcon(field.type)} />
|
||||
<span class="txt">{field.name}</span>
|
||||
</label>
|
||||
<textarea id={uniqueId} required={field.required} class="txt-mono txt-sm" bind:value />
|
||||
<textarea id={uniqueId} required={field.required} class="txt-mono" bind:value />
|
||||
</Field>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
$: isMultiple = field.options?.maxSelect > 1;
|
||||
|
||||
$: if (typeof value === "undefined") {
|
||||
value = isMultiple ? [] : null;
|
||||
value = isMultiple ? [] : "";
|
||||
}
|
||||
|
||||
$: if (isMultiple && Array.isArray(value) && value.length > field.options.maxSelect) {
|
||||
|
||||
@@ -349,7 +349,7 @@ button {
|
||||
border-color: var(--baseAlt2Color);
|
||||
}
|
||||
&.txt-mono {
|
||||
font-size: var(--smFontSize);
|
||||
line-height: var(--smLineHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,9 +436,6 @@ select {
|
||||
line-height: 1;
|
||||
margin-top: -2px;
|
||||
margin-bottom: -2px;
|
||||
+ .txt {
|
||||
margin-left: -5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
%input, label {
|
||||
|
||||
@@ -79,8 +79,8 @@
|
||||
text-align: center;
|
||||
font-size: 1.6rem;
|
||||
line-height: 1;
|
||||
border-top-left-radius: $size;
|
||||
border-bottom-left-radius: $size;
|
||||
border-top-left-radius: 50%;
|
||||
border-bottom-left-radius: 50%;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
color: #fff;
|
||||
@@ -154,7 +154,7 @@
|
||||
width: 850px;
|
||||
}
|
||||
&.overlay-panel-lg {
|
||||
width: 650px;
|
||||
width: 700px;
|
||||
}
|
||||
&.overlay-panel-sm {
|
||||
width: 460px;
|
||||
@@ -188,13 +188,30 @@
|
||||
padding-top: calc(var(--baseSpacing) - 5px);
|
||||
}
|
||||
}
|
||||
&.compact-header {
|
||||
.panel-header {
|
||||
row-gap: var(--smSpacing);
|
||||
}
|
||||
}
|
||||
&.image-preview {
|
||||
width: auto;
|
||||
min-width: 300px;
|
||||
max-width: 70%;
|
||||
max-height: 90%;
|
||||
.panel-header {
|
||||
position: absolute;
|
||||
z-index: 99;
|
||||
.overlay-close {
|
||||
left: 100%;
|
||||
right: auto;
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border-top-right-radius: 50%;
|
||||
border-bottom-right-radius: 50%;
|
||||
i {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.panel-header,
|
||||
.panel-footer {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
--infoColor: #3da9fc;
|
||||
--infoAltColor: #d8eefe;
|
||||
--successColor: #2cb67d;
|
||||
--successAltColor: #daf6ea;
|
||||
--successAltColor: #d6f5e8;
|
||||
--dangerColor: #ef4565;
|
||||
--dangerAltColor: #fcdee4;
|
||||
--warningColor: #ff8e3c;
|
||||
|
||||
@@ -118,15 +118,15 @@ export default class CommonHelper {
|
||||
* Normalizes and returns arr as a valid array instance (if not already).
|
||||
*
|
||||
* @param {Array} arr
|
||||
* @param {Boolean} [allowNull]
|
||||
* @param {Boolean} [allowEmpty]
|
||||
* @return {Array}
|
||||
*/
|
||||
static toArray(arr, allowNull = false) {
|
||||
static toArray(arr, allowEmpty = false) {
|
||||
if (Array.isArray(arr)) {
|
||||
return arr;
|
||||
}
|
||||
|
||||
return (allowNull || arr !== null) && typeof arr !== "undefined" ? [arr] : [];
|
||||
return (allowEmpty || !CommonHelper.isEmpty(arr)) && typeof arr !== "undefined" ? [arr] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user