mirror of
https://github.com/pocketbase/pocketbase.git
synced 2026-10-13 01:28:16 +02:00
merge v0.23.0-rc changes
This commit is contained in:
1 parent
ad92992324
commit
844f18cac3
753 files changed
+85107
-63362
No files matched your search
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import CommonHelper from "@/utils/CommonHelper";
|
||||
import Toggler from "@/components/base/Toggler.svelte";
|
||||
import CommonHelper from "@/utils/CommonHelper";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
|
||||
let classes = "";
|
||||
export { classes as class }; // export reserved keyword
|
||||
@@ -35,7 +35,7 @@
|
||||
icon: CommonHelper.getFieldTypeIcon("email"),
|
||||
},
|
||||
{
|
||||
label: "Url",
|
||||
label: "URL",
|
||||
value: "url",
|
||||
icon: CommonHelper.getFieldTypeIcon("url"),
|
||||
},
|
||||
@@ -44,6 +44,11 @@
|
||||
value: "date",
|
||||
icon: CommonHelper.getFieldTypeIcon("date"),
|
||||
},
|
||||
{
|
||||
label: "Autodate",
|
||||
value: "autodate",
|
||||
icon: CommonHelper.getFieldTypeIcon("autodate"),
|
||||
},
|
||||
{
|
||||
label: "Select",
|
||||
value: "select",
|
||||
@@ -64,6 +69,11 @@
|
||||
value: "json",
|
||||
icon: CommonHelper.getFieldTypeIcon("json"),
|
||||
},
|
||||
// {
|
||||
// label: "Password",
|
||||
// value: "password",
|
||||
// icon: CommonHelper.getFieldTypeIcon("password"),
|
||||
// },
|
||||
];
|
||||
|
||||
function select(fieldType) {
|
||||
|
||||
@@ -21,34 +21,43 @@
|
||||
number: "Nonzero",
|
||||
};
|
||||
|
||||
// @todo refactor once the UI is dynamic
|
||||
const authHideNonemptyToggle = ["password", "tokenKey", "id", "autodate"];
|
||||
const authHideHiddenToggle = ["password", "tokenKey", "id", "email"];
|
||||
const authHidePresentableToggle = ["password", "tokenKey"];
|
||||
|
||||
export let key = "";
|
||||
export let field = CommonHelper.initSchemaField();
|
||||
export let draggable = true;
|
||||
export let collection = {};
|
||||
|
||||
let nameInput;
|
||||
let showOptions = false;
|
||||
|
||||
$: if (field.toDelete) {
|
||||
$: isAuthCollection = collection?.type == "auth";
|
||||
|
||||
$: if (field._toDelete) {
|
||||
// reset the name if it was previously deleted
|
||||
if (field.originalName && field.name !== field.originalName) {
|
||||
field.name = field.originalName;
|
||||
if (field._originalName && field.name !== field._originalName) {
|
||||
field.name = field._originalName;
|
||||
}
|
||||
}
|
||||
|
||||
$: if (!field.originalName && field.name) {
|
||||
field.originalName = field.name;
|
||||
$: if (!field._originalName && field.name) {
|
||||
field._originalName = field.name;
|
||||
}
|
||||
|
||||
$: if (typeof field.toDelete === "undefined") {
|
||||
field.toDelete = false; // normalize
|
||||
$: if (typeof field._toDelete === "undefined") {
|
||||
field._toDelete = false; // normalize
|
||||
}
|
||||
|
||||
$: if (field.required) {
|
||||
field.nullable = false;
|
||||
}
|
||||
|
||||
$: interactive = !field.toDelete && !(field.id && field.system);
|
||||
$: interactive = !field._toDelete;
|
||||
|
||||
$: hasErrors = !CommonHelper.isEmpty(CommonHelper.getNestedVal($errors, `schema.${key}`));
|
||||
$: hasErrors = !CommonHelper.isEmpty(CommonHelper.getNestedVal($errors, `fields.${key}`));
|
||||
|
||||
$: requiredLabel = customRequiredLabels[field?.type] || "Nonempty";
|
||||
|
||||
@@ -57,19 +66,19 @@
|
||||
collapse();
|
||||
dispatch("remove");
|
||||
} else {
|
||||
field.toDelete = true;
|
||||
field._toDelete = true;
|
||||
}
|
||||
}
|
||||
|
||||
function restore() {
|
||||
field.toDelete = false;
|
||||
field._toDelete = false;
|
||||
|
||||
// reset all errors since the error index key would have been changed
|
||||
setErrors({});
|
||||
}
|
||||
|
||||
function duplicate() {
|
||||
if (!field.toDelete) {
|
||||
if (!field._toDelete) {
|
||||
collapse();
|
||||
dispatch("duplicate");
|
||||
}
|
||||
@@ -126,44 +135,49 @@
|
||||
class="schema-field"
|
||||
class:required={field.required}
|
||||
class:expanded={interactive && showOptions}
|
||||
class:deleted={field.toDelete}
|
||||
class:deleted={field._toDelete}
|
||||
transition:slide={{ duration: 150 }}
|
||||
>
|
||||
<div class="schema-field-header">
|
||||
{#if interactive}
|
||||
{#if interactive && draggable}
|
||||
<div class="drag-handle-wrapper" draggable={true} aria-label="Sort">
|
||||
<span class="drag-handle" />
|
||||
</div>
|
||||
{/if}
|
||||
<Field
|
||||
class="form-field required m-0 {!interactive ? 'disabled' : ''}"
|
||||
name="schema.{key}.name"
|
||||
name="fields.{key}.name"
|
||||
inlineError
|
||||
>
|
||||
{#if field.required}
|
||||
<div class="field-labels">
|
||||
<div class="field-labels">
|
||||
{#if field.required}
|
||||
<span class="label label-success">{requiredLabel}</span>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
{#if field.hidden}
|
||||
<span class="label label-danger">Hidden</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="form-field-addon prefix no-pointer-events field-type-icon"
|
||||
class:txt-disabled={!interactive}
|
||||
class="form-field-addon prefix field-type-icon"
|
||||
class:txt-disabled={!interactive || field.system}
|
||||
use:tooltip={field.type + (field.system ? " (system)" : "")}
|
||||
on:click={() => nameInput?.focus()}
|
||||
>
|
||||
<i class={CommonHelper.getFieldTypeIcon(field.type)} />
|
||||
</div>
|
||||
|
||||
<!-- svelte-ignore a11y-autofocus -->
|
||||
<input
|
||||
bind:this={nameInput}
|
||||
type="text"
|
||||
required
|
||||
disabled={!interactive}
|
||||
readonly={field.id && field.system}
|
||||
disabled={!interactive || field.system}
|
||||
spellcheck="false"
|
||||
autofocus={!field.id}
|
||||
placeholder="Field name"
|
||||
value={field.name}
|
||||
title="System field"
|
||||
on:input={(e) => {
|
||||
const oldName = field.name;
|
||||
field.name = normalizeFieldName(e.target.value);
|
||||
@@ -178,10 +192,10 @@
|
||||
<span class="separator" />
|
||||
</slot>
|
||||
|
||||
{#if field.toDelete}
|
||||
{#if field._toDelete}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-circle btn-warning btn-transparent options-trigger"
|
||||
class="btn btn-sm btn-circle btn-success btn-transparent options-trigger"
|
||||
aria-label="Restore"
|
||||
use:tooltip={"Restore"}
|
||||
on:click={restore}
|
||||
@@ -191,7 +205,7 @@
|
||||
{:else if interactive}
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Toggle field options"
|
||||
aria-label="Toggle {field.name} field options"
|
||||
class="btn btn-sm btn-circle options-trigger {showOptions
|
||||
? 'btn-secondary'
|
||||
: 'btn-transparent'}"
|
||||
@@ -206,49 +220,83 @@
|
||||
</div>
|
||||
|
||||
{#if interactive && showOptions}
|
||||
<div class="schema-field-options" transition:slide={{ duration: 150 }}>
|
||||
<div class="schema-field-options" transition:slide={{ delay: 10, duration: 150 }}>
|
||||
<div class="hidden-empty m-b-sm">
|
||||
<slot name="options" {interactive} {hasErrors} />
|
||||
</div>
|
||||
|
||||
<div class="schema-field-options-footer">
|
||||
<Field class="form-field form-field-toggle" name="requried" let:uniqueId>
|
||||
<input type="checkbox" id={uniqueId} bind:checked={field.required} />
|
||||
<label for={uniqueId}>
|
||||
<span class="txt">{requiredLabel}</span>
|
||||
<i
|
||||
class="ri-information-line link-hint"
|
||||
use:tooltip={{
|
||||
text: `Requires the field value NOT to be ${CommonHelper.zeroDefaultStr(
|
||||
field,
|
||||
)}.`,
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
</Field>
|
||||
<!-- @todo move to each field after the refactoring -->
|
||||
{#if !field.primaryKey && field.type != "autodate" && (!isAuthCollection || !authHideNonemptyToggle.includes(field.name))}
|
||||
<Field class="form-field form-field-toggle" name="requried" let:uniqueId>
|
||||
<input type="checkbox" id={uniqueId} bind:checked={field.required} />
|
||||
<label for={uniqueId}>
|
||||
<span class="txt">{requiredLabel}</span>
|
||||
<i
|
||||
class="ri-information-line link-hint"
|
||||
use:tooltip={{
|
||||
text: `Requires the field value NOT to be ${CommonHelper.zeroDefaultStr(
|
||||
field,
|
||||
)}.`,
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
</Field>
|
||||
{/if}
|
||||
|
||||
<Field class="form-field form-field-toggle" name="presentable" let:uniqueId>
|
||||
<input type="checkbox" id={uniqueId} bind:checked={field.presentable} />
|
||||
<label for={uniqueId}>
|
||||
<span class="txt">Presentable</span>
|
||||
<i
|
||||
class="ri-information-line link-hint"
|
||||
use:tooltip={{
|
||||
text: `Whether the field should be preferred in the Admin UI relation listings (default to auto).`,
|
||||
{#if !field.primaryKey && (!isAuthCollection || !authHideHiddenToggle.includes(field.name))}
|
||||
<Field class="form-field form-field-toggle" name="hidden" let:uniqueId>
|
||||
<input
|
||||
type="checkbox"
|
||||
id={uniqueId}
|
||||
bind:checked={field.hidden}
|
||||
on:change={(e) => {
|
||||
if (e.target.checked) {
|
||||
field.presentable = false;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
</Field>
|
||||
<label for={uniqueId}>
|
||||
<span class="txt">Hidden</span>
|
||||
<i
|
||||
class="ri-information-line link-hint"
|
||||
use:tooltip={{
|
||||
text: `Hide from the JSON API response and filters.`,
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
</Field>
|
||||
{/if}
|
||||
|
||||
{#if !isAuthCollection || !authHidePresentableToggle.includes(field.name)}
|
||||
<Field class="form-field form-field-toggle m-0" name="presentable" let:uniqueId>
|
||||
<input
|
||||
type="checkbox"
|
||||
id={uniqueId}
|
||||
bind:checked={field.presentable}
|
||||
disabled={field.hidden}
|
||||
/>
|
||||
<label for={uniqueId}>
|
||||
<span class="txt">Presentable</span>
|
||||
<i
|
||||
class="ri-information-line {field.hidden ? 'txt-disabled' : 'link-hint'}"
|
||||
use:tooltip={{
|
||||
text: `Whether the field should be preferred in the Superuser UI relation listings (default to auto).`,
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
</Field>
|
||||
{/if}
|
||||
|
||||
<slot name="optionsFooter" {interactive} {hasErrors} />
|
||||
|
||||
{#if !field.toDelete}
|
||||
{#if !field._toDelete && !field.primaryKey}
|
||||
<div class="m-l-auto txt-right">
|
||||
<div class="inline-flex flex-gap-sm flex-nowrap">
|
||||
<div
|
||||
tabindex="0"
|
||||
role="button"
|
||||
aria-label="More"
|
||||
title="More field options"
|
||||
class="btn btn-circle btn-sm btn-transparent"
|
||||
>
|
||||
<i class="ri-more-line" aria-hidden="true" />
|
||||
@@ -263,14 +311,16 @@
|
||||
>
|
||||
<span class="txt">Duplicate</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="dropdown-item"
|
||||
role="menuitem"
|
||||
on:click|preventDefault={remove}
|
||||
>
|
||||
<span class="txt">Remove</span>
|
||||
</button>
|
||||
{#if !field.system}
|
||||
<button
|
||||
type="button"
|
||||
class="dropdown-item"
|
||||
role="menuitem"
|
||||
on:click|preventDefault={remove}
|
||||
>
|
||||
<span class="txt">Remove</span>
|
||||
</button>
|
||||
{/if}
|
||||
</Toggler>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
<script>
|
||||
import tooltip from "@/actions/tooltip";
|
||||
import Field from "@/components/base/Field.svelte";
|
||||
import ObjectSelect from "@/components/base/ObjectSelect.svelte";
|
||||
import SchemaField from "@/components/collections/schema/SchemaField.svelte";
|
||||
|
||||
const ON_CREATE = 1;
|
||||
const ON_UPDATE = 2;
|
||||
const ON_CREATE_UPDATE = 3;
|
||||
|
||||
const options = [
|
||||
{ label: "Create", value: ON_CREATE },
|
||||
{ label: "Update", value: ON_UPDATE },
|
||||
{ label: "Create/Update", value: ON_CREATE_UPDATE },
|
||||
];
|
||||
|
||||
export let field;
|
||||
export let key = "";
|
||||
|
||||
let selectedOption = optionFromField();
|
||||
|
||||
$: updateField(selectedOption);
|
||||
|
||||
function optionFromField() {
|
||||
if (field.onCreate && field.onUpdate) {
|
||||
return ON_CREATE_UPDATE;
|
||||
}
|
||||
|
||||
if (field.onUpdate) {
|
||||
return ON_UPDATE;
|
||||
}
|
||||
|
||||
return ON_CREATE;
|
||||
}
|
||||
|
||||
function updateField(option) {
|
||||
switch (option) {
|
||||
case ON_CREATE:
|
||||
field.onCreate = true;
|
||||
field.onUpdate = false;
|
||||
break;
|
||||
case ON_UPDATE:
|
||||
field.onCreate = false;
|
||||
field.onUpdate = true;
|
||||
break;
|
||||
case ON_CREATE_UPDATE:
|
||||
field.onCreate = true;
|
||||
field.onUpdate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<SchemaField bind:field {key} on:rename on:remove on:duplicate {...$$restProps}>
|
||||
<svelte:fragment let:interactive>
|
||||
<div class="separator" />
|
||||
|
||||
<Field
|
||||
class="form-field form-field-single-multiple-select form-field-autodate-select {!interactive
|
||||
? 'readonly'
|
||||
: ''}"
|
||||
inlineError
|
||||
let:uniqueId
|
||||
>
|
||||
<div use:tooltip={{ text: "Auto set on:", position: "top" }}>
|
||||
<ObjectSelect
|
||||
id={uniqueId}
|
||||
items={options}
|
||||
disabled={field.system}
|
||||
readonly={!interactive}
|
||||
bind:keyOfSelected={selectedOption}
|
||||
/>
|
||||
</div>
|
||||
</Field>
|
||||
|
||||
<div class="separator" />
|
||||
</svelte:fragment>
|
||||
</SchemaField>
|
||||
@@ -1,27 +1,27 @@
|
||||
<script>
|
||||
import Flatpickr from "svelte-flatpickr";
|
||||
import CommonHelper from "@/utils/CommonHelper";
|
||||
import Field from "@/components/base/Field.svelte";
|
||||
import SchemaField from "@/components/collections/schema/SchemaField.svelte";
|
||||
import CommonHelper from "@/utils/CommonHelper";
|
||||
import Flatpickr from "svelte-flatpickr";
|
||||
|
||||
export let field;
|
||||
export let key = "";
|
||||
|
||||
let pickerMinValue = field?.options?.min;
|
||||
let pickerMaxValue = field?.options?.max;
|
||||
let pickerMinValue = field?.min;
|
||||
let pickerMaxValue = field?.max;
|
||||
|
||||
$: if (pickerMinValue != field?.options?.min) {
|
||||
pickerMinValue = field?.options?.min;
|
||||
$: if (pickerMinValue != field?.min) {
|
||||
pickerMinValue = field?.min;
|
||||
}
|
||||
|
||||
$: if (pickerMaxValue != field?.options?.max) {
|
||||
pickerMaxValue = field?.options?.max;
|
||||
$: if (pickerMaxValue != field?.max) {
|
||||
pickerMaxValue = field?.max;
|
||||
}
|
||||
|
||||
// ensure that value is set even on manual input edit
|
||||
function onClose(e, key) {
|
||||
if (e.detail && e.detail.length == 3) {
|
||||
field.options[key] = e.detail[1];
|
||||
field[key] = e.detail[1];
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -30,26 +30,26 @@
|
||||
<svelte:fragment slot="options">
|
||||
<div class="grid grid-sm">
|
||||
<div class="col-sm-6">
|
||||
<Field class="form-field" name="schema.{key}.options.min" let:uniqueId>
|
||||
<Field class="form-field" name="fields.{key}.min" let:uniqueId>
|
||||
<label for={uniqueId}>Min date (UTC)</label>
|
||||
<Flatpickr
|
||||
id={uniqueId}
|
||||
options={CommonHelper.defaultFlatpickrOptions()}
|
||||
bind:value={pickerMinValue}
|
||||
bind:formattedValue={field.options.min}
|
||||
bind:formattedValue={field.min}
|
||||
on:close={(e) => onClose(e, "min")}
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6">
|
||||
<Field class="form-field" name="schema.{key}.options.max" let:uniqueId>
|
||||
<Field class="form-field" name="fields.{key}.max" let:uniqueId>
|
||||
<label for={uniqueId}>Max date (UTC)</label>
|
||||
<Flatpickr
|
||||
id={uniqueId}
|
||||
options={CommonHelper.defaultFlatpickrOptions()}
|
||||
bind:value={pickerMaxValue}
|
||||
bind:formattedValue={field.options.max}
|
||||
bind:formattedValue={field.max}
|
||||
on:close={(e) => onClose(e, "max")}
|
||||
/>
|
||||
</Field>
|
||||
|
||||
@@ -1,27 +1,29 @@
|
||||
<script>
|
||||
import CommonHelper from "@/utils/CommonHelper";
|
||||
import tooltip from "@/actions/tooltip";
|
||||
import Field from "@/components/base/Field.svelte";
|
||||
import SchemaField from "@/components/collections/schema/SchemaField.svelte";
|
||||
|
||||
export let field;
|
||||
export let key = "";
|
||||
|
||||
$: if (CommonHelper.isEmpty(field.options)) {
|
||||
loadDefaults();
|
||||
}
|
||||
|
||||
function loadDefaults() {
|
||||
field.options = {
|
||||
convertUrls: false,
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<SchemaField bind:field {key} on:rename on:remove on:duplicate {...$$restProps}>
|
||||
<svelte:fragment slot="optionsFooter">
|
||||
<Field class="form-field form-field-toggle" name="schema.{key}.options.convertUrls" let:uniqueId>
|
||||
<input type="checkbox" id={uniqueId} bind:checked={field.options.convertUrls} />
|
||||
<svelte:fragment slot="options">
|
||||
<Field class="form-field m-b-sm" name="fields.{key}.maxSize" let:uniqueId>
|
||||
<label for={uniqueId}>Max size <small>(bytes)</small></label>
|
||||
<input
|
||||
type="number"
|
||||
id={uniqueId}
|
||||
step="1"
|
||||
min="0"
|
||||
value={field.maxSize || ""}
|
||||
on:input={(e) => (field.maxSize = e.target.value << 0)}
|
||||
placeholder="Default to max ~5MB"
|
||||
/>
|
||||
</Field>
|
||||
|
||||
<Field class="form-field form-field-toggle" name="fields.{key}.convertURLs" let:uniqueId>
|
||||
<input type="checkbox" id={uniqueId} bind:checked={field.convertURLs} />
|
||||
<label for={uniqueId}>
|
||||
<span class="txt">Strip urls domain</span>
|
||||
<i
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script>
|
||||
import CommonHelper from "@/utils/CommonHelper";
|
||||
import tooltip from "@/actions/tooltip";
|
||||
import Field from "@/components/base/Field.svelte";
|
||||
import MultipleValueInput from "@/components/base/MultipleValueInput.svelte";
|
||||
import SchemaField from "@/components/collections/schema/SchemaField.svelte";
|
||||
import CommonHelper from "@/utils/CommonHelper";
|
||||
|
||||
export let field;
|
||||
export let key = "";
|
||||
@@ -13,7 +13,7 @@
|
||||
<svelte:fragment slot="options">
|
||||
<div class="grid grid-sm">
|
||||
<div class="col-sm-6">
|
||||
<Field class="form-field" name="schema.{key}.options.exceptDomains" let:uniqueId>
|
||||
<Field class="form-field" name="fields.{key}.exceptDomains" let:uniqueId>
|
||||
<label for={uniqueId}>
|
||||
<span class="txt">Except domains</span>
|
||||
<i
|
||||
@@ -26,16 +26,16 @@
|
||||
</label>
|
||||
<MultipleValueInput
|
||||
id={uniqueId}
|
||||
disabled={!CommonHelper.isEmpty(field.options.onlyDomains)}
|
||||
bind:value={field.options.exceptDomains}
|
||||
disabled={!CommonHelper.isEmpty(field.onlyDomains)}
|
||||
bind:value={field.exceptDomains}
|
||||
/>
|
||||
<div class="help-block">Use comma as separator.</div>
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6">
|
||||
<Field class="form-field" name="schema.{key}.options.onlyDomains" let:uniqueId>
|
||||
<label for="{uniqueId}.options.onlyDomains">
|
||||
<Field class="form-field" name="fields.{key}.onlyDomains" let:uniqueId>
|
||||
<label for="{uniqueId}.onlyDomains">
|
||||
<span class="txt">Only domains</span>
|
||||
<i
|
||||
class="ri-information-line link-hint"
|
||||
@@ -46,9 +46,9 @@
|
||||
/>
|
||||
</label>
|
||||
<MultipleValueInput
|
||||
id="{uniqueId}.options.onlyDomains"
|
||||
disabled={!CommonHelper.isEmpty(field.options.exceptDomains)}
|
||||
bind:value={field.options.onlyDomains}
|
||||
id="{uniqueId}.onlyDomains"
|
||||
disabled={!CommonHelper.isEmpty(field.exceptDomains)}
|
||||
bind:value={field.onlyDomains}
|
||||
/>
|
||||
<div class="help-block">Use comma as separator.</div>
|
||||
</Field>
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
];
|
||||
|
||||
let mimeTypesList = baseMimeTypesList.slice();
|
||||
let isSingle = field.options?.maxSelect <= 1;
|
||||
let isSingle = field.maxSelect <= 1;
|
||||
let oldIsSingle = isSingle;
|
||||
|
||||
$: if (CommonHelper.isEmpty(field.options)) {
|
||||
$: if (typeof field.maxSelect == "undefined") {
|
||||
loadDefaults();
|
||||
} else {
|
||||
appendMissingMimeTypes();
|
||||
@@ -30,19 +30,17 @@
|
||||
$: if (oldIsSingle != isSingle) {
|
||||
oldIsSingle = isSingle;
|
||||
if (isSingle) {
|
||||
field.options.maxSelect = 1;
|
||||
field.maxSelect = 1;
|
||||
} else {
|
||||
field.options.maxSelect = field.options?.values?.length || 99;
|
||||
field.maxSelect = 99;
|
||||
}
|
||||
}
|
||||
|
||||
function loadDefaults() {
|
||||
field.options = {
|
||||
maxSelect: 1,
|
||||
maxSize: 5242880,
|
||||
thumbs: [],
|
||||
mimeTypes: [],
|
||||
};
|
||||
field.maxSelect = 1;
|
||||
field.thumbs = [];
|
||||
field.mimeTypes = [];
|
||||
|
||||
isSingle = true;
|
||||
oldIsSingle = isSingle;
|
||||
}
|
||||
@@ -50,13 +48,13 @@
|
||||
// append any previously set custom mime types to the predefined
|
||||
// list for backward compatibility
|
||||
function appendMissingMimeTypes() {
|
||||
if (CommonHelper.isEmpty(field.options.mimeTypes)) {
|
||||
if (CommonHelper.isEmpty(field.mimeTypes)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const missing = [];
|
||||
|
||||
for (const v of field.options.mimeTypes) {
|
||||
for (const v of field.mimeTypes) {
|
||||
if (!!mimeTypesList.find((item) => item.mimeType === v)) {
|
||||
continue; // exist
|
||||
}
|
||||
@@ -93,7 +91,7 @@
|
||||
<svelte:fragment slot="options">
|
||||
<div class="grid grid-sm">
|
||||
<div class="col-sm-12">
|
||||
<Field class="form-field" name="schema.{key}.options.mimeTypes" let:uniqueId>
|
||||
<Field class="form-field" name="fields.{key}.mimeTypes" let:uniqueId>
|
||||
<label for={uniqueId}>
|
||||
<span class="txt">Allowed mime types</span>
|
||||
<i
|
||||
@@ -114,7 +112,7 @@
|
||||
items={mimeTypesList}
|
||||
labelComponent={MimeTypeSelectOption}
|
||||
optionComponent={MimeTypeSelectOption}
|
||||
bind:keyOfSelected={field.options.mimeTypes}
|
||||
bind:keyOfSelected={field.mimeTypes}
|
||||
/>
|
||||
<div class="help-block">
|
||||
<div tabindex="0" role="button" class="inline-flex flex-gap-0">
|
||||
@@ -126,7 +124,7 @@
|
||||
class="dropdown-item closable"
|
||||
role="menuitem"
|
||||
on:click={() => {
|
||||
field.options.mimeTypes = [
|
||||
field.mimeTypes = [
|
||||
"image/jpeg",
|
||||
"image/png",
|
||||
"image/svg+xml",
|
||||
@@ -142,7 +140,7 @@
|
||||
class="dropdown-item closable"
|
||||
role="menuitem"
|
||||
on:click={() => {
|
||||
field.options.mimeTypes = [
|
||||
field.mimeTypes = [
|
||||
"application/pdf",
|
||||
"application/msword",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
@@ -158,7 +156,7 @@
|
||||
class="dropdown-item closable"
|
||||
role="menuitem"
|
||||
on:click={() => {
|
||||
field.options.mimeTypes = [
|
||||
field.mimeTypes = [
|
||||
"video/mp4",
|
||||
"video/x-ms-wmv",
|
||||
"video/quicktime",
|
||||
@@ -173,7 +171,7 @@
|
||||
class="dropdown-item closable"
|
||||
role="menuitem"
|
||||
on:click={() => {
|
||||
field.options.mimeTypes = [
|
||||
field.mimeTypes = [
|
||||
"application/zip",
|
||||
"application/x-7z-compressed",
|
||||
"application/x-rar-compressed",
|
||||
@@ -189,7 +187,7 @@
|
||||
</div>
|
||||
|
||||
<div class={!isSingle ? "col-sm-6" : "col-sm-8"}>
|
||||
<Field class="form-field" name="schema.{key}.options.thumbs" let:uniqueId>
|
||||
<Field class="form-field" name="fields.{key}.thumbs" let:uniqueId>
|
||||
<label for={uniqueId}>
|
||||
<span class="txt">Thumb sizes</span>
|
||||
<i
|
||||
@@ -202,8 +200,8 @@
|
||||
</label>
|
||||
<MultipleValueInput
|
||||
id={uniqueId}
|
||||
placeholder="eg. 50x50, 480x720"
|
||||
bind:value={field.options.thumbs}
|
||||
placeholder="e.g. 50x50, 480x720"
|
||||
bind:value={field.thumbs}
|
||||
/>
|
||||
<div class="help-block">
|
||||
<span class="txt">Use comma as separator.</span>
|
||||
@@ -214,27 +212,27 @@
|
||||
<ul class="m-0">
|
||||
<li>
|
||||
<strong>WxH</strong>
|
||||
(eg. 100x50) - crop to WxH viewbox (from center)
|
||||
(e.g. 100x50) - crop to WxH viewbox (from center)
|
||||
</li>
|
||||
<li>
|
||||
<strong>WxHt</strong>
|
||||
(eg. 100x50t) - crop to WxH viewbox (from top)
|
||||
(e.g. 100x50t) - crop to WxH viewbox (from top)
|
||||
</li>
|
||||
<li>
|
||||
<strong>WxHb</strong>
|
||||
(eg. 100x50b) - crop to WxH viewbox (from bottom)
|
||||
(e.g. 100x50b) - crop to WxH viewbox (from bottom)
|
||||
</li>
|
||||
<li>
|
||||
<strong>WxHf</strong>
|
||||
(eg. 100x50f) - fit inside a WxH viewbox (without cropping)
|
||||
(e.g. 100x50f) - fit inside a WxH viewbox (without cropping)
|
||||
</li>
|
||||
<li>
|
||||
<strong>0xH</strong>
|
||||
(eg. 0x50) - resize to H height preserving the aspect ratio
|
||||
(e.g. 0x50) - resize to H height preserving the aspect ratio
|
||||
</li>
|
||||
<li>
|
||||
<strong>Wx0</strong>
|
||||
(eg. 100x0) - resize to W width preserving the aspect ratio
|
||||
(e.g. 100x0) - resize to W width preserving the aspect ratio
|
||||
</li>
|
||||
</ul>
|
||||
</Toggler>
|
||||
@@ -244,16 +242,24 @@
|
||||
</div>
|
||||
|
||||
<div class={!isSingle ? "col-sm-3" : "col-sm-4"}>
|
||||
<Field class="form-field required" name="schema.{key}.options.maxSize" let:uniqueId>
|
||||
<Field class="form-field" name="fields.{key}.maxSize" let:uniqueId>
|
||||
<label for={uniqueId}>Max file size</label>
|
||||
<input type="number" id={uniqueId} step="1" min="0" bind:value={field.options.maxSize} />
|
||||
<input
|
||||
type="number"
|
||||
id={uniqueId}
|
||||
step="1"
|
||||
min="0"
|
||||
value={field.maxSize || ""}
|
||||
on:input={(e) => (field.maxSize = e.target.value << 0)}
|
||||
placeholder="Default to max ~5MB"
|
||||
/>
|
||||
<div class="help-block">Must be in bytes.</div>
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
{#if !isSingle}
|
||||
<div class="col-sm-3">
|
||||
<Field class="form-field required" name="schema.{key}.options.maxSelect" let:uniqueId>
|
||||
<Field class="form-field" name="fields.{key}.maxSelect" let:uniqueId>
|
||||
<label for={uniqueId}>Max select</label>
|
||||
<input
|
||||
id={uniqueId}
|
||||
@@ -261,29 +267,31 @@
|
||||
step="1"
|
||||
min="2"
|
||||
required
|
||||
bind:value={field.options.maxSelect}
|
||||
placeholder="Default to single"
|
||||
bind:value={field.maxSelect}
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="optionsFooter">
|
||||
<Field class="form-field form-field-toggle" name="schema.{key}.options.protected" let:uniqueId>
|
||||
<input type="checkbox" id={uniqueId} bind:checked={field.options.protected} />
|
||||
<label for={uniqueId}>
|
||||
<span class="txt">Protected</span>
|
||||
</label>
|
||||
<a
|
||||
href={import.meta.env.PB_PROTECTED_FILE_DOCS}
|
||||
class="toggle-info txt-sm txt-hint m-l-5"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
(Learn more)
|
||||
</a>
|
||||
</Field>
|
||||
<Field class="form-field form-field-toggle" name="fields.{key}.protected" let:uniqueId>
|
||||
<input type="checkbox" id={uniqueId} bind:checked={field.protected} />
|
||||
<label for={uniqueId}>
|
||||
<span class="txt">Protected</span>
|
||||
</label>
|
||||
<small class="txt-hint">
|
||||
it will require View API rule permissions and file token to be accessible
|
||||
<a
|
||||
href={import.meta.env.PB_PROTECTED_FILE_DOCS}
|
||||
class="toggle-info"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>
|
||||
(Learn more)
|
||||
</a>
|
||||
</small>
|
||||
</Field>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</SchemaField>
|
||||
|
||||
|
||||
@@ -1,30 +1,27 @@
|
||||
<script>
|
||||
import { slide } from "svelte/transition";
|
||||
import CommonHelper from "@/utils/CommonHelper";
|
||||
import Field from "@/components/base/Field.svelte";
|
||||
import SchemaField from "@/components/collections/schema/SchemaField.svelte";
|
||||
import { slide } from "svelte/transition";
|
||||
|
||||
export let field;
|
||||
export let key = "";
|
||||
|
||||
let showInfo = false;
|
||||
|
||||
$: if (CommonHelper.isEmpty(field.options)) {
|
||||
loadDefaults();
|
||||
}
|
||||
|
||||
function loadDefaults() {
|
||||
field.options = {
|
||||
maxSize: 2000000,
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<SchemaField bind:field {key} on:rename on:remove on:duplicate {...$$restProps}>
|
||||
<svelte:fragment slot="options">
|
||||
<Field class="form-field required m-b-sm" name="schema.{key}.options.maxSize" let:uniqueId>
|
||||
<Field class="form-field m-b-sm" name="fields.{key}.maxSize" let:uniqueId>
|
||||
<label for={uniqueId}>Max size <small>(bytes)</small></label>
|
||||
<input type="number" id={uniqueId} step="1" min="0" bind:value={field.options.maxSize} />
|
||||
<input
|
||||
type="number"
|
||||
id={uniqueId}
|
||||
step="1"
|
||||
min="0"
|
||||
value={field.maxSize || ""}
|
||||
on:input={(e) => (field.maxSize = e.target.value << 0)}
|
||||
placeholder="Default to max ~5MB"
|
||||
/>
|
||||
</Field>
|
||||
|
||||
<button
|
||||
|
||||
@@ -11,29 +11,24 @@
|
||||
<svelte:fragment slot="options">
|
||||
<div class="grid grid-sm">
|
||||
<div class="col-sm-6">
|
||||
<Field class="form-field" name="schema.{key}.options.min" let:uniqueId>
|
||||
<Field class="form-field" name="fields.{key}.min" let:uniqueId>
|
||||
<label for={uniqueId}>Min</label>
|
||||
<input type="number" id={uniqueId} bind:value={field.options.min} />
|
||||
<input type="number" id={uniqueId} bind:value={field.min} />
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6">
|
||||
<Field class="form-field" name="schema.{key}.options.max" let:uniqueId>
|
||||
<Field class="form-field" name="fields.{key}.max" let:uniqueId>
|
||||
<label for={uniqueId}>Max</label>
|
||||
<input
|
||||
type="number"
|
||||
id={uniqueId}
|
||||
min={field.options.min}
|
||||
bind:value={field.options.max}
|
||||
/>
|
||||
<input type="number" id={uniqueId} min={field.min} bind:value={field.max} />
|
||||
</Field>
|
||||
</div>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
|
||||
<svelte:fragment slot="optionsFooter">
|
||||
<Field class="form-field form-field-toggle" name="schema.{key}.options.noDecimal" let:uniqueId>
|
||||
<input type="checkbox" id={uniqueId} bind:checked={field.options.noDecimal} />
|
||||
<Field class="form-field form-field-toggle" name="fields.{key}.onlyInt" let:uniqueId>
|
||||
<input type="checkbox" id={uniqueId} bind:checked={field.onlyInt} />
|
||||
<label for={uniqueId}>
|
||||
<span class="txt">No decimals</span>
|
||||
<i
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<script>
|
||||
import Field from "@/components/base/Field.svelte";
|
||||
import SchemaField from "@/components/collections/schema/SchemaField.svelte";
|
||||
import CommonHelper from "@/utils/CommonHelper";
|
||||
|
||||
export let field;
|
||||
export let key = "";
|
||||
|
||||
$: if (CommonHelper.isEmpty(field.id)) {
|
||||
loadDefaults();
|
||||
}
|
||||
|
||||
function loadDefaults() {
|
||||
field.cost = 11;
|
||||
}
|
||||
</script>
|
||||
|
||||
<SchemaField bind:field {key} on:rename on:remove on:duplicate {...$$restProps}>
|
||||
<svelte:fragment slot="options">
|
||||
<div class="grid grid-sm">
|
||||
<div class="col-sm-6">
|
||||
<Field class="form-field" name="fields.{key}.min" let:uniqueId>
|
||||
<label for={uniqueId}>Min length</label>
|
||||
<input
|
||||
type="number"
|
||||
id={uniqueId}
|
||||
step="1"
|
||||
min="0"
|
||||
placeholder="No min limit"
|
||||
value={field.min || ""}
|
||||
on:input={(e) => (field.min = e.target.value << 0)}
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6">
|
||||
<Field class="form-field" name="fields.{key}.max" let:uniqueId>
|
||||
<label for={uniqueId}>Max length</label>
|
||||
<input
|
||||
type="number"
|
||||
id={uniqueId}
|
||||
step="1"
|
||||
placeholder="Up to 71 chars"
|
||||
min={field.min || 0}
|
||||
max="71"
|
||||
value={field.max || ""}
|
||||
on:input={(e) => (field.max = e.target.value << 0)}
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6">
|
||||
<Field class="form-field" name="fields.{key}.cost" let:uniqueId>
|
||||
<label for={uniqueId}>Bcrypt cost</label>
|
||||
<input
|
||||
type="number"
|
||||
id={uniqueId}
|
||||
placeholder="Default to 10"
|
||||
step="1"
|
||||
min="6"
|
||||
max="31"
|
||||
value={field.cost || ""}
|
||||
on:input={(e) => (field.cost = e.target.value << 0)}
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6">
|
||||
<Field class="form-field" name="fields.{key}.pattern" let:uniqueId>
|
||||
<label for={uniqueId}>Validation pattern</label>
|
||||
<input type="text" id={uniqueId} placeholder="ex. ^\w+$" bind:value={field.pattern} />
|
||||
</Field>
|
||||
</div>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</SchemaField>
|
||||
@@ -1,8 +1,6 @@
|
||||
<script>
|
||||
import CommonHelper from "@/utils/CommonHelper";
|
||||
import tooltip from "@/actions/tooltip";
|
||||
import Field from "@/components/base/Field.svelte";
|
||||
import Select from "@/components/base/Select.svelte";
|
||||
import ObjectSelect from "@/components/base/ObjectSelect.svelte";
|
||||
import CollectionUpsertPanel from "@/components/collections/CollectionUpsertPanel.svelte";
|
||||
import SchemaField from "@/components/collections/schema/SchemaField.svelte";
|
||||
@@ -22,34 +20,32 @@
|
||||
];
|
||||
|
||||
let upsertPanel = null;
|
||||
let isSingle = field.options?.maxSelect == 1;
|
||||
let isSingle = field.maxSelect <= 1;
|
||||
let oldIsSingle = isSingle;
|
||||
|
||||
$: selectCollections = $collections.filter((c) => c.type != "view");
|
||||
$: selectCollections = $collections.filter((c) => !c.system && c.type != "view");
|
||||
|
||||
// load defaults
|
||||
$: if (CommonHelper.isEmpty(field.options)) {
|
||||
$: if (typeof field.maxSelect == "undefined") {
|
||||
loadDefaults();
|
||||
}
|
||||
|
||||
$: if (oldIsSingle != isSingle) {
|
||||
oldIsSingle = isSingle;
|
||||
if (isSingle) {
|
||||
field.options.minSelect = null;
|
||||
field.options.maxSelect = 1;
|
||||
field.minSelect = 0;
|
||||
field.maxSelect = 1;
|
||||
} else {
|
||||
field.options.maxSelect = null;
|
||||
field.maxSelect = 999;
|
||||
}
|
||||
}
|
||||
|
||||
$: selectedColection = $collections.find((c) => c.id == field.options.collectionId) || null;
|
||||
$: selectedColection = $collections.find((c) => c.id == field.collectionId) || null;
|
||||
|
||||
function loadDefaults() {
|
||||
field.options = {
|
||||
maxSelect: 1,
|
||||
collectionId: null,
|
||||
cascadeDelete: false,
|
||||
};
|
||||
field.maxSelect = 1;
|
||||
field.collectionId = null;
|
||||
field.cascadeDelete = false;
|
||||
isSingle = true;
|
||||
oldIsSingle = isSingle;
|
||||
}
|
||||
@@ -62,7 +58,7 @@
|
||||
<Field
|
||||
class="form-field required {!interactive ? 'readonly' : ''}"
|
||||
inlineError
|
||||
name="schema.{key}.options.collectionId"
|
||||
name="fields.{key}.collectionId"
|
||||
let:uniqueId
|
||||
>
|
||||
<ObjectSelect
|
||||
@@ -73,7 +69,7 @@
|
||||
selectionKey="id"
|
||||
items={selectCollections}
|
||||
readonly={!interactive || field.id}
|
||||
bind:keyOfSelected={field.options.collectionId}
|
||||
bind:keyOfSelected={field.collectionId}
|
||||
>
|
||||
<svelte:fragment slot="afterOptions">
|
||||
<hr />
|
||||
@@ -111,35 +107,36 @@
|
||||
<div class="grid grid-sm">
|
||||
{#if !isSingle}
|
||||
<div class="col-sm-6">
|
||||
<Field class="form-field" name="schema.{key}.options.minSelect" let:uniqueId>
|
||||
<Field class="form-field" name="fields.{key}.minSelect" let:uniqueId>
|
||||
<label for={uniqueId}>Min select</label>
|
||||
<input
|
||||
type="number"
|
||||
id={uniqueId}
|
||||
step="1"
|
||||
min="1"
|
||||
min="0"
|
||||
placeholder="No min limit"
|
||||
bind:value={field.options.minSelect}
|
||||
value={field.minSelect || ""}
|
||||
on:input={(e) => (field.minSelect = e.target.value << 0)}
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<Field class="form-field" name="schema.{key}.options.maxSelect" let:uniqueId>
|
||||
<Field class="form-field" name="fields.{key}.maxSelect" let:uniqueId>
|
||||
<label for={uniqueId}>Max select</label>
|
||||
<input
|
||||
type="number"
|
||||
id={uniqueId}
|
||||
step="1"
|
||||
placeholder="No max limit"
|
||||
min={field.options.minSelect || 2}
|
||||
bind:value={field.options.maxSelect}
|
||||
placeholder="Default to single"
|
||||
min={field.minSelect || 1}
|
||||
bind:value={field.maxSelect}
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="col-sm-12">
|
||||
<Field class="form-field" name="schema.{key}.options.cascadeDelete" let:uniqueId>
|
||||
<Field class="form-field" name="fields.{key}.cascadeDelete" let:uniqueId>
|
||||
<label for={uniqueId}>
|
||||
<span class="txt">Cascade delete</span>
|
||||
<!-- prettier-ignore -->
|
||||
@@ -157,7 +154,7 @@
|
||||
<ObjectSelect
|
||||
id={uniqueId}
|
||||
items={defaultOptions}
|
||||
bind:keyOfSelected={field.options.cascadeDelete}
|
||||
bind:keyOfSelected={field.cascadeDelete}
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
@@ -169,7 +166,7 @@
|
||||
bind:this={upsertPanel}
|
||||
on:save={(e) => {
|
||||
if (e?.detail?.collection?.id && e.detail.collection.type != "view") {
|
||||
field.options.collectionId = e.detail.collection.id;
|
||||
field.collectionId = e.detail.collection.id;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -1,10 +1,9 @@
|
||||
<script>
|
||||
import CommonHelper from "@/utils/CommonHelper";
|
||||
import tooltip from "@/actions/tooltip";
|
||||
import Field from "@/components/base/Field.svelte";
|
||||
import MultipleValueInput from "@/components/base/MultipleValueInput.svelte";
|
||||
import ObjectSelect from "@/components/base/ObjectSelect.svelte";
|
||||
import SchemaField from "@/components/collections/schema/SchemaField.svelte";
|
||||
import MultipleValueInput from "@/components/base/MultipleValueInput.svelte";
|
||||
|
||||
export let field;
|
||||
export let key = "";
|
||||
@@ -14,27 +13,25 @@
|
||||
{ label: "Multiple", value: false },
|
||||
];
|
||||
|
||||
let isSingle = field.options?.maxSelect <= 1;
|
||||
let isSingle = field.maxSelect <= 1;
|
||||
let oldIsSingle = isSingle;
|
||||
|
||||
$: if (CommonHelper.isEmpty(field.options)) {
|
||||
$: if (typeof field.maxSelect == "undefined") {
|
||||
loadDefaults();
|
||||
}
|
||||
|
||||
$: if (oldIsSingle != isSingle) {
|
||||
oldIsSingle = isSingle;
|
||||
if (isSingle) {
|
||||
field.options.maxSelect = 1;
|
||||
field.maxSelect = 1;
|
||||
} else {
|
||||
field.options.maxSelect = field.options?.values?.length || 2;
|
||||
field.maxSelect = field.values?.length || 2;
|
||||
}
|
||||
}
|
||||
|
||||
function loadDefaults() {
|
||||
field.options = {
|
||||
maxSelect: 1,
|
||||
values: [],
|
||||
};
|
||||
field.maxSelect = 1;
|
||||
field.values = [];
|
||||
isSingle = true;
|
||||
oldIsSingle = isSingle;
|
||||
}
|
||||
@@ -47,7 +44,7 @@
|
||||
<Field
|
||||
class="form-field required {!interactive ? 'readonly' : ''}"
|
||||
inlineError
|
||||
name="schema.{key}.options.values"
|
||||
name="fields.{key}.values"
|
||||
let:uniqueId
|
||||
>
|
||||
<div use:tooltip={{ text: "Choices (comma separated)", position: "top-left", delay: 700 }}>
|
||||
@@ -56,7 +53,7 @@
|
||||
placeholder="Choices: eg. optionA, optionB"
|
||||
required
|
||||
readonly={!interactive}
|
||||
bind:value={field.options.values}
|
||||
bind:value={field.values}
|
||||
/>
|
||||
</div>
|
||||
</Field>
|
||||
@@ -81,15 +78,16 @@
|
||||
|
||||
<svelte:fragment slot="options">
|
||||
{#if !isSingle}
|
||||
<Field class="form-field required" name="schema.{key}.options.maxSelect" let:uniqueId>
|
||||
<Field class="form-field" name="fields.{key}.maxSelect" let:uniqueId>
|
||||
<label for={uniqueId}>Max select</label>
|
||||
<input
|
||||
id={uniqueId}
|
||||
type="number"
|
||||
step="1"
|
||||
min="2"
|
||||
required
|
||||
bind:value={field.options.maxSelect}
|
||||
max={field.values.length}
|
||||
placeholder="Default to single"
|
||||
bind:value={field.maxSelect}
|
||||
/>
|
||||
</Field>
|
||||
{/if}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script>
|
||||
import SchemaField from "@/components/collections/schema/SchemaField.svelte";
|
||||
import tooltip from "@/actions/tooltip";
|
||||
import Field from "@/components/base/Field.svelte";
|
||||
import SchemaField from "@/components/collections/schema/SchemaField.svelte";
|
||||
|
||||
export let field;
|
||||
export let key = "";
|
||||
@@ -9,37 +10,73 @@
|
||||
<SchemaField bind:field {key} on:rename on:remove on:duplicate {...$$restProps}>
|
||||
<svelte:fragment slot="options">
|
||||
<div class="grid grid-sm">
|
||||
<div class="col-sm-3">
|
||||
<Field class="form-field" name="schema.{key}.options.min" let:uniqueId>
|
||||
<label for={uniqueId}>Min length</label>
|
||||
<input type="number" id={uniqueId} step="1" min="0" bind:value={field.options.min} />
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-3">
|
||||
<Field class="form-field" name="schema.{key}.options.max" let:uniqueId>
|
||||
<label for={uniqueId}>Max length</label>
|
||||
<div class="col-sm-6">
|
||||
<Field class="form-field" name="fields.{key}.min" let:uniqueId>
|
||||
<label for={uniqueId}>
|
||||
<span class="txt">Min length</span>
|
||||
<i
|
||||
class="ri-information-line link-hint"
|
||||
use:tooltip={"Clear the field or set it to 0 for no limit."}
|
||||
/>
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
id={uniqueId}
|
||||
step="1"
|
||||
min={field.options.min || 0}
|
||||
bind:value={field.options.max}
|
||||
min="0"
|
||||
placeholder="No min limit"
|
||||
value={field.min || ""}
|
||||
on:input={(e) => (field.min = e.target.value << 0)}
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6">
|
||||
<Field class="form-field" name="schema.{key}.options.pattern" let:uniqueId>
|
||||
<label for={uniqueId}>Regex pattern</label>
|
||||
<Field class="form-field" name="fields.{key}.max" let:uniqueId>
|
||||
<label for={uniqueId}>
|
||||
<span class="txt">Max length</span>
|
||||
<i
|
||||
class="ri-information-line link-hint"
|
||||
use:tooltip={"Clear the field or set it to 0 to fallback to the default limit."}
|
||||
/>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
type="number"
|
||||
id={uniqueId}
|
||||
placeholder={"Valid Go regular expression, eg. ^\\w+$"}
|
||||
bind:value={field.options.pattern}
|
||||
step="1"
|
||||
placeholder="Default to max 5000 characters"
|
||||
min={field.min || 0}
|
||||
value={field.max || ""}
|
||||
on:input={(e) => (field.max = e.target.value << 0)}
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6">
|
||||
<Field class="form-field" name="fields.{key}.pattern" let:uniqueId>
|
||||
<label for={uniqueId}>Validation pattern</label>
|
||||
<input type="text" id={uniqueId} bind:value={field.pattern} />
|
||||
<div class="help-block">
|
||||
<p>Ex. <code>{"^[a-z0-9]+$"}</code></p>
|
||||
</div>
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6">
|
||||
<Field class="form-field" name="fields.{key}.pattern" let:uniqueId>
|
||||
<label for={uniqueId}>
|
||||
<span class="txt">Autogenerate pattern</span>
|
||||
<i
|
||||
class="ri-information-line link-hint"
|
||||
use:tooltip={"Set and autogenerate text matching the pattern on missing record create value."}
|
||||
/>
|
||||
</label>
|
||||
<input type="text" id={uniqueId} bind:value={field.autogeneratePattern} />
|
||||
<div class="help-block">
|
||||
<p>Ex. <code>{"[a-z0-9]{30}"}</code></p>
|
||||
</div>
|
||||
</Field>
|
||||
</div>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</SchemaField>
|
||||
Reference in new issue
Block a user