diff --git a/packages/bbui/src/Actions/click_outside.js b/packages/bbui/src/Actions/click_outside.js index 124f43ff04..526659cb7a 100644 --- a/packages/bbui/src/Actions/click_outside.js +++ b/packages/bbui/src/Actions/click_outside.js @@ -71,8 +71,8 @@ const handleMouseDown = e => { // Clear any previous listeners in case of multiple down events, and register // a single mouse up listener - document.removeEventListener("mouseup", handleMouseUp) - document.addEventListener("mouseup", handleMouseUp, true) + document.removeEventListener("click", handleMouseUp) + document.addEventListener("click", handleMouseUp, true) } // Global singleton listeners for our events 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..6094c93a26 100644 --- a/packages/builder/src/pages/builder/app/[application]/_layout.svelte +++ b/packages/builder/src/pages/builder/app/[application]/_layout.svelte @@ -105,10 +105,6 @@ } onMount(async () => { - document.fonts.onloadingdone = e => { - builderStore.loadFonts(e.fontfaces) - } - if (!hasSynced && application) { try { await API.syncApp(application) @@ -149,19 +145,17 @@ /> - {#key $builderStore?.fonts} - {#each $layout.children as { path, title }} - - - - {/each} - {/key} + {#each $layout.children as { path, title }} + + + + {/each}
    diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte index 9ff2a764b7..54241ea1cc 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte @@ -191,6 +191,9 @@ // Number fields min: setting.min ?? null, max: setting.max ?? null, + + // Field select settings + explanation: setting.explanation, }} {bindings} {componentBindings} diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/new/_components/componentStructure.json b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/new/_components/componentStructure.json index 0f85d2e3e3..ba6f403d81 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/new/_components/componentStructure.json +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/new/_components/componentStructure.json @@ -71,6 +71,7 @@ "multifieldselect", "s3upload", "codescanner", + "signaturesinglefield", "bbreferencesinglefield", "bbreferencefield" ] diff --git a/packages/builder/src/stores/builder/app.js b/packages/builder/src/stores/builder/app.js index 7dfee4daa9..e57a079185 100644 --- a/packages/builder/src/stores/builder/app.js +++ b/packages/builder/src/stores/builder/app.js @@ -19,6 +19,7 @@ export const INITIAL_APP_META_STATE = { showNotificationAction: false, sidePanel: false, }, + typeSupportPresets: {}, features: { componentValidation: false, disableUserMetadata: false, @@ -79,6 +80,13 @@ export class AppMetaStore extends BudiStore { })) } + syncClientTypeSupportPresets(typeSupportPresets) { + this.update(state => ({ + ...state, + typeSupportPresets, + })) + } + async syncAppRoutes() { const resp = await API.fetchAppRoutes() this.update(state => ({ diff --git a/packages/builder/src/stores/builder/automations.js b/packages/builder/src/stores/builder/automations.js index cbe48cef33..ff53dda86b 100644 --- a/packages/builder/src/stores/builder/automations.js +++ b/packages/builder/src/stores/builder/automations.js @@ -82,6 +82,7 @@ const automationActions = store => ({ steps: [], trigger, }, + disabled: false, } const response = await store.actions.save(automation) await store.actions.fetch() @@ -134,6 +135,28 @@ const automationActions = store => ({ }) await store.actions.fetch() }, + toggleDisabled: async automationId => { + let automation + try { + automation = store.actions.getDefinition(automationId) + if (!automation) { + return + } + automation.disabled = !automation.disabled + await store.actions.save(automation) + notifications.success( + `Automation ${ + automation.disabled ? "enabled" : "disabled" + } successfully` + ) + } catch (error) { + notifications.error( + `Error ${ + automation && automation.disabled ? "enabling" : "disabling" + } automation` + ) + } + }, updateBlockInputs: async (block, data) => { // Create new modified block let newBlock = { diff --git a/packages/builder/src/stores/builder/builder.js b/packages/builder/src/stores/builder/builder.js index 055498bc91..d002062da9 100644 --- a/packages/builder/src/stores/builder/builder.js +++ b/packages/builder/src/stores/builder/builder.js @@ -14,7 +14,6 @@ export const INITIAL_BUILDER_STATE = { tourKey: null, tourStepKey: null, hoveredComponentId: null, - fonts: null, } export class BuilderStore extends BudiStore { @@ -37,16 +36,6 @@ export class BuilderStore extends BudiStore { this.websocket } - loadFonts(fontFaces) { - const ff = fontFaces.map( - fontFace => `${fontFace.family}-${fontFace.weight}` - ) - this.update(state => ({ - ...state, - fonts: [...(state.fonts || []), ...ff], - })) - } - init(app) { if (!app?.appId) { console.error("BuilderStore: No appId supplied for websocket") diff --git a/packages/builder/src/stores/builder/components.js b/packages/builder/src/stores/builder/components.js index 19a4f41532..8498214313 100644 --- a/packages/builder/src/stores/builder/components.js +++ b/packages/builder/src/stores/builder/components.js @@ -108,6 +108,7 @@ export class ComponentStore extends BudiStore { // Sync client features to app store appStore.syncClientFeatures(components.features) + appStore.syncClientTypeSupportPresets(components?.typeSupportPresets ?? {}) return components } diff --git a/packages/builder/src/stores/builder/tests/app.test.js b/packages/builder/src/stores/builder/tests/app.test.js index e0e5d17ba6..728f472317 100644 --- a/packages/builder/src/stores/builder/tests/app.test.js +++ b/packages/builder/src/stores/builder/tests/app.test.js @@ -91,6 +91,14 @@ describe("Application Meta Store", () => { }) }) + it("Sync type support information to state", async ctx => { + ctx.test.appStore.syncClientTypeSupportPresets({ preset: "information" }) + + expect(ctx.test.store.typeSupportPresets).toStrictEqual({ + preset: "information", + }) + }) + it("Sync component feature flags to state", async ctx => { ctx.test.appStore.syncClientFeatures(clientFeaturesResp) diff --git a/packages/builder/src/stores/builder/tests/component.test.js b/packages/builder/src/stores/builder/tests/component.test.js index b6c9ca27cd..b8baefc5e6 100644 --- a/packages/builder/src/stores/builder/tests/component.test.js +++ b/packages/builder/src/stores/builder/tests/component.test.js @@ -42,6 +42,7 @@ vi.mock("stores/builder", async () => { update: mockAppStore.update, set: mockAppStore.set, syncClientFeatures: vi.fn(), + syncClientTypeSupportPresets: vi.fn(), } const mockTableStore = writable() const tables = { diff --git a/packages/cli/src/environment.ts b/packages/cli/src/environment.ts index 9d017f99b2..51f6e9b972 100644 --- a/packages/cli/src/environment.ts +++ b/packages/cli/src/environment.ts @@ -1,3 +1,4 @@ +process.env.DISABLE_PINO_LOGGER = "1" process.env.NO_JS = "1" process.env.JS_BCRYPT = "1" process.env.DISABLE_JWT_WARNING = "1" diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 86a6d2b7b3..317ccea974 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -1,5 +1,5 @@ #!/usr/bin/env node -process.env.DISABLE_PINO_LOGGER = "1" +// have to import this before anything else import "./environment" import { getCommands } from "./options" import { Command } from "commander" diff --git a/packages/cli/start.sh b/packages/cli/start.sh index 9650f0bbfa..ae39f73753 100755 --- a/packages/cli/start.sh +++ b/packages/cli/start.sh @@ -1,3 +1,3 @@ #!/bin/bash dir="$(dirname -- "$(readlink -f "${BASH_SOURCE}")")" -${dir}/node_modules/ts-node/dist/bin.js ${dir}/src/index.ts $@ +${dir}/../../node_modules/ts-node/dist/bin.js ${dir}/src/index.ts $@ diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 2fae9c0213..afe17c2a76 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -13,6 +13,42 @@ "sidePanel": true, "skeletonLoader": true }, + "typeSupportPresets": { + "numberLike": { + "supported": ["number", "boolean"], + "partialSupport": [ + { "type": "longform", "message": "stringAsNumber" }, + { "type": "string", "message": "stringAsNumber" }, + { "type": "bigint", "message": "stringAsNumber" }, + { "type": "options", "message": "stringAsNumber" }, + { "type": "formula", "message": "stringAsNumber" }, + { "type": "datetime", "message": "dateAsNumber"} + ], + "unsupported": [ + { "type": "json", "message": "jsonPrimitivesOnly" } + ] + }, + "stringLike": { + "supported": ["string", "number", "bigint", "options", "longform", "boolean", "datetime"], + "unsupported": [ + { "type": "json", "message": "jsonPrimitivesOnly" } + ] + }, + "datetimeLike": { + "supported": ["datetime"], + "partialSupport": [ + { "type": "longform", "message": "stringAsDate" }, + { "type": "string", "message": "stringAsDate" }, + { "type": "options", "message": "stringAsDate" }, + { "type": "formula", "message": "stringAsDate" }, + { "type": "bigint", "message": "stringAsDate" }, + { "type": "number", "message": "numberAsDate"} + ], + "unsupported": [ + { "type": "json", "message": "jsonPrimitivesOnly" } + ] + } + }, "layout": { "name": "Layout", "description": "This component is specific only to layouts", @@ -1602,6 +1638,7 @@ ] }, "bar": { + "documentationLink": "https://docs.budibase.com/docs/bar-chart", "name": "Bar Chart", "description": "Bar chart", "icon": "GraphBarVertical", @@ -1626,6 +1663,11 @@ "label": "Label column", "key": "labelColumn", "dependsOn": "dataProvider", + "explanation": { + "typeSupport": { + "preset": "stringLike" + } + }, "required": true }, { @@ -1633,6 +1675,11 @@ "label": "Data columns", "key": "valueColumns", "dependsOn": "dataProvider", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -1760,6 +1807,7 @@ ] }, "line": { + "documentationLink": "https://docs.budibase.com/docs/line-chart", "name": "Line Chart", "description": "Line chart", "icon": "GraphTrend", @@ -1784,6 +1832,11 @@ "label": "Label column", "key": "labelColumn", "dependsOn": "dataProvider", + "explanation": { + "typeSupport": { + "preset": "stringLike" + } + }, "required": true }, { @@ -1791,6 +1844,11 @@ "label": "Data columns", "key": "valueColumns", "dependsOn": "dataProvider", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -1913,6 +1971,7 @@ ] }, "area": { + "documentationLink": "https://docs.budibase.com/docs/area-chart", "name": "Area Chart", "description": "Line chart", "icon": "GraphAreaStacked", @@ -1937,6 +1996,11 @@ "label": "Label column", "key": "labelColumn", "dependsOn": "dataProvider", + "explanation": { + "typeSupport": { + "preset": "stringLike" + } + }, "required": true }, { @@ -1944,6 +2008,11 @@ "label": "Data columns", "key": "valueColumns", "dependsOn": "dataProvider", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -2078,6 +2147,7 @@ ] }, "pie": { + "documentationLink": "https://docs.budibase.com/docs/pie-donut-chart", "name": "Pie Chart", "description": "Pie chart", "icon": "GraphPie", @@ -2102,13 +2172,23 @@ "label": "Label column", "key": "labelColumn", "dependsOn": "dataProvider", + "explanation": { + "typeSupport": { + "preset": "stringLike" + } + }, "required": true }, { "type": "field", - "label": "Data columns", + "label": "Data column", "key": "valueColumn", "dependsOn": "dataProvider", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -2207,6 +2287,7 @@ ] }, "donut": { + "documentationLink": "https://docs.budibase.com/docs/pie-donut-chart", "name": "Donut Chart", "description": "Donut chart", "icon": "GraphDonut", @@ -2231,6 +2312,11 @@ "label": "Label column", "key": "labelColumn", "dependsOn": "dataProvider", + "explanation": { + "typeSupport": { + "preset": "stringLike" + } + }, "required": true }, { @@ -2238,6 +2324,11 @@ "label": "Data columns", "key": "valueColumn", "dependsOn": "dataProvider", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -2336,6 +2427,7 @@ ] }, "candlestick": { + "documentationLink": "https://docs.budibase.com/docs/candlestick-chart", "name": "Candlestick Chart", "description": "Candlestick chart", "icon": "GraphBarVerticalStacked", @@ -2360,6 +2452,11 @@ "label": "Date column", "key": "dateColumn", "dependsOn": "dataProvider", + "explanation": { + "typeSupport": { + "preset": "datetimeLike" + } + }, "required": true }, { @@ -2367,6 +2464,11 @@ "label": "Open column", "key": "openColumn", "dependsOn": "dataProvider", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -2374,6 +2476,11 @@ "label": "Close column", "key": "closeColumn", "dependsOn": "dataProvider", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -2381,6 +2488,11 @@ "label": "High column", "key": "highColumn", "dependsOn": "dataProvider", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -2388,6 +2500,11 @@ "label": "Low column", "key": "lowColumn", "dependsOn": "dataProvider", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -2427,6 +2544,7 @@ ] }, "histogram": { + "documentationLink": "https://docs.budibase.com/docs/histogram-chart", "name": "Histogram Chart", "description": "Histogram chart", "icon": "Histogram", @@ -2434,7 +2552,6 @@ "width": 600, "height": 400 }, - "requiredAncestors": ["dataprovider"], "settings": [ { "type": "text", @@ -2452,6 +2569,11 @@ "label": "Data column", "key": "valueColumn", "dependsOn": "dataProvider", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -2746,6 +2868,14 @@ "type": "plainText", "label": "Label", "key": "label" + }, + { + "type": "number", + "label": "Initial width", + "key": "width", + "placeholder": "Auto", + "min": 80, + "max": 9999 } ] }, @@ -4107,6 +4237,55 @@ } ] }, + "signaturesinglefield": { + "name": "Signature", + "icon": "AnnotatePen", + "styles": ["size"], + "size": { + "width": 400, + "height": 50 + }, + "settings": [ + { + "type": "field/signature_single", + "label": "Field", + "key": "field", + "required": true + }, + { + "type": "text", + "label": "Label", + "key": "label" + }, + { + "type": "text", + "label": "Help text", + "key": "helpText" + }, + { + "type": "boolean", + "label": "Disabled", + "key": "disabled", + "defaultValue": false + }, + { + "type": "event", + "label": "On change", + "key": "onChange", + "context": [ + { + "label": "Field Value", + "key": "value" + } + ] + }, + { + "type": "validation/signature_single", + "label": "Validation", + "key": "validation" + } + ] + }, "embeddedmap": { "name": "Embedded Map", "icon": "Location", @@ -4372,7 +4551,7 @@ "defaultValue": false }, { - "type": "validation/attachment", + "type": "validation/attachment_single", "label": "Validation", "key": "validation" }, @@ -5256,6 +5435,11 @@ "label": "Label column", "key": "labelColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "stringLike" + } + }, "required": true }, { @@ -5263,6 +5447,11 @@ "label": "Data column", "key": "valueColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true } ] @@ -5281,6 +5470,11 @@ "label": "Label column", "key": "labelColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "stringLike" + } + }, "required": true }, { @@ -5288,6 +5482,11 @@ "label": "Data column", "key": "valueColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true } ] @@ -5306,6 +5505,11 @@ "label": "Label column", "key": "labelColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "stringLike" + } + }, "required": true }, { @@ -5313,6 +5517,11 @@ "label": "Data columns", "key": "valueColumns", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -5360,6 +5569,11 @@ "label": "Value column", "key": "valueColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -5401,6 +5615,11 @@ "label": "Label column", "key": "labelColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "stringLike" + } + }, "required": true }, { @@ -5408,6 +5627,11 @@ "label": "Data columns", "key": "valueColumns", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -5450,6 +5674,11 @@ "label": "Label columns", "key": "labelColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "stringLike" + } + }, "required": true }, { @@ -5457,6 +5686,11 @@ "label": "Data columns", "key": "valueColumns", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -5511,6 +5745,11 @@ "label": "Date column", "key": "dateColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "datetimeLike" + } + }, "required": true }, { @@ -5518,6 +5757,11 @@ "label": "Open column", "key": "openColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -5525,6 +5769,11 @@ "label": "Close column", "key": "closeColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -5532,6 +5781,11 @@ "label": "High column", "key": "highColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -5539,6 +5793,11 @@ "label": "Low column", "key": "lowColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { diff --git a/packages/client/package.json b/packages/client/package.json index 71a9e2e055..68c8ec15b1 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -25,7 +25,7 @@ "@budibase/string-templates": "0.0.0", "@budibase/types": "0.0.0", "@spectrum-css/card": "3.0.3", - "apexcharts": "^3.22.1", + "apexcharts": "^3.48.0", "dayjs": "^1.10.8", "downloadjs": "1.4.7", "html5-qrcode": "^2.2.1", @@ -33,8 +33,8 @@ "sanitize-html": "^2.7.0", "screenfull": "^6.0.1", "shortid": "^2.2.15", - "svelte-apexcharts": "^1.0.2", - "svelte-spa-router": "^4.0.1" + "svelte-spa-router": "^4.0.1", + "atrament": "^4.3.0" }, "devDependencies": { "@rollup/plugin-alias": "^5.1.0", diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index 378fa64b73..8eacbdf041 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -193,6 +193,9 @@ $: pad = pad || (interactive && hasChildren && inDndPath) $: $dndIsDragging, (pad = false) + $: currentTheme = $context?.device?.theme + $: darkMode = !currentTheme?.includes("light") + // Update component context $: store.set({ id, @@ -222,6 +225,7 @@ parent: id, ancestors: [...($component?.ancestors ?? []), instance._component], path: [...($component?.path ?? []), id], + darkMode, }) const initialise = (instance, force = false) => { @@ -283,10 +287,23 @@ const dependsOnKey = setting.dependsOn.setting || setting.dependsOn const dependsOnValue = setting.dependsOn.value const realDependentValue = instance[dependsOnKey] + + const sectionDependsOnKey = + setting.sectionDependsOn?.setting || setting.sectionDependsOn + const sectionDependsOnValue = setting.sectionDependsOn?.value + const sectionRealDependentValue = instance[sectionDependsOnKey] + if (dependsOnValue == null && realDependentValue == null) { return false } - if (dependsOnValue !== realDependentValue) { + if (dependsOnValue != null && dependsOnValue !== realDependentValue) { + return false + } + + if ( + sectionDependsOnValue != null && + sectionDependsOnValue !== sectionRealDependentValue + ) { return false } } diff --git a/packages/client/src/components/app/GridBlock.svelte b/packages/client/src/components/app/GridBlock.svelte index cf0ec76109..7a07ceb6e1 100644 --- a/packages/client/src/components/app/GridBlock.svelte +++ b/packages/client/src/components/app/GridBlock.svelte @@ -37,13 +37,16 @@ let grid let gridContext - let minHeight + let minHeight = 0 + $: currentTheme = $context?.device?.theme + $: darkMode = !currentTheme?.includes("light") $: parsedColumns = getParsedColumns(columns) $: columnWhitelist = parsedColumns.filter(x => x.active).map(x => x.field) $: schemaOverrides = getSchemaOverrides(parsedColumns) $: enrichedButtons = enrichButtons(buttons) $: selectedRows = deriveSelectedRows(gridContext) + $: styles = patchStyles($component.styles, minHeight) $: data = { selectedRows: $selectedRows } $: actions = [ { @@ -84,9 +87,11 @@ const getSchemaOverrides = columns => { let overrides = {} - columns.forEach(column => { + columns.forEach((column, idx) => { overrides[column.field] = { displayName: column.label, + width: column.width, + order: idx, } }) return overrides @@ -128,52 +133,55 @@ ) } + const patchStyles = (styles, minHeight) => { + return { + ...styles, + normal: { + ...styles?.normal, + "min-height": `${minHeight}px`, + }, + } + } + onMount(() => { gridContext = grid.getContext() gridContext.minHeight.subscribe($height => (minHeight = $height)) }) - -
    - onRowClick?.({ row: e.detail })} - /> -
    -
    +
    + onRowClick?.({ row: e.detail })} + /> +
    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} - +