@@ -207,6 +198,11 @@
diff --git a/packages/client/src/components/app/charts/ApexOptionsBuilder.js b/packages/client/src/components/app/charts/ApexOptionsBuilder.js
deleted file mode 100644
index 04b5805df3..0000000000
--- a/packages/client/src/components/app/charts/ApexOptionsBuilder.js
+++ /dev/null
@@ -1,195 +0,0 @@
-export class ApexOptionsBuilder {
- constructor() {
- this.formatters = {
- ["Default"]: val => (isNaN(val) ? val : Math.round(val * 100) / 100),
- ["Thousands"]: val => `${Math.round(val / 1000)}K`,
- ["Millions"]: val => `${Math.round(val / 1000000)}M`,
- }
- this.options = {
- series: [],
- legend: {
- show: false,
- position: "top",
- horizontalAlign: "right",
- showForSingleSeries: true,
- showForNullSeries: true,
- showForZeroSeries: true,
- },
- chart: {
- toolbar: {
- show: false,
- },
- zoom: {
- enabled: false,
- },
- },
- xaxis: {
- labels: {
- formatter: this.formatters.Default,
- },
- },
- yaxis: {
- labels: {
- formatter: this.formatters.Default,
- },
- },
- }
- }
-
- setOption(path, value) {
- if (value == null || value === "") {
- return this
- }
- let tmp = this.options
- for (let i = 0; i < path.length - 1; i++) {
- const step = path[i]
- if (!tmp[step]) {
- tmp[step] = {}
- }
- tmp = tmp[step]
- }
- tmp[path[path.length - 1]] = value
- return this
- }
-
- getOptions() {
- return this.options
- }
-
- type(type) {
- return this.setOption(["chart", "type"], type)
- }
-
- title(title) {
- return this.setOption(["title", "text"], title)
- }
-
- colors(colors) {
- if (!colors) {
- delete this.options.colors
- this.options["customColor"] = false
- return this
- }
- this.options["customColor"] = true
- return this.setOption(["colors"], colors)
- }
-
- width(width) {
- return this.setOption(["chart", "width"], width || undefined)
- }
-
- height(height) {
- return this.setOption(["chart", "height"], height || undefined)
- }
-
- xLabel(label) {
- return this.setOption(["xaxis", "title", "text"], label)
- }
-
- yLabel(label) {
- return this.setOption(["yaxis", "title", "text"], label)
- }
-
- xCategories(categories) {
- return this.setOption(["xaxis", "categories"], categories)
- }
-
- yCategories(categories) {
- return this.setOption(["yaxis", "categories"], categories)
- }
-
- series(series) {
- return this.setOption(["series"], series)
- }
-
- horizontal(horizontal) {
- return this.setOption(["plotOptions", "bar", "horizontal"], horizontal)
- }
-
- dataLabels(dataLabels) {
- return this.setOption(["dataLabels", "enabled"], dataLabels)
- }
-
- animate(animate) {
- return this.setOption(["chart", "animations", "enabled"], animate)
- }
-
- curve(curve) {
- return this.setOption(["stroke", "curve"], curve)
- }
-
- gradient(gradient) {
- const fill = {
- type: "gradient",
- gradient: {
- shadeIntensity: 1,
- opacityFrom: 0.7,
- opacityTo: 0.9,
- stops: [0, 90, 100],
- },
- }
- return this.setOption(["fill"], gradient ? fill : undefined)
- }
-
- legend(legend) {
- return this.setOption(["legend", "show"], legend)
- }
-
- legendPosition(position) {
- return this.setOption(["legend", "position"], position)
- }
-
- stacked(stacked) {
- return this.setOption(["chart", "stacked"], stacked)
- }
-
- labels(labels) {
- return this.setOption(["labels"], labels)
- }
-
- xUnits(units) {
- return this.setOption(
- ["xaxis", "labels", "formatter"],
- this.formatters[units || "Default"]
- )
- }
-
- yUnits(units) {
- return this.setOption(
- ["yaxis", "labels", "formatter"],
- this.formatters[units || "Default"]
- )
- }
-
- clearXFormatter() {
- delete this.options.xaxis.labels
- return this
- }
-
- clearYFormatter() {
- delete this.options.yaxis.labels
- return this
- }
-
- xType(type) {
- return this.setOption(["xaxis", "type"], type)
- }
-
- yType(type) {
- return this.setOption(["yaxis", "type"], type)
- }
-
- yTooltip(yTooltip) {
- return this.setOption(["yaxis", "tooltip", "enabled"], yTooltip)
- }
-
- palette(palette) {
- if (!palette) {
- return this
- }
- return this.setOption(
- ["theme", "palette"],
- palette.toLowerCase().replace(/[\W]/g, "")
- )
- }
-}
diff --git a/packages/client/src/components/app/charts/AreaChart.svelte b/packages/client/src/components/app/charts/AreaChart.svelte
index dc80b2b9da..a9a61e59f6 100644
--- a/packages/client/src/components/app/charts/AreaChart.svelte
+++ b/packages/client/src/components/app/charts/AreaChart.svelte
@@ -1,5 +1,159 @@
-
+
diff --git a/packages/client/src/components/app/charts/BarChart.svelte b/packages/client/src/components/app/charts/BarChart.svelte
index fd8443e2d6..aeebfe9461 100644
--- a/packages/client/src/components/app/charts/BarChart.svelte
+++ b/packages/client/src/components/app/charts/BarChart.svelte
@@ -1,11 +1,12 @@
diff --git a/packages/client/src/components/app/charts/CandleStickChart.svelte b/packages/client/src/components/app/charts/CandleStickChart.svelte
index b2760b005e..61cdef180b 100644
--- a/packages/client/src/components/app/charts/CandleStickChart.svelte
+++ b/packages/client/src/components/app/charts/CandleStickChart.svelte
@@ -1,6 +1,6 @@
diff --git a/packages/client/src/components/app/charts/DonutChart.svelte b/packages/client/src/components/app/charts/DonutChart.svelte
index 721a09053a..dad9edfd67 100644
--- a/packages/client/src/components/app/charts/DonutChart.svelte
+++ b/packages/client/src/components/app/charts/DonutChart.svelte
@@ -1,5 +1,99 @@
-
+
diff --git a/packages/client/src/components/app/charts/HistogramChart.svelte b/packages/client/src/components/app/charts/HistogramChart.svelte
index 26b9028550..37c395d45f 100644
--- a/packages/client/src/components/app/charts/HistogramChart.svelte
+++ b/packages/client/src/components/app/charts/HistogramChart.svelte
@@ -1,135 +1,154 @@
diff --git a/packages/client/src/components/app/charts/LineChart.svelte b/packages/client/src/components/app/charts/LineChart.svelte
index 7f82a833d2..c2dac189e1 100644
--- a/packages/client/src/components/app/charts/LineChart.svelte
+++ b/packages/client/src/components/app/charts/LineChart.svelte
@@ -1,8 +1,7 @@
diff --git a/packages/client/src/components/app/charts/PieChart.svelte b/packages/client/src/components/app/charts/PieChart.svelte
index 8cb7317d94..3250a2ca95 100644
--- a/packages/client/src/components/app/charts/PieChart.svelte
+++ b/packages/client/src/components/app/charts/PieChart.svelte
@@ -1,6 +1,6 @@
diff --git a/packages/client/src/components/app/charts/utils.js b/packages/client/src/components/app/charts/utils.js
new file mode 100644
index 0000000000..1aea22c991
--- /dev/null
+++ b/packages/client/src/components/app/charts/utils.js
@@ -0,0 +1,51 @@
+export const formatters = {
+ ["Default"]: val => val,
+ ["Thousands"]: val => `${Math.round(val / 1000)}K`,
+ ["Millions"]: val => `${Math.round(val / 1000000)}M`,
+ ["Datetime"]: val => new Date(val).toLocaleString(),
+}
+
+export const parsePalette = paletteName => {
+ if (paletteName === "Custom") {
+ // return null in this case so that the palette option doesn't get consumed by Apex Charts
+ return null
+ }
+
+ const [_, number] = paletteName.split(" ")
+
+ return `palette${number}`
+}
+
+// Deep clone which copies function references
+export const cloneDeep = value => {
+ const typesToNaiveCopy = ["string", "boolean", "number", "function", "symbol"]
+
+ if (value === null) {
+ return null
+ }
+
+ if (value === undefined) {
+ return undefined
+ }
+
+ if (typesToNaiveCopy.includes(typeof value)) {
+ return value
+ }
+
+ if (Array.isArray(value)) {
+ return value.map(element => cloneDeep(element))
+ }
+
+ // Only copy "pure" objects, we want to error on stuff like Maps or Sets
+ if (typeof value === "object" && value.constructor.name === "Object") {
+ const cloneObject = {}
+
+ Object.entries(value).forEach(([key, childValue]) => {
+ cloneObject[key] = cloneDeep(childValue)
+ })
+
+ return cloneObject
+ }
+
+ throw `Unsupported value: "${value}" of type: "${typeof value}"`
+}
diff --git a/packages/client/src/components/app/charts/utils.test.js b/packages/client/src/components/app/charts/utils.test.js
new file mode 100644
index 0000000000..1b065e2fae
--- /dev/null
+++ b/packages/client/src/components/app/charts/utils.test.js
@@ -0,0 +1,31 @@
+import { expect, describe, it, vi } from "vitest"
+import { cloneDeep } from "./utils"
+
+describe("utils", () => {
+ let context
+
+ beforeEach(() => {
+ vi.clearAllMocks()
+ context = {}
+ })
+
+ describe("cloneDeep", () => {
+ beforeEach(() => {
+ context.value = {
+ obj: { one: 1, two: 2 },
+ arr: [1, { first: null, second: undefined }, 2],
+ str: "test",
+ num: 123,
+ bool: true,
+ sym: Symbol("test"),
+ func: () => "some value",
+ }
+ context.cloneValue = cloneDeep(context.value)
+ })
+
+ it("to clone the object and not copy object references", () => {
+ expect(context.cloneValue.obj.one).toEqual(1)
+ expect(context.cloneValue.obj.two).toEqual(2)
+ })
+ })
+})
diff --git a/packages/client/src/components/app/forms/SignatureField.svelte b/packages/client/src/components/app/forms/SignatureField.svelte
new file mode 100644
index 0000000000..bdae148368
--- /dev/null
+++ b/packages/client/src/components/app/forms/SignatureField.svelte
@@ -0,0 +1,129 @@
+
+
+
+
+
+ {#if fieldState}
+ {#if (Array.isArray(fieldState?.value) && !fieldState?.value?.length) || !fieldState?.value}
+ {
+ if (!$builderStore.inBuilder) {
+ modal.show()
+ }
+ }}
+ >
+ Add signature
+
+ {:else}
+
+
+
+ {/if}
+ {/if}
+
+
+
diff --git a/packages/client/src/components/app/forms/index.js b/packages/client/src/components/app/forms/index.js
index 15966c3765..391b5fa19f 100644
--- a/packages/client/src/components/app/forms/index.js
+++ b/packages/client/src/components/app/forms/index.js
@@ -16,5 +16,6 @@ export { default as formstep } from "./FormStep.svelte"
export { default as jsonfield } from "./JSONField.svelte"
export { default as s3upload } from "./S3Upload.svelte"
export { default as codescanner } from "./CodeScannerField.svelte"
+export { default as signaturesinglefield } from "./SignatureField.svelte"
export { default as bbreferencefield } from "./BBReferenceField.svelte"
export { default as bbreferencesinglefield } from "./BBReferenceSingleField.svelte"
diff --git a/packages/client/src/components/app/forms/validation.js b/packages/client/src/components/app/forms/validation.js
index bdd7213cb0..46a5330cf3 100644
--- a/packages/client/src/components/app/forms/validation.js
+++ b/packages/client/src/components/app/forms/validation.js
@@ -200,6 +200,17 @@ const parseType = (value, type) => {
return value
}
+ // Parse attachment/signature single, treating no key as null
+ if (
+ type === FieldTypes.ATTACHMENT_SINGLE ||
+ type === FieldTypes.SIGNATURE_SINGLE
+ ) {
+ if (!value?.key) {
+ return null
+ }
+ return value
+ }
+
// Parse links, treating no elements as null
if (type === FieldTypes.LINK) {
if (!Array.isArray(value) || !value.length) {
@@ -246,10 +257,8 @@ const maxLengthHandler = (value, rule) => {
// Evaluates a max file size (MB) constraint
const maxFileSizeHandler = (value, rule) => {
const limit = parseType(rule.value, "number")
- return (
- value == null ||
- !value.some(attachment => attachment.size / 1000000 > limit)
- )
+ const check = attachment => attachment.size / 1000000 > limit
+ return value == null || !(value?.key ? check(value) : value.some(check))
}
// Evaluates a max total upload size (MB) constraint
@@ -257,8 +266,11 @@ const maxUploadSizeHandler = (value, rule) => {
const limit = parseType(rule.value, "number")
return (
value == null ||
- value.reduce((acc, currentItem) => acc + currentItem.size, 0) / 1000000 <=
- limit
+ (value?.key
+ ? value.size / 1000000 <= limit
+ : value.reduce((acc, currentItem) => acc + currentItem.size, 0) /
+ 1000000 <=
+ limit)
)
}
diff --git a/packages/client/src/utils/componentProps.js b/packages/client/src/utils/componentProps.js
index efe69938e7..bdf74c8014 100644
--- a/packages/client/src/utils/componentProps.js
+++ b/packages/client/src/utils/componentProps.js
@@ -108,7 +108,12 @@ export const getSettingsDefinition = definition => {
let settings = []
definition.settings?.forEach(setting => {
if (setting.section) {
- settings = settings.concat(setting.settings || [])
+ settings = settings.concat(
+ (setting.settings || [])?.map(childSetting => ({
+ ...childSetting,
+ sectionDependsOn: setting.dependsOn,
+ }))
+ )
} else {
settings.push(setting)
}
diff --git a/packages/frontend-core/src/components/SignatureModal.svelte b/packages/frontend-core/src/components/SignatureModal.svelte
new file mode 100644
index 0000000000..8132c5bced
--- /dev/null
+++ b/packages/frontend-core/src/components/SignatureModal.svelte
@@ -0,0 +1,59 @@
+
+
+
+ {
+ onConfirm(canvas)
+ }}
+ >
+
+ {title}
+
+
+ {
+ edited = true
+ }}
+ />
+
+
+
+
+
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 @@