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/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/Tooltip/Context.svelte b/packages/bbui/src/Tooltip/Context.svelte new file mode 100644 index 0000000000..84d6fbbb73 --- /dev/null +++ b/packages/bbui/src/Tooltip/Context.svelte @@ -0,0 +1,79 @@ + + + + + + + diff --git a/packages/bbui/src/index.js b/packages/bbui/src/index.js index f28e185305..e746e3a72b 100644 --- a/packages/bbui/src/index.js +++ b/packages/bbui/src/index.js @@ -53,6 +53,7 @@ export { default as Link } from "./Link/Link.svelte" export { default as Tooltip } from "./Tooltip/Tooltip.svelte" export { default as TempTooltip } from "./Tooltip/TempTooltip.svelte" export { default as TooltipWrapper } from "./Tooltip/TooltipWrapper.svelte" +export { default as ContextTooltip } from "./Tooltip/Context.svelte" export { default as Menu } from "./Menu/Menu.svelte" export { default as MenuSection } from "./Menu/Section.svelte" export { default as MenuSeparator } from "./Menu/Separator.svelte" diff --git a/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte b/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte index ba5f75083a..0102d8f7a9 100644 --- a/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte +++ b/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte @@ -54,6 +54,7 @@ export let autofocus = false export let jsBindingWrapping = true export let readonly = false + export let readonlyLineNumbers = false const dispatch = createEventDispatcher() @@ -240,6 +241,9 @@ if (readonly) { complete.push(EditorState.readOnly.of(true)) + if (readonlyLineNumbers) { + complete.push(lineNumbers()) + } } else { complete = [ ...complete, 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/FieldSelect.svelte b/packages/builder/src/components/design/settings/controls/FieldSelect.svelte index e50a0e8030..15b67ded18 100644 --- a/packages/builder/src/components/design/settings/controls/FieldSelect.svelte +++ b/packages/builder/src/components/design/settings/controls/FieldSelect.svelte @@ -1,12 +1,22 @@ - + +{#if explanation} + + + +{/if} diff --git a/packages/builder/src/components/design/settings/controls/MultiFieldSelect.svelte b/packages/builder/src/components/design/settings/controls/MultiFieldSelect.svelte index d0224fb1db..d6c9a0b1e3 100644 --- a/packages/builder/src/components/design/settings/controls/MultiFieldSelect.svelte +++ b/packages/builder/src/components/design/settings/controls/MultiFieldSelect.svelte @@ -1,12 +1,22 @@ - + + +{#if explanation} + + + +{/if} 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/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/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/client/manifest.json b/packages/client/manifest.json index 1d2499a679..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 }, { @@ -5313,6 +5435,11 @@ "label": "Label column", "key": "labelColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "stringLike" + } + }, "required": true }, { @@ -5320,6 +5447,11 @@ "label": "Data column", "key": "valueColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true } ] @@ -5338,6 +5470,11 @@ "label": "Label column", "key": "labelColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "stringLike" + } + }, "required": true }, { @@ -5345,6 +5482,11 @@ "label": "Data column", "key": "valueColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true } ] @@ -5363,6 +5505,11 @@ "label": "Label column", "key": "labelColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "stringLike" + } + }, "required": true }, { @@ -5370,6 +5517,11 @@ "label": "Data columns", "key": "valueColumns", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -5417,6 +5569,11 @@ "label": "Value column", "key": "valueColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -5458,6 +5615,11 @@ "label": "Label column", "key": "labelColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "stringLike" + } + }, "required": true }, { @@ -5465,6 +5627,11 @@ "label": "Data columns", "key": "valueColumns", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -5507,6 +5674,11 @@ "label": "Label columns", "key": "labelColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "stringLike" + } + }, "required": true }, { @@ -5514,6 +5686,11 @@ "label": "Data columns", "key": "valueColumns", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -5568,6 +5745,11 @@ "label": "Date column", "key": "dateColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "datetimeLike" + } + }, "required": true }, { @@ -5575,6 +5757,11 @@ "label": "Open column", "key": "openColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -5582,6 +5769,11 @@ "label": "Close column", "key": "closeColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -5589,6 +5781,11 @@ "label": "High column", "key": "highColumn", "dependsOn": "dataSource", + "explanation": { + "typeSupport": { + "preset": "numberLike" + } + }, "required": true }, { @@ -5596,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 a7db1ee7ef..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,7 +33,6 @@ "sanitize-html": "^2.7.0", "screenfull": "^6.0.1", "shortid": "^2.2.15", - "svelte-apexcharts": "^1.0.2", "svelte-spa-router": "^4.0.1", "atrament": "^4.3.0" }, diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index df7fce0374..8eacbdf041 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -287,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/blocks/ChartBlock.svelte b/packages/client/src/components/app/blocks/ChartBlock.svelte index 2767c44b8e..ddfc7b522b 100644 --- a/packages/client/src/components/app/blocks/ChartBlock.svelte +++ b/packages/client/src/components/app/blocks/ChartBlock.svelte @@ -32,7 +32,7 @@ // Bar/Line/Area export let valueColumns - export let yAxisUnits + export let valueUnits export let yAxisLabel export let xAxisLabel export let curve @@ -51,8 +51,6 @@ export let bucketCount let dataProviderId - - $: colors = c1 && c2 && c3 && c4 && c5 ? [c1, c2, c3, c4, c5] : null @@ -84,8 +82,7 @@ dataLabels, legend, animate, - ...colors, - yAxisUnits, + valueUnits, yAxisLabel, xAxisLabel, stacked, @@ -98,6 +95,11 @@ lowColumn, dateColumn, bucketCount, + c1, + c2, + c3, + c4, + c5, }} /> {/if} diff --git a/packages/client/src/components/app/charts/ApexChart.svelte b/packages/client/src/components/app/charts/ApexChart.svelte index b25be421f7..33e6cdfa80 100644 --- a/packages/client/src/components/app/charts/ApexChart.svelte +++ b/packages/client/src/components/app/charts/ApexChart.svelte @@ -1,25 +1,85 @@ -{#if options} - {#key options.customColor} -
    - {/key} -{:else if $builderStore.inBuilder} -
    - -
    -{/if} +{#key optionsCopy?.customColor} +
    + {#if $builderStore.inBuilder && noData} +
    + + Add rows to your data source to start using your component +
    + {/if} +{/key} 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/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/server/src/api/controllers/component.ts b/packages/server/src/api/controllers/component.ts index 12051be770..6d4d3e2d21 100644 --- a/packages/server/src/api/controllers/component.ts +++ b/packages/server/src/api/controllers/component.ts @@ -20,7 +20,8 @@ export async function fetchAppComponentDefinitions(ctx: UserCtx) { const definitions: { [key: string]: any } = {} for (let { manifest, library } of componentManifests) { for (let key of Object.keys(manifest)) { - if (key === "features") { + // These keys are not components, and should not be preprended with the `@budibase/` prefix + if (key === "features" || key === "typeSupportPresets") { definitions[key] = manifest[key] } else { const fullComponentName = `${library}/${key}`.toLowerCase() diff --git a/yarn.lock b/yarn.lock index 36ce2ce75e..f26b25c6aa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6291,6 +6291,11 @@ js-yaml "^3.10.0" tslib "^2.4.0" +"@yr/monotone-cubic-spline@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@yr/monotone-cubic-spline/-/monotone-cubic-spline-1.0.3.tgz#7272d89f8e4f6fb7a1600c28c378cc18d3b577b9" + integrity sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA== + "@zerodevx/svelte-json-view@^1.0.7": version "1.0.7" resolved "https://registry.yarnpkg.com/@zerodevx/svelte-json-view/-/svelte-json-view-1.0.7.tgz#abf3efa71dedcb3e9d16bc9cc61d5ea98c8d00b1" @@ -6589,11 +6594,12 @@ anymatch@^3.0.3, anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" -apexcharts@^3.19.2, apexcharts@^3.22.1: - version "3.37.1" - resolved "https://registry.yarnpkg.com/apexcharts/-/apexcharts-3.37.1.tgz#50443d302fc7fc72aace9c6c4074baae017c6950" - integrity sha512-fmQ5Updeb/LASl+S1+mIxXUFxzY0Fa7gexfCs4o+OPP9f2NEBNjvybOtPrah44N4roK7U5o5Jis906QeEQu0cA== +apexcharts@^3.48.0: + version "3.49.1" + resolved "https://registry.yarnpkg.com/apexcharts/-/apexcharts-3.49.1.tgz#837d1d4fd80f2c092f0587e8fb6bbc31ad57a0f3" + integrity sha512-MqGtlq/KQuO8j0BBsUJYlRG8VBctKwYdwuBtajHgHTmSgUU3Oai+8oYN/rKCXwXzrUlYA+GiMgotAIbXY2BCGw== dependencies: + "@yr/monotone-cubic-spline" "^1.0.3" svg.draggable.js "^2.2.2" svg.easing.js "^2.0.0" svg.filter.js "^2.0.2" @@ -20039,13 +20045,6 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -svelte-apexcharts@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/svelte-apexcharts/-/svelte-apexcharts-1.0.2.tgz#4e000f8b8f7c901c05658c845457dfc8314d54c1" - integrity sha512-6qlx4rE+XsonZ0FZudfwqOQ34Pq+3wpxgAD75zgEmGoYhYBJcwmikTuTf3o8ZBsZue9U/pAwhNy3ed1Bkq1gmA== - dependencies: - apexcharts "^3.19.2" - svelte-dnd-action@^0.9.8: version "0.9.22" resolved "https://registry.yarnpkg.com/svelte-dnd-action/-/svelte-dnd-action-0.9.22.tgz#003eee9dddb31d8c782f6832aec8b1507fff194d"