diff --git a/packages/bbui/src/Form/Core/Multiselect.svelte b/packages/bbui/src/Form/Core/Multiselect.svelte index 2243570cd5..4873430fa0 100644 --- a/packages/bbui/src/Form/Core/Multiselect.svelte +++ b/packages/bbui/src/Form/Core/Multiselect.svelte @@ -17,6 +17,8 @@ export let customPopoverHeight export let open = false export let loading + export let onOptionMouseenter = () => {} + export let onOptionMouseleave = () => {} const dispatch = createEventDispatcher() @@ -97,4 +99,6 @@ {autoWidth} {customPopoverHeight} {loading} + {onOptionMouseenter} + {onOptionMouseleave} /> diff --git a/packages/bbui/src/Form/Core/Picker.svelte b/packages/bbui/src/Form/Core/Picker.svelte index eb7a5db655..c6d4ed3353 100644 --- a/packages/bbui/src/Form/Core/Picker.svelte +++ b/packages/bbui/src/Form/Core/Picker.svelte @@ -41,6 +41,8 @@ export let footer = null export let customAnchor = null export let loading + export let onOptionMouseenter = () => {} + export let onOptionMouseleave = () => {} const dispatch = createEventDispatcher() @@ -199,6 +201,8 @@ aria-selected="true" tabindex="0" on:click={() => onSelectOption(getOptionValue(option, idx))} + on:mouseenter={e => onOptionMouseenter(e, option)} + on:mouseleave={e => onOptionMouseleave(e, option)} class:is-disabled={!isOptionEnabled(option)} > {#if getOptionIcon(option, idx)} diff --git a/packages/bbui/src/Form/Core/Select.svelte b/packages/bbui/src/Form/Core/Select.svelte index 5754c683ed..0111bd6bcf 100644 --- a/packages/bbui/src/Form/Core/Select.svelte +++ b/packages/bbui/src/Form/Core/Select.svelte @@ -26,6 +26,8 @@ export let tag = null export let searchTerm = null export let loading + export let onOptionMouseenter = () => {} + export let onOptionMouseleave = () => {} const dispatch = createEventDispatcher() @@ -95,6 +97,8 @@ {autocomplete} {sort} {tag} + {onOptionMouseenter} + {onOptionMouseleave} isPlaceholder={value == null || value === ""} placeholderOption={placeholder === false ? null : placeholder} isOptionSelected={option => compareOptionAndValue(option, value)} diff --git a/packages/bbui/src/Form/Core/Signature.svelte b/packages/bbui/src/Form/Core/Signature.svelte new file mode 100644 index 0000000000..729d3ac5e2 --- /dev/null +++ b/packages/bbui/src/Form/Core/Signature.svelte @@ -0,0 +1,267 @@ + + +
+ {#if !disabled} +
+ {#if updated && saveIcon} + + { + dispatch("change", toDataUrl()) + }} + /> + + {/if} + {#if signatureFile?.url && !updated} + + { + if (editable) { + clearCanvas() + } + dispatch("clear") + }} + /> + + {/if} +
+ {/if} + {#if !editable && signatureFile?.url} + + {#if !urlFailed} + { + urlFailed = true + }} + /> + {:else} + Could not load signature + {/if} + {:else} +
+ + {#if editable} +
+
+ +
+
+
+ {/if} +
+ {/if} +
+ + diff --git a/packages/bbui/src/Form/Core/index.js b/packages/bbui/src/Form/Core/index.js index 7117b90081..6395fe2fac 100644 --- a/packages/bbui/src/Form/Core/index.js +++ b/packages/bbui/src/Form/Core/index.js @@ -16,3 +16,4 @@ export { default as CoreStepper } from "./Stepper.svelte" export { default as CoreRichTextField } from "./RichTextField.svelte" export { default as CoreSlider } from "./Slider.svelte" export { default as CoreFile } from "./File.svelte" +export { default as CoreSignature } from "./Signature.svelte" diff --git a/packages/bbui/src/Form/Multiselect.svelte b/packages/bbui/src/Form/Multiselect.svelte index b0246c8530..9878605f4b 100644 --- a/packages/bbui/src/Form/Multiselect.svelte +++ b/packages/bbui/src/Form/Multiselect.svelte @@ -19,6 +19,8 @@ export let searchTerm = null export let customPopoverHeight export let helpText = null + export let onOptionMouseenter = () => {} + export let onOptionMouseleave = () => {} const dispatch = createEventDispatcher() const onChange = e => { @@ -41,6 +43,8 @@ {autoWidth} {autocomplete} {customPopoverHeight} + {onOptionMouseenter} + {onOptionMouseleave} bind:searchTerm on:change={onChange} on:click diff --git a/packages/bbui/src/Form/Select.svelte b/packages/bbui/src/Form/Select.svelte index 2119a37980..260090c7b7 100644 --- a/packages/bbui/src/Form/Select.svelte +++ b/packages/bbui/src/Form/Select.svelte @@ -29,6 +29,9 @@ export let tag = null export let helpText = null export let compare + export let onOptionMouseenter = () => {} + export let onOptionMouseleave = () => {} + const dispatch = createEventDispatcher() const onChange = e => { value = e.detail @@ -67,6 +70,8 @@ {customPopoverHeight} {tag} {compare} + {onOptionMouseenter} + {onOptionMouseleave} on:change={onChange} on:click /> diff --git a/packages/bbui/src/Modal/Modal.svelte b/packages/bbui/src/Modal/Modal.svelte index be9c338892..4656be69d1 100644 --- a/packages/bbui/src/Modal/Modal.svelte +++ b/packages/bbui/src/Modal/Modal.svelte @@ -173,6 +173,7 @@ } .spectrum-Modal { + border: 2px solid var(--spectrum-global-color-gray-200); overflow: visible; max-height: none; margin: 40px 0; diff --git a/packages/bbui/src/Modal/ModalContent.svelte b/packages/bbui/src/Modal/ModalContent.svelte index 189ef70c2b..61ceaeb00a 100644 --- a/packages/bbui/src/Modal/ModalContent.svelte +++ b/packages/bbui/src/Modal/ModalContent.svelte @@ -27,6 +27,7 @@ export let secondaryButtonText = undefined export let secondaryAction = undefined export let secondaryButtonWarning = false + export let custom = false const { hide, cancel } = getContext(Context.Modal) let loading = false @@ -63,12 +64,13 @@ class:spectrum-Dialog--medium={size === "M"} class:spectrum-Dialog--large={size === "L"} class:spectrum-Dialog--extraLarge={size === "XL"} + class:no-grid={custom} style="position: relative;" role="dialog" tabindex="-1" aria-modal="true" > -
+
+
+ +
diff --git a/packages/builder/src/components/automation/AutomationPanel/AutomationPanel.svelte b/packages/builder/src/components/automation/AutomationPanel/AutomationPanel.svelte index ac1c4f91cb..7898e13ec8 100644 --- a/packages/builder/src/components/automation/AutomationPanel/AutomationPanel.svelte +++ b/packages/builder/src/components/automation/AutomationPanel/AutomationPanel.svelte @@ -61,6 +61,7 @@ selected={automation._id === selectedAutomationId} on:click={() => selectAutomation(automation._id)} selectedBy={$userSelectedResourceMap[automation._id]} + disabled={automation.disabled} > diff --git a/packages/builder/src/components/automation/AutomationPanel/EditAutomationPopover.svelte b/packages/builder/src/components/automation/AutomationPanel/EditAutomationPopover.svelte index 1bc4b0f18e..9465374ae2 100644 --- a/packages/builder/src/components/automation/AutomationPanel/EditAutomationPopover.svelte +++ b/packages/builder/src/components/automation/AutomationPanel/EditAutomationPopover.svelte @@ -39,6 +39,15 @@ >Duplicate Edit + + {automation.disabled ? "Activate" : "Pause"} + Delete diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte index 879927343f..85ae1924d0 100644 --- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte +++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte @@ -364,6 +364,7 @@ value.customType !== "cron" && value.customType !== "triggerSchema" && value.customType !== "automationFields" && + value.type !== "signature_single" && value.type !== "attachment" && value.type !== "attachment_single" ) @@ -456,7 +457,7 @@ value={inputData[key]} options={Object.keys(table?.schema || {})} /> - {:else if value.type === "attachment"} + {:else if value.type === "attachment" || value.type === "signature_single"}
diff --git a/packages/builder/src/components/automation/SetupPanel/RowSelector.svelte b/packages/builder/src/components/automation/SetupPanel/RowSelector.svelte index ab020aad08..b5a54138ca 100644 --- a/packages/builder/src/components/automation/SetupPanel/RowSelector.svelte +++ b/packages/builder/src/components/automation/SetupPanel/RowSelector.svelte @@ -24,6 +24,11 @@ let table let schemaFields + let attachmentTypes = [ + FieldType.ATTACHMENTS, + FieldType.ATTACHMENT_SINGLE, + FieldType.SIGNATURE_SINGLE, + ] $: { table = $tables.list.find(table => table._id === value?.tableId) @@ -120,15 +125,9 @@ {#if schemaFields.length} {#each schemaFields as [field, schema]} {#if !schema.autocolumn} -
+
-
+
{#if isTestModal} onChange(e, field)} useLabel={false} /> -{:else if schema.type === FieldType.ATTACHMENTS || schema.type === FieldType.ATTACHMENT_SINGLE} +{:else if attachmentTypes.includes(schema.type)}
onChange( { detail: - schema.type === FieldType.ATTACHMENT_SINGLE + schema.type === FieldType.ATTACHMENT_SINGLE || + schema.type === FieldType.SIGNATURE_SINGLE ? e.detail.length > 0 - ? { url: e.detail[0].name, filename: e.detail[0].value } + ? { + url: e.detail[0].name, + filename: e.detail[0].value, + } : {} : e.detail.map(({ name, value }) => ({ url: name, @@ -125,7 +136,8 @@ customButtonText={"Add attachment"} keyPlaceholder={"URL"} valuePlaceholder={"Filename"} - actionButtonDisabled={schema.type === FieldType.ATTACHMENT_SINGLE && + actionButtonDisabled={(schema.type === FieldType.ATTACHMENT_SINGLE || + schema.type === FieldType.SIGNATURE) && Object.keys(value[field]).length >= 1} />
diff --git a/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte b/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte index 4ff8ae994b..1a6bb86113 100644 --- a/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte +++ b/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte @@ -1,4 +1,5 @@ + { + const signatureFile = sigCanvas.toFile() + + let attachRequest = new FormData() + attachRequest.append("file", signatureFile) + + try { + const uploadReq = await API.uploadBuilderAttachment(attachRequest) + const [signatureAttachment] = uploadReq + value = signatureAttachment + } catch (error) { + $notifications.error(error.message || "Failed to save signature") + value = [] + } + }} + title={meta.name} + {value} + bind:this={signatureModal} +/> + {#if type === "options" && meta.constraints.inclusion.length !== 0} {/if} + + diff --git a/packages/builder/src/components/backend/DataTable/TableDataTable.svelte b/packages/builder/src/components/backend/DataTable/TableDataTable.svelte index 26972ede16..e8e1008e3c 100644 --- a/packages/builder/src/components/backend/DataTable/TableDataTable.svelte +++ b/packages/builder/src/components/backend/DataTable/TableDataTable.svelte @@ -1,6 +1,6 @@ - { - if (!open) { - popover.show() - open = true - } - }} -/> + { - drawers = [] - $draggable.actions.select(componentInstance._id) - }} - on:close={() => { - open = false - if ($draggable.selected === componentInstance._id) { - $draggable.actions.select() - } - }} + open={isOpen} + on:close={close} {anchor} align="left-outside" showPopover={drawers.length === 0} clickOutsideOverride={drawers.length > 0} maxHeight={600} offset={18} - handlePostionUpdate={customPositionHandler} > diff --git a/packages/builder/src/components/design/settings/controls/EditComponentPopover/index.js b/packages/builder/src/components/design/settings/controls/EditComponentPopover/index.js deleted file mode 100644 index 2dc3f60185..0000000000 --- a/packages/builder/src/components/design/settings/controls/EditComponentPopover/index.js +++ /dev/null @@ -1,18 +0,0 @@ -export const customPositionHandler = (anchorBounds, eleBounds, cfg) => { - let { left, top, offset } = cfg - let percentageOffset = 30 - // left-outside - left = anchorBounds.left - eleBounds.width - (offset || 5) - - // shift up from the anchor, if space allows - let offsetPos = Math.floor(eleBounds.height / 100) * percentageOffset - let defaultTop = anchorBounds.top - offsetPos - - if (window.innerHeight - defaultTop < eleBounds.height) { - top = window.innerHeight - eleBounds.height - 5 - } else { - top = anchorBounds.top - offsetPos - } - - return { ...cfg, left, top } -} diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/index.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/index.svelte new file mode 100644 index 0000000000..d9714c2e7a --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/index.svelte @@ -0,0 +1,48 @@ + + + +
+ {#if subject === subjects.column} + + {:else if subject === subjects.support} + + {:else if subject === subjects.stringsAsNumbers} + + {:else if subject === subjects.notRequired} + + {:else if subject === subjects.datesAsNumbers} + + {:else if subject === subjects.scalarJsonOnly} + + {:else if subject === subjects.numbersAsDates} + + {:else if subject === subjects.stringsAsDates} + + {/if} +
+
+ + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/Column.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/Column.svelte new file mode 100644 index 0000000000..7fbac09827 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/Column.svelte @@ -0,0 +1,147 @@ + + + +
+ Column Overview for {columnName} +
+
+ {#if schema.type === "string"} + + {:else if schema.type === "datetime"} + + + + + {:else if schema.type === "number"} + + + {:else if schema.type === "array"} + {#each schema?.constraints?.inclusion ?? [] as option, index} + + {option} + + {/each} + {:else if schema.type === "options"} + {#each schema?.constraints?.inclusion ?? [] as option, index} + + {option} + + {/each} + {:else if schema.type === "json"} + + + + {:else if schema.type === "formula"} + + + + + {:else if schema.type === "link"} + + table._id === schema?.tableId) + ?.name} + /> + + {:else if schema.type === "bb_reference"} + + {/if} + +
+
+ + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/DatesAsNumbers.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/DatesAsNumbers.svelte new file mode 100644 index 0000000000..e5cab5dc15 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/DatesAsNumbers.svelte @@ -0,0 +1,63 @@ + + + +
+ A datetime value can be used in place of a numeric value, but it will be + converted to a UNIX time timestamp, which is the number of milliseconds + since Jan 1st 1970. A more recent moment in time will be a higher number. +
+ + + + + {new Date(946684800000).toLocaleString()} + + {"->"} 946684800000 + + + + {new Date(1577836800000).toLocaleString()} + + {"->"} 1577836800000 + + + Now{"->"} {timestamp} + + +
+ + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/NotRequired.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/NotRequired.svelte new file mode 100644 index 0000000000..f28e9a227e --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/NotRequired.svelte @@ -0,0 +1,11 @@ + + + +
+ A required constraint can be applied to columns to ensure a value + is always present. If a column doesn't have this constraint, then its value for + a particular row could he missing. +
+
diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/NumbersAsDates.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/NumbersAsDates.svelte new file mode 100644 index 0000000000..d69228544e --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/NumbersAsDates.svelte @@ -0,0 +1,65 @@ + + + +
+ A number value can be used in place of a datetime value, but it will be + parsed as a UNIX time timestamp, which is the number of milliseconds + since Jan 1st 1970. A more recent moment in time will be a higher number. +
+ + + + 946684800000 + {"->"} + + {new Date(946684800000).toLocaleString()} + + + + 1577836800000 + {"->"} + + {new Date(1577836800000).toLocaleString()} + + + + {timestamp} + {"->"} + Now + + +
+ + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/ScalarJsonOnly.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/ScalarJsonOnly.svelte new file mode 100644 index 0000000000..11fe3c7838 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/ScalarJsonOnly.svelte @@ -0,0 +1,71 @@ + + + +
+ JSON objects can't be used here, but any number, string or boolean values nested within said + object can be if they are otherwise compatible with the input. These scalar values + can be selected from the same menu as this parent and take the form parent.child. +
+ + {#if scalarDescendants.length > 0} + + {#each scalarDescendants as descendant} + + {descendant.name}-{descendant.type} + + {/each} + + {/if} +
+ + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/StringsAsDates.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/StringsAsDates.svelte new file mode 100644 index 0000000000..7303eac7cb --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/StringsAsDates.svelte @@ -0,0 +1,107 @@ + + + +
+ A string value can be used in place of a datetime value, but it will be + parsed as: +
+
+ A UNIX time timestamp, which is the number of milliseconds since + Jan 1st 1970. A more recent moment in time will be a higher number. +
+ + + + 946684800000 + {"->"} + + {new Date(946684800000).toLocaleString()} + + + + 1577836800000 + {"->"} + + {new Date(1577836800000).toLocaleString()} + + + + {timestamp} + {"->"} + Now + + +
+ An ISO 8601 datetime string, which represents an exact moment + in time as well as the potentional to store the timezone it occured in. +
+
+ + + 2000-01-01T00:00:00.000Z + + + {new Date(946684800000).toLocaleString()} + + + + 2000-01-01T00:00:00.000Z + + + {new Date(1577836800000).toLocaleString()} + + + + {iso} + + Now + + +
+
+ + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/StringsAsNumbers.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/StringsAsNumbers.svelte new file mode 100644 index 0000000000..e30a450d80 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/StringsAsNumbers.svelte @@ -0,0 +1,56 @@ + + + +
+ Text can be used in place of numbers in certain scenarios, but care needs to + be taken; if the value isn't purely numerical it may be converted in an + unexpected way. +
+ + + + "100"{"->"}100 + + + "100k"{"->"}100 + + + "100,000"{"->"}100 + + + "100 million"{"->"}100 + + + "100.9"{"->"}100.9 + + + "One hundred"{"->"}Error + + +
+ + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/Support.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/Support.svelte new file mode 100644 index 0000000000..0419c0ad16 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/Support.svelte @@ -0,0 +1,35 @@ + + + +
+ + Fully compatible with the input as long as the data is present. +
+
+ + Partially compatible with the input, but beware of other caveats + mentioned. +
+
+ + Incompatible with the component. +
+
+ + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/BindingValue.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/BindingValue.svelte new file mode 100644 index 0000000000..811283ba51 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/BindingValue.svelte @@ -0,0 +1,39 @@ + + +
+ +
+ + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Block.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Block.svelte new file mode 100644 index 0000000000..449b40304d --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Block.svelte @@ -0,0 +1,30 @@ + + + + + + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/ExampleLine.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/ExampleLine.svelte new file mode 100644 index 0000000000..6dd3e10a39 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/ExampleLine.svelte @@ -0,0 +1,12 @@ +
  • +
    + +
    +
  • + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/ExampleSection.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/ExampleSection.svelte new file mode 100644 index 0000000000..4da4f5141b --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/ExampleSection.svelte @@ -0,0 +1,32 @@ + + +
    + + + {heading} + + +
      + +
    +
    + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/JSONValue.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/JSONValue.svelte new file mode 100644 index 0000000000..4703398b2d --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/JSONValue.svelte @@ -0,0 +1,22 @@ + + +
    +  {value}
    +
    + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Property.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Property.svelte new file mode 100644 index 0000000000..8d6e853ab4 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Property.svelte @@ -0,0 +1,49 @@ + + +
    + + + {name} + + + - + + + {value} + + +
    + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Section.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Section.svelte new file mode 100644 index 0000000000..486e111725 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Section.svelte @@ -0,0 +1,11 @@ +
    + +
    + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Subject.svelte b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Subject.svelte new file mode 100644 index 0000000000..4e21160cae --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/Subject.svelte @@ -0,0 +1,51 @@ + + +
    + + + {heading} + + +
    +
    +
    + +
    + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/index.js b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/index.js new file mode 100644 index 0000000000..d174f4d6cc --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/components/index.js @@ -0,0 +1,8 @@ +export { default as Subject } from "./Subject.svelte" +export { default as Property } from "./Property.svelte" +export { default as JSONValue } from "./JSONValue.svelte" +export { default as BindingValue } from "./BindingValue.svelte" +export { default as Section } from "./Section.svelte" +export { default as Block } from "./Block.svelte" +export { default as ExampleSection } from "./ExampleSection.svelte" +export { default as ExampleLine } from "./ExampleLine.svelte" diff --git a/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/index.js b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/index.js new file mode 100644 index 0000000000..c7f54d6415 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/DetailsModal/subjects/index.js @@ -0,0 +1,8 @@ +export { default as Column } from "./Column.svelte" +export { default as NotRequired } from "./NotRequired.svelte" +export { default as StringsAsNumbers } from "./StringsAsNumbers.svelte" +export { default as Support } from "./Support.svelte" +export { default as DatesAsNumbers } from "./DatesAsNumbers.svelte" +export { default as ScalarJsonOnly } from "./ScalarJsonOnly.svelte" +export { default as StringsAsDates } from "./StringsAsDates.svelte" +export { default as NumbersAsDates } from "./NumbersAsDates.svelte" diff --git a/packages/builder/src/components/design/settings/controls/Explanation/Explanation.svelte b/packages/builder/src/components/design/settings/controls/Explanation/Explanation.svelte new file mode 100644 index 0000000000..bc45e410c9 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/Explanation.svelte @@ -0,0 +1,102 @@ + + +
    + + + {#if messages.includes(messageConstants.stringAsNumber)} + + {/if} + {#if messages.includes(messageConstants.notRequired)} + + {/if} + {#if messages.includes(messageConstants.jsonPrimitivesOnly)} + + {/if} + {#if messages.includes(messageConstants.dateAsNumber)} + + {/if} + {#if messages.includes(messageConstants.numberAsDate)} + + {/if} + {#if messages.includes(messageConstants.stringAsDate)} + + {/if} +
    + +{#if detailsModalSubject !== subjects.none} + +{/if} + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/explanation.js b/packages/builder/src/components/design/settings/controls/Explanation/explanation.js new file mode 100644 index 0000000000..4e024c67fc --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/explanation.js @@ -0,0 +1,100 @@ +export const messages = { + jsonPrimitivesOnly: Symbol("explanation-json-primitives-only"), + stringAsNumber: Symbol("explanation-string-as-number"), + dateAsNumber: Symbol("explanation-date-as-number"), + numberAsDate: Symbol("explanation-number-as-date"), + stringAsDate: Symbol("explanation-string-as-date"), + notRequired: Symbol("explanation-not-required"), + contextError: Symbol("explanation-context-error"), +} + +export const support = { + unsupported: Symbol("explanation-unsupported"), + partialSupport: Symbol("explanation-partialSupport"), + supported: Symbol("explanation-supported"), +} + +const getSupport = (type, explanation) => { + if (!explanation?.typeSupport) { + return support.supported + } + + if ( + explanation?.typeSupport?.supported?.find( + mapping => mapping === type || mapping?.type === type + ) + ) { + return support.supported + } + + if ( + explanation?.typeSupport?.partialSupport?.find( + mapping => mapping === type || mapping?.type === type + ) + ) { + return support.partialSupport + } + + return support.unsupported +} + +const getSupportMessage = (type, explanation) => { + if (!explanation?.typeSupport) { + return null + } + + const supported = explanation?.typeSupport?.supported?.find( + mapping => mapping?.type === type + ) + if (supported) { + return messages[supported?.message] + } + + const partialSupport = explanation?.typeSupport?.partialSupport?.find( + mapping => mapping?.type === type + ) + if (partialSupport) { + return messages[partialSupport?.message] + } + + const unsupported = explanation?.typeSupport?.unsupported?.find( + mapping => mapping?.type === type + ) + if (unsupported) { + return messages[unsupported?.message] + } + + return null +} + +export const getExplanationMessagesAndSupport = (fieldSchema, explanation) => { + try { + const explanationMessagesAndSupport = { + support: getSupport(fieldSchema.type, explanation), + messages: [getSupportMessage(fieldSchema.type, explanation)], + } + + const isRequired = fieldSchema?.constraints?.presence?.allowEmpty === false + if (!isRequired) { + explanationMessagesAndSupport.messages.push(messages.notRequired) + } + + return explanationMessagesAndSupport + } catch (e) { + return { + support: support.partialSupport, + messages: [messages.contextError], + } + } +} + +export const getExplanationWithPresets = (explanation, presets) => { + if (explanation?.typeSupport?.preset) { + return { + ...explanation, + typeSupport: presets[explanation?.typeSupport?.preset], + } + } + + return explanation +} diff --git a/packages/builder/src/components/design/settings/controls/Explanation/index.js b/packages/builder/src/components/design/settings/controls/Explanation/index.js new file mode 100644 index 0000000000..5780c1de14 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/index.js @@ -0,0 +1 @@ +export { default as Explanation } from "./Explanation.svelte" diff --git a/packages/builder/src/components/design/settings/controls/Explanation/lines/Column.svelte b/packages/builder/src/components/design/settings/controls/Explanation/lines/Column.svelte new file mode 100644 index 0000000000..9c3b87f8b9 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/lines/Column.svelte @@ -0,0 +1,84 @@ + + + + setExplanationSubject(subjects.column)} + on:mouseleave={() => setExplanationSubject(subjects.none)} + href={tableHref} + text={columnName} + /> + + + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/lines/DateAsNumber.svelte b/packages/builder/src/components/design/settings/controls/Explanation/lines/DateAsNumber.svelte new file mode 100644 index 0000000000..ba5eb9b0e1 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/lines/DateAsNumber.svelte @@ -0,0 +1,16 @@ + + + + + setExplanationSubject(subjects.datesAsNumbers)} + on:mouseleave={() => setExplanationSubject(subjects.none)} + text="UNIX time value" + /> + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/lines/JSONPrimitivesOnly.svelte b/packages/builder/src/components/design/settings/controls/Explanation/lines/JSONPrimitivesOnly.svelte new file mode 100644 index 0000000000..2286c09044 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/lines/JSONPrimitivesOnly.svelte @@ -0,0 +1,21 @@ + + + + setExplanationSubject(subjects.scalarJsonOnly)} + on:mouseleave={() => setExplanationSubject(subjects.none)} + >Scalar JSON values + + + + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/lines/NotRequired.svelte b/packages/builder/src/components/design/settings/controls/Explanation/lines/NotRequired.svelte new file mode 100644 index 0000000000..e705bd68e6 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/lines/NotRequired.svelte @@ -0,0 +1,25 @@ + + + + + setExplanationSubject(subjects.notRequired)} + on:mouseleave={() => setExplanationSubject(subjects.none)} + text="required" + /> + + + + + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/lines/NumberAsDate.svelte b/packages/builder/src/components/design/settings/controls/Explanation/lines/NumberAsDate.svelte new file mode 100644 index 0000000000..c6413c13a5 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/lines/NumberAsDate.svelte @@ -0,0 +1,16 @@ + + + + + setExplanationSubject(subjects.numbersAsDates)} + on:mouseleave={() => setExplanationSubject(subjects.none)} + text="UNIX time value" + /> + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/lines/StringAsDate.svelte b/packages/builder/src/components/design/settings/controls/Explanation/lines/StringAsDate.svelte new file mode 100644 index 0000000000..72267b6f47 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/lines/StringAsDate.svelte @@ -0,0 +1,16 @@ + + + + + setExplanationSubject(subjects.stringsAsDates)} + on:mouseleave={() => setExplanationSubject(subjects.none)} + text="UNIX time or ISO 8601 value" + /> + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/lines/StringAsNumber.svelte b/packages/builder/src/components/design/settings/controls/Explanation/lines/StringAsNumber.svelte new file mode 100644 index 0000000000..937545c1c3 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/lines/StringAsNumber.svelte @@ -0,0 +1,16 @@ + + + + + setExplanationSubject(subjects.stringsAsNumbers)} + on:mouseleave={() => setExplanationSubject(subjects.none)} + text="non-numerical values" + /> + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/lines/Support.svelte b/packages/builder/src/components/design/settings/controls/Explanation/lines/Support.svelte new file mode 100644 index 0000000000..848ab208fb --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/lines/Support.svelte @@ -0,0 +1,59 @@ + + + + setExplanationSubject(subjects.support)} + on:mouseleave={() => setExplanationSubject(subjects.none)} + {icon} + {color} + {text} + /> + + + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/lines/index.js b/packages/builder/src/components/design/settings/controls/Explanation/lines/index.js new file mode 100644 index 0000000000..beff239398 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/lines/index.js @@ -0,0 +1,8 @@ +export { default as Column } from "./Column.svelte" +export { default as NotRequired } from "./NotRequired.svelte" +export { default as StringAsNumber } from "./StringAsNumber.svelte" +export { default as Support } from "./Support.svelte" +export { default as JSONPrimitivesOnly } from "./JSONPrimitivesOnly.svelte" +export { default as DateAsNumber } from "./DateAsNumber.svelte" +export { default as NumberAsDate } from "./NumberAsDate.svelte" +export { default as StringAsDate } from "./StringAsDate.svelte" diff --git a/packages/builder/src/components/design/settings/controls/Explanation/subjects.js b/packages/builder/src/components/design/settings/controls/Explanation/subjects.js new file mode 100644 index 0000000000..1f94fa6fd0 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/subjects.js @@ -0,0 +1,13 @@ +const subjects = { + column: Symbol("details-modal-column"), + support: Symbol("details-modal-support"), + stringsAsNumbers: Symbol("details-modal-strings-as-numbers"), + datesAsNumbers: Symbol("details-modal-dates-as-numbers"), + numbersAsDates: Symbol("explanation-numbers-as-dates"), + stringsAsDates: Symbol("explanation-strings-as-dates"), + notRequired: Symbol("details-modal-not-required"), + scalarJsonOnly: Symbol("explanation-scalar-json-only"), + none: Symbol("details-modal-none"), +} + +export default subjects diff --git a/packages/builder/src/components/design/settings/controls/Explanation/typography/Comma.svelte b/packages/builder/src/components/design/settings/controls/Explanation/typography/Comma.svelte new file mode 100644 index 0000000000..f16bd16054 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/typography/Comma.svelte @@ -0,0 +1,14 @@ +, + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/typography/DocumentationLink.svelte b/packages/builder/src/components/design/settings/controls/Explanation/typography/DocumentationLink.svelte new file mode 100644 index 0000000000..55b9732d4a --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/typography/DocumentationLink.svelte @@ -0,0 +1,66 @@ + + + + + + + {text} + + + + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/typography/InfoWord.svelte b/packages/builder/src/components/design/settings/controls/Explanation/typography/InfoWord.svelte new file mode 100644 index 0000000000..cac12cbfb5 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/typography/InfoWord.svelte @@ -0,0 +1,78 @@ + + +{#if href !== null} + + {#if icon} + + {/if} + + + {text} + + + +{:else} + +{/if} + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/typography/Line.svelte b/packages/builder/src/components/design/settings/controls/Explanation/typography/Line.svelte new file mode 100644 index 0000000000..5d28ba0423 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/typography/Line.svelte @@ -0,0 +1,41 @@ + + +
    + +
    + +
    +
    + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/typography/Period.svelte b/packages/builder/src/components/design/settings/controls/Explanation/typography/Period.svelte new file mode 100644 index 0000000000..d1bbafe6a6 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/typography/Period.svelte @@ -0,0 +1,13 @@ +. + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/typography/Space.svelte b/packages/builder/src/components/design/settings/controls/Explanation/typography/Space.svelte new file mode 100644 index 0000000000..b88831d760 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/typography/Space.svelte @@ -0,0 +1,9 @@ +{" "} + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/typography/Text.svelte b/packages/builder/src/components/design/settings/controls/Explanation/typography/Text.svelte new file mode 100644 index 0000000000..6562c9e864 --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/typography/Text.svelte @@ -0,0 +1,64 @@ + + +{#each words as word} + {#if word === " "} + + {:else if word === ","} + + {:else if word === "."} + + {:else} + + {word} + + {/if} +{/each} + + diff --git a/packages/builder/src/components/design/settings/controls/Explanation/typography/index.js b/packages/builder/src/components/design/settings/controls/Explanation/typography/index.js new file mode 100644 index 0000000000..102b65190d --- /dev/null +++ b/packages/builder/src/components/design/settings/controls/Explanation/typography/index.js @@ -0,0 +1,7 @@ +export { default as Space } from "./Space.svelte" +export { default as Comma } from "./Comma.svelte" +export { default as Period } from "./Period.svelte" +export { default as Text } from "./Text.svelte" +export { default as InfoWord } from "./InfoWord.svelte" +export { default as DocumentationLink } from "./DocumentationLink.svelte" +export { default as Line } from "./Line.svelte" diff --git a/packages/builder/src/components/design/settings/controls/FieldConfiguration/FieldSetting.svelte b/packages/builder/src/components/design/settings/controls/FieldConfiguration/FieldSetting.svelte index 771bcf20e0..27590a9858 100644 --- a/packages/builder/src/components/design/settings/controls/FieldConfiguration/FieldSetting.svelte +++ b/packages/builder/src/components/design/settings/controls/FieldConfiguration/FieldSetting.svelte @@ -1,5 +1,5 @@ - + +{#if explanation} + + + +{/if} diff --git a/packages/builder/src/components/design/settings/controls/GridColumnConfiguration/FieldSetting.svelte b/packages/builder/src/components/design/settings/controls/GridColumnConfiguration/FieldSetting.svelte index 5fc5c96db8..668f2f7d59 100644 --- a/packages/builder/src/components/design/settings/controls/GridColumnConfiguration/FieldSetting.svelte +++ b/packages/builder/src/components/design/settings/controls/GridColumnConfiguration/FieldSetting.svelte @@ -1,5 +1,5 @@ - + + +{#if explanation} + + + +{/if} diff --git a/packages/builder/src/components/design/settings/controls/ValidationEditor/ValidationDrawer.svelte b/packages/builder/src/components/design/settings/controls/ValidationEditor/ValidationDrawer.svelte index 3a98de94cd..f70c0910e0 100644 --- a/packages/builder/src/components/design/settings/controls/ValidationEditor/ValidationDrawer.svelte +++ b/packages/builder/src/components/design/settings/controls/ValidationEditor/ValidationDrawer.svelte @@ -108,6 +108,8 @@ Constraints.MaxFileSize, Constraints.MaxUploadSize, ], + ["attachment_single"]: [Constraints.Required, Constraints.MaxUploadSize], + ["signature_single"]: [Constraints.Required], ["link"]: [ Constraints.Required, Constraints.Contains, diff --git a/packages/builder/src/components/portal/onboarding/tours.js b/packages/builder/src/components/portal/onboarding/tours.js index fab97cdd03..6a3fe1daf0 100644 --- a/packages/builder/src/components/portal/onboarding/tours.js +++ b/packages/builder/src/components/portal/onboarding/tours.js @@ -10,7 +10,6 @@ import { NewFormSteps, } from "./steps" import { API } from "api" -import { customPositionHandler } from "components/design/settings/controls/EditComponentPopover" const ONBOARDING_EVENT_PREFIX = "onboarding" @@ -187,7 +186,6 @@ const getTours = () => { tourEvent(TOUR_STEP_KEYS.BUILDER_FORM_CREATE_STEPS) builderStore.highlightSetting("steps", "info") }, - positionHandler: customPositionHandler, align: "left-outside", }, ], @@ -203,7 +201,6 @@ const getTours = () => { tourEvent(TOUR_STEP_KEYS.BUILDER_FORM_ROW_ID) builderStore.highlightSetting("rowId", "info") }, - positionHandler: customPositionHandler, align: "left-outside", }, { @@ -219,7 +216,6 @@ const getTours = () => { tourEvent(TOUR_STEP_KEYS.BUILDER_FORM_VIEW_UPDATE_STEPS) builderStore.highlightSetting("steps", "info") }, - positionHandler: customPositionHandler, align: "left-outside", scrollIntoView: true, }, diff --git a/packages/builder/src/constants/backend/index.js b/packages/builder/src/constants/backend/index.js index 6ac37e60be..78e90d6298 100644 --- a/packages/builder/src/constants/backend/index.js +++ b/packages/builder/src/constants/backend/index.js @@ -127,6 +127,14 @@ export const FIELDS = { presence: false, }, }, + SIGNATURE_SINGLE: { + name: "Signature", + type: FieldType.SIGNATURE_SINGLE, + icon: "AnnotatePen", + constraints: { + presence: false, + }, + }, LINK: { name: "Relationship", type: FieldType.LINK, diff --git a/packages/builder/src/pages/builder/app/[application]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/_layout.svelte index 7d4958db04..cd62a97340 100644 --- a/packages/builder/src/pages/builder/app/[application]/_layout.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_layout.svelte @@ -21,7 +21,7 @@ } from "@budibase/bbui" import AppActions from "components/deploy/AppActions.svelte" import { API } from "api" - import { isActive, goto, layout, redirect } from "@roxi/routify" + import { isActive, url, goto, layout, redirect } from "@roxi/routify" import { capitalise } from "helpers" import { onMount, onDestroy } from "svelte" import VerificationPromptBanner from "components/common/VerificationPromptBanner.svelte" @@ -69,7 +69,7 @@ // e.g. if one of your screens is selected on front end, then // you browse to backend, when you click frontend, you will be // brought back to the same screen. - const topItemNavigate = path => () => { + const topItemNavigate = path => { const activeTopNav = $layout.children.find(c => $isActive(c.path)) if (activeTopNav) { builderStore.setPreviousTopNavPath( @@ -105,10 +105,6 @@ } onMount(async () => { - document.fonts.onloadingdone = e => { - builderStore.loadFonts(e.fontfaces) - } - if (!hasSynced && application) { try { await API.syncApp(application) @@ -140,28 +136,23 @@
    {#if $appStore.initialised}
    - - $goto("../../portal/apps")} - /> - + + + - {#key $builderStore?.fonts} - {#each $layout.children as { path, title }} - - - - {/each} - {/key} + {#each $layout.children as { path, title }} + + topItemNavigate(path)} + title={capitalise(title)} + id={`builder-${title}-tab`} + /> + + {/each}
    @@ -207,6 +198,11 @@ diff --git a/packages/client/src/components/app/charts/ApexOptionsBuilder.js b/packages/client/src/components/app/charts/ApexOptionsBuilder.js deleted file mode 100644 index 04b5805df3..0000000000 --- a/packages/client/src/components/app/charts/ApexOptionsBuilder.js +++ /dev/null @@ -1,195 +0,0 @@ -export class ApexOptionsBuilder { - constructor() { - this.formatters = { - ["Default"]: val => (isNaN(val) ? val : Math.round(val * 100) / 100), - ["Thousands"]: val => `${Math.round(val / 1000)}K`, - ["Millions"]: val => `${Math.round(val / 1000000)}M`, - } - this.options = { - series: [], - legend: { - show: false, - position: "top", - horizontalAlign: "right", - showForSingleSeries: true, - showForNullSeries: true, - showForZeroSeries: true, - }, - chart: { - toolbar: { - show: false, - }, - zoom: { - enabled: false, - }, - }, - xaxis: { - labels: { - formatter: this.formatters.Default, - }, - }, - yaxis: { - labels: { - formatter: this.formatters.Default, - }, - }, - } - } - - setOption(path, value) { - if (value == null || value === "") { - return this - } - let tmp = this.options - for (let i = 0; i < path.length - 1; i++) { - const step = path[i] - if (!tmp[step]) { - tmp[step] = {} - } - tmp = tmp[step] - } - tmp[path[path.length - 1]] = value - return this - } - - getOptions() { - return this.options - } - - type(type) { - return this.setOption(["chart", "type"], type) - } - - title(title) { - return this.setOption(["title", "text"], title) - } - - colors(colors) { - if (!colors) { - delete this.options.colors - this.options["customColor"] = false - return this - } - this.options["customColor"] = true - return this.setOption(["colors"], colors) - } - - width(width) { - return this.setOption(["chart", "width"], width || undefined) - } - - height(height) { - return this.setOption(["chart", "height"], height || undefined) - } - - xLabel(label) { - return this.setOption(["xaxis", "title", "text"], label) - } - - yLabel(label) { - return this.setOption(["yaxis", "title", "text"], label) - } - - xCategories(categories) { - return this.setOption(["xaxis", "categories"], categories) - } - - yCategories(categories) { - return this.setOption(["yaxis", "categories"], categories) - } - - series(series) { - return this.setOption(["series"], series) - } - - horizontal(horizontal) { - return this.setOption(["plotOptions", "bar", "horizontal"], horizontal) - } - - dataLabels(dataLabels) { - return this.setOption(["dataLabels", "enabled"], dataLabels) - } - - animate(animate) { - return this.setOption(["chart", "animations", "enabled"], animate) - } - - curve(curve) { - return this.setOption(["stroke", "curve"], curve) - } - - gradient(gradient) { - const fill = { - type: "gradient", - gradient: { - shadeIntensity: 1, - opacityFrom: 0.7, - opacityTo: 0.9, - stops: [0, 90, 100], - }, - } - return this.setOption(["fill"], gradient ? fill : undefined) - } - - legend(legend) { - return this.setOption(["legend", "show"], legend) - } - - legendPosition(position) { - return this.setOption(["legend", "position"], position) - } - - stacked(stacked) { - return this.setOption(["chart", "stacked"], stacked) - } - - labels(labels) { - return this.setOption(["labels"], labels) - } - - xUnits(units) { - return this.setOption( - ["xaxis", "labels", "formatter"], - this.formatters[units || "Default"] - ) - } - - yUnits(units) { - return this.setOption( - ["yaxis", "labels", "formatter"], - this.formatters[units || "Default"] - ) - } - - clearXFormatter() { - delete this.options.xaxis.labels - return this - } - - clearYFormatter() { - delete this.options.yaxis.labels - return this - } - - xType(type) { - return this.setOption(["xaxis", "type"], type) - } - - yType(type) { - return this.setOption(["yaxis", "type"], type) - } - - yTooltip(yTooltip) { - return this.setOption(["yaxis", "tooltip", "enabled"], yTooltip) - } - - palette(palette) { - if (!palette) { - return this - } - return this.setOption( - ["theme", "palette"], - palette.toLowerCase().replace(/[\W]/g, "") - ) - } -} diff --git a/packages/client/src/components/app/charts/AreaChart.svelte b/packages/client/src/components/app/charts/AreaChart.svelte index dc80b2b9da..a9a61e59f6 100644 --- a/packages/client/src/components/app/charts/AreaChart.svelte +++ b/packages/client/src/components/app/charts/AreaChart.svelte @@ -1,5 +1,159 @@ - + diff --git a/packages/client/src/components/app/charts/BarChart.svelte b/packages/client/src/components/app/charts/BarChart.svelte index fd8443e2d6..aeebfe9461 100644 --- a/packages/client/src/components/app/charts/BarChart.svelte +++ b/packages/client/src/components/app/charts/BarChart.svelte @@ -1,11 +1,12 @@ diff --git a/packages/client/src/components/app/charts/CandleStickChart.svelte b/packages/client/src/components/app/charts/CandleStickChart.svelte index b2760b005e..61cdef180b 100644 --- a/packages/client/src/components/app/charts/CandleStickChart.svelte +++ b/packages/client/src/components/app/charts/CandleStickChart.svelte @@ -1,6 +1,6 @@ diff --git a/packages/client/src/components/app/charts/DonutChart.svelte b/packages/client/src/components/app/charts/DonutChart.svelte index 721a09053a..dad9edfd67 100644 --- a/packages/client/src/components/app/charts/DonutChart.svelte +++ b/packages/client/src/components/app/charts/DonutChart.svelte @@ -1,5 +1,99 @@ - + diff --git a/packages/client/src/components/app/charts/HistogramChart.svelte b/packages/client/src/components/app/charts/HistogramChart.svelte index 26b9028550..37c395d45f 100644 --- a/packages/client/src/components/app/charts/HistogramChart.svelte +++ b/packages/client/src/components/app/charts/HistogramChart.svelte @@ -1,135 +1,154 @@ diff --git a/packages/client/src/components/app/charts/LineChart.svelte b/packages/client/src/components/app/charts/LineChart.svelte index 7f82a833d2..c2dac189e1 100644 --- a/packages/client/src/components/app/charts/LineChart.svelte +++ b/packages/client/src/components/app/charts/LineChart.svelte @@ -1,8 +1,7 @@ diff --git a/packages/client/src/components/app/charts/PieChart.svelte b/packages/client/src/components/app/charts/PieChart.svelte index 8cb7317d94..3250a2ca95 100644 --- a/packages/client/src/components/app/charts/PieChart.svelte +++ b/packages/client/src/components/app/charts/PieChart.svelte @@ -1,6 +1,6 @@ diff --git a/packages/client/src/components/app/charts/utils.js b/packages/client/src/components/app/charts/utils.js new file mode 100644 index 0000000000..1aea22c991 --- /dev/null +++ b/packages/client/src/components/app/charts/utils.js @@ -0,0 +1,51 @@ +export const formatters = { + ["Default"]: val => val, + ["Thousands"]: val => `${Math.round(val / 1000)}K`, + ["Millions"]: val => `${Math.round(val / 1000000)}M`, + ["Datetime"]: val => new Date(val).toLocaleString(), +} + +export const parsePalette = paletteName => { + if (paletteName === "Custom") { + // return null in this case so that the palette option doesn't get consumed by Apex Charts + return null + } + + const [_, number] = paletteName.split(" ") + + return `palette${number}` +} + +// Deep clone which copies function references +export const cloneDeep = value => { + const typesToNaiveCopy = ["string", "boolean", "number", "function", "symbol"] + + if (value === null) { + return null + } + + if (value === undefined) { + return undefined + } + + if (typesToNaiveCopy.includes(typeof value)) { + return value + } + + if (Array.isArray(value)) { + return value.map(element => cloneDeep(element)) + } + + // Only copy "pure" objects, we want to error on stuff like Maps or Sets + if (typeof value === "object" && value.constructor.name === "Object") { + const cloneObject = {} + + Object.entries(value).forEach(([key, childValue]) => { + cloneObject[key] = cloneDeep(childValue) + }) + + return cloneObject + } + + throw `Unsupported value: "${value}" of type: "${typeof value}"` +} diff --git a/packages/client/src/components/app/charts/utils.test.js b/packages/client/src/components/app/charts/utils.test.js new file mode 100644 index 0000000000..1b065e2fae --- /dev/null +++ b/packages/client/src/components/app/charts/utils.test.js @@ -0,0 +1,31 @@ +import { expect, describe, it, vi } from "vitest" +import { cloneDeep } from "./utils" + +describe("utils", () => { + let context + + beforeEach(() => { + vi.clearAllMocks() + context = {} + }) + + describe("cloneDeep", () => { + beforeEach(() => { + context.value = { + obj: { one: 1, two: 2 }, + arr: [1, { first: null, second: undefined }, 2], + str: "test", + num: 123, + bool: true, + sym: Symbol("test"), + func: () => "some value", + } + context.cloneValue = cloneDeep(context.value) + }) + + it("to clone the object and not copy object references", () => { + expect(context.cloneValue.obj.one).toEqual(1) + expect(context.cloneValue.obj.two).toEqual(2) + }) + }) +}) diff --git a/packages/client/src/components/app/forms/SignatureField.svelte b/packages/client/src/components/app/forms/SignatureField.svelte new file mode 100644 index 0000000000..bdae148368 --- /dev/null +++ b/packages/client/src/components/app/forms/SignatureField.svelte @@ -0,0 +1,129 @@ + + + + + + {#if fieldState} + {#if (Array.isArray(fieldState?.value) && !fieldState?.value?.length) || !fieldState?.value} + { + if (!$builderStore.inBuilder) { + modal.show() + } + }} + > + Add signature + + {:else} +
    + +
    + {/if} + {/if} +
    + + diff --git a/packages/client/src/components/app/forms/index.js b/packages/client/src/components/app/forms/index.js index 15966c3765..391b5fa19f 100644 --- a/packages/client/src/components/app/forms/index.js +++ b/packages/client/src/components/app/forms/index.js @@ -16,5 +16,6 @@ export { default as formstep } from "./FormStep.svelte" export { default as jsonfield } from "./JSONField.svelte" export { default as s3upload } from "./S3Upload.svelte" export { default as codescanner } from "./CodeScannerField.svelte" +export { default as signaturesinglefield } from "./SignatureField.svelte" export { default as bbreferencefield } from "./BBReferenceField.svelte" export { default as bbreferencesinglefield } from "./BBReferenceSingleField.svelte" diff --git a/packages/client/src/components/app/forms/validation.js b/packages/client/src/components/app/forms/validation.js index bdd7213cb0..46a5330cf3 100644 --- a/packages/client/src/components/app/forms/validation.js +++ b/packages/client/src/components/app/forms/validation.js @@ -200,6 +200,17 @@ const parseType = (value, type) => { return value } + // Parse attachment/signature single, treating no key as null + if ( + type === FieldTypes.ATTACHMENT_SINGLE || + type === FieldTypes.SIGNATURE_SINGLE + ) { + if (!value?.key) { + return null + } + return value + } + // Parse links, treating no elements as null if (type === FieldTypes.LINK) { if (!Array.isArray(value) || !value.length) { @@ -246,10 +257,8 @@ const maxLengthHandler = (value, rule) => { // Evaluates a max file size (MB) constraint const maxFileSizeHandler = (value, rule) => { const limit = parseType(rule.value, "number") - return ( - value == null || - !value.some(attachment => attachment.size / 1000000 > limit) - ) + const check = attachment => attachment.size / 1000000 > limit + return value == null || !(value?.key ? check(value) : value.some(check)) } // Evaluates a max total upload size (MB) constraint @@ -257,8 +266,11 @@ const maxUploadSizeHandler = (value, rule) => { const limit = parseType(rule.value, "number") return ( value == null || - value.reduce((acc, currentItem) => acc + currentItem.size, 0) / 1000000 <= - limit + (value?.key + ? value.size / 1000000 <= limit + : value.reduce((acc, currentItem) => acc + currentItem.size, 0) / + 1000000 <= + limit) ) } diff --git a/packages/client/src/utils/componentProps.js b/packages/client/src/utils/componentProps.js index efe69938e7..bdf74c8014 100644 --- a/packages/client/src/utils/componentProps.js +++ b/packages/client/src/utils/componentProps.js @@ -108,7 +108,12 @@ export const getSettingsDefinition = definition => { let settings = [] definition.settings?.forEach(setting => { if (setting.section) { - settings = settings.concat(setting.settings || []) + settings = settings.concat( + (setting.settings || [])?.map(childSetting => ({ + ...childSetting, + sectionDependsOn: setting.dependsOn, + })) + ) } else { settings.push(setting) } diff --git a/packages/frontend-core/src/components/SignatureModal.svelte b/packages/frontend-core/src/components/SignatureModal.svelte new file mode 100644 index 0000000000..8132c5bced --- /dev/null +++ b/packages/frontend-core/src/components/SignatureModal.svelte @@ -0,0 +1,59 @@ + + + + { + onConfirm(canvas) + }} + > +
    + {title} +
    + +
    +
    + + diff --git a/packages/frontend-core/src/components/grid/cells/AttachmentCell.svelte b/packages/frontend-core/src/components/grid/cells/AttachmentCell.svelte index ea452c86a8..f485593c46 100644 --- a/packages/frontend-core/src/components/grid/cells/AttachmentCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/AttachmentCell.svelte @@ -8,7 +8,6 @@ export let onChange export let readonly = false export let api - export let invertX = false export let schema export let maximum @@ -92,13 +91,7 @@
    {#if isOpen} - +
    {#if isOpen} - + { - columns.actions.changePrimaryDisplay(column.name) + datasource.actions.changePrimaryDisplay(column.name) open = false } const hideColumn = () => { - columns.update(state => { - const index = state.findIndex(col => col.name === column.name) - state[index].visible = false - return state.slice() - }) - columns.actions.saveChanges() + datasource.actions.addSchemaMutation(column.name, { visible: false }) + datasource.actions.saveSchemaMutations() open = false } diff --git a/packages/frontend-core/src/components/grid/cells/LongFormCell.svelte b/packages/frontend-core/src/components/grid/cells/LongFormCell.svelte index 6a05b4ae49..7829e5da7d 100644 --- a/packages/frontend-core/src/components/grid/cells/LongFormCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/LongFormCell.svelte @@ -8,7 +8,6 @@ export let onChange export let readonly = false export let api - export let invertX = false let textarea let isOpen = false @@ -67,7 +66,7 @@
    {#if isOpen} - +