From 61a143628b2fccfc88030b07ba55cdce6a18cc04 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 7 Jun 2023 10:48:08 +0100 Subject: [PATCH 001/158] Revert tableType flag and derive from table instead --- .../builder/src/components/backend/DataTable/DataTable.svelte | 1 - .../backend/DataTable/buttons/grid/GridImportButton.svelte | 4 ++-- .../components/backend/DataTable/modals/ImportModal.svelte | 1 + packages/frontend-core/src/components/grid/layout/Grid.svelte | 2 -- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/builder/src/components/backend/DataTable/DataTable.svelte b/packages/builder/src/components/backend/DataTable/DataTable.svelte index 1b0c92bde0..81df5a475d 100644 --- a/packages/builder/src/components/backend/DataTable/DataTable.svelte +++ b/packages/builder/src/components/backend/DataTable/DataTable.svelte @@ -32,7 +32,6 @@ diff --git a/packages/builder/src/components/backend/DataTable/modals/ImportModal.svelte b/packages/builder/src/components/backend/DataTable/modals/ImportModal.svelte index c020d1a7ac..1696c6ba03 100644 --- a/packages/builder/src/components/backend/DataTable/modals/ImportModal.svelte +++ b/packages/builder/src/components/backend/DataTable/modals/ImportModal.svelte @@ -14,6 +14,7 @@ export let tableId export let tableType + let rows = [] let allValid = false let displayColumn = null diff --git a/packages/frontend-core/src/components/grid/layout/Grid.svelte b/packages/frontend-core/src/components/grid/layout/Grid.svelte index 81f42ca257..dc24fc0d64 100644 --- a/packages/frontend-core/src/components/grid/layout/Grid.svelte +++ b/packages/frontend-core/src/components/grid/layout/Grid.svelte @@ -33,7 +33,6 @@ export let API = null export let tableId = null - export let tableType = null export let schemaOverrides = null export let allowAddRows = true export let allowAddColumns = true @@ -67,7 +66,6 @@ rand, config, tableId: tableIdStore, - tableType, schemaOverrides: schemaOverridesStore, } context = { ...context, ...createEventManagers() } From 752dd93d84fbdc4aa02f363128b77a630cd6451d Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 7 Jun 2023 15:50:38 +0100 Subject: [PATCH 002/158] Add initial grid block, and update grid to keep indentation consistent when row expansion is disabled --- .../new/_components/componentStructure.json | 1 + packages/client/manifest.json | 20 ++++++++++ .../src/components/app/GridBlock.svelte | 37 +++++++++++++++++++ packages/client/src/components/app/index.js | 1 + .../components/grid/cells/GutterCell.svelte | 6 ++- .../src/components/grid/layout/Grid.svelte | 35 ++++++++++-------- 6 files changed, 83 insertions(+), 17 deletions(-) create mode 100644 packages/client/src/components/app/GridBlock.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/new/_components/componentStructure.json b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/new/_components/componentStructure.json index d35e7cd515..012ab461f0 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/new/_components/componentStructure.json +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/new/_components/componentStructure.json @@ -3,6 +3,7 @@ "name": "Blocks", "icon": "Article", "children": [ + "gridblock", "tableblock", "cardsblock", "repeaterblock", diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 71637723c1..b3e4438646 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -5225,5 +5225,25 @@ "type": "schema", "suffix": "repeater" } + }, + "gridblock": { + "block": true, + "name": "Grid block", + "icon": "Table", + "styles": [ + "size" + ], + "size": { + "width": 600, + "height": 400 + }, + "settings": [ + { + "type": "table", + "label": "Table", + "key": "table", + "required": true + } + ] } } diff --git a/packages/client/src/components/app/GridBlock.svelte b/packages/client/src/components/app/GridBlock.svelte new file mode 100644 index 0000000000..aae41b30c6 --- /dev/null +++ b/packages/client/src/components/app/GridBlock.svelte @@ -0,0 +1,37 @@ + + +
+ +
+ + diff --git a/packages/client/src/components/app/index.js b/packages/client/src/components/app/index.js index 70074790ac..060c15a857 100644 --- a/packages/client/src/components/app/index.js +++ b/packages/client/src/components/app/index.js @@ -36,6 +36,7 @@ export { default as markdownviewer } from "./MarkdownViewer.svelte" export { default as embeddedmap } from "./embedded-map/EmbeddedMap.svelte" export { default as grid } from "./Grid.svelte" export { default as sidepanel } from "./SidePanel.svelte" +export { default as gridblock } from "./GridBlock.svelte" export * from "./charts" export * from "./forms" export * from "./table" diff --git a/packages/frontend-core/src/components/grid/cells/GutterCell.svelte b/packages/frontend-core/src/components/grid/cells/GutterCell.svelte index 56c4c20d54..a8e0da85de 100644 --- a/packages/frontend-core/src/components/grid/cells/GutterCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/GutterCell.svelte @@ -70,10 +70,12 @@ color="var(--spectrum-global-color-red-400)" /> - {:else if $config.allowExpandRows} + {:else}
diff --git a/packages/frontend-core/src/components/grid/layout/Grid.svelte b/packages/frontend-core/src/components/grid/layout/Grid.svelte index dc24fc0d64..3fead0c926 100644 --- a/packages/frontend-core/src/components/grid/layout/Grid.svelte +++ b/packages/frontend-core/src/components/grid/layout/Grid.svelte @@ -43,6 +43,9 @@ export let stripeRows = false export let collaboration = true export let showAvatars = true + export let showControls = true + + allowExpandRows = false // Unique identifier for DOM nodes inside this instance const rand = Math.random() @@ -117,22 +120,24 @@ class:stripe={$config.stripeRows} style="--row-height:{$rowHeight}px; --default-row-height:{DefaultRowHeight}px; --gutter-width:{GutterWidth}px; --max-cell-render-height:{MaxCellRenderHeight}px; --max-cell-render-width-overflow:{MaxCellRenderWidthOverflow}px; --content-lines:{$contentLines};" > -
-
- - - - - - - + {#if showControls} +
+
+ + + + + + + +
+
+ {#if showAvatars} + + {/if} +
-
- {#if showAvatars} - - {/if} -
-
+ {/if} {#if $loaded}
From f9a8be507dfc1c607fadba73e2216105ee12d03a Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 7 Jun 2023 15:51:27 +0100 Subject: [PATCH 003/158] Undo hardcoded disabling of row expansion --- packages/frontend-core/src/components/grid/layout/Grid.svelte | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/frontend-core/src/components/grid/layout/Grid.svelte b/packages/frontend-core/src/components/grid/layout/Grid.svelte index 3fead0c926..ae4409ddca 100644 --- a/packages/frontend-core/src/components/grid/layout/Grid.svelte +++ b/packages/frontend-core/src/components/grid/layout/Grid.svelte @@ -45,8 +45,6 @@ export let showAvatars = true export let showControls = true - allowExpandRows = false - // Unique identifier for DOM nodes inside this instance const rand = Math.random() From 5820996e4d55e4c1ffb5dd4ffc5e2ea528fa097c Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 8 Jun 2023 08:35:36 +0100 Subject: [PATCH 004/158] Update grid flags to allow readonly modifications of schema --- packages/client/src/components/app/GridBlock.svelte | 3 +-- .../src/components/grid/cells/HeaderCell.svelte | 4 ++-- .../src/components/grid/controls/AddColumnButton.svelte | 2 +- .../frontend-core/src/components/grid/layout/Grid.svelte | 9 +++------ .../src/components/grid/layout/HeaderRow.svelte | 2 +- .../frontend-core/src/components/grid/stores/columns.js | 6 ++++-- 6 files changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/client/src/components/app/GridBlock.svelte b/packages/client/src/components/app/GridBlock.svelte index aae41b30c6..3bf7fef231 100644 --- a/packages/client/src/components/app/GridBlock.svelte +++ b/packages/client/src/components/app/GridBlock.svelte @@ -21,9 +21,8 @@ {allowEditRows} {allowDeleteRows} showControls={false} - allowAddColumns={false} - allowEditColumns={false} allowExpandRows={false} + allowSchemaChanges={false} />
diff --git a/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte b/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte index 21ee210233..db2e1a729b 100644 --- a/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte @@ -163,7 +163,7 @@ Edit column @@ -171,7 +171,7 @@ icon="Label" on:click={makeDisplayColumn} disabled={idx === "sticky" || - !$config.allowEditColumns || + !$config.allowSchemaChanges || bannedDisplayColumnTypes.includes(column.schema.type)} > Use as display column diff --git a/packages/frontend-core/src/components/grid/controls/AddColumnButton.svelte b/packages/frontend-core/src/components/grid/controls/AddColumnButton.svelte index 6ad241eb65..20125bc49c 100644 --- a/packages/frontend-core/src/components/grid/controls/AddColumnButton.svelte +++ b/packages/frontend-core/src/components/grid/controls/AddColumnButton.svelte @@ -10,7 +10,7 @@ quiet size="M" on:click={() => dispatch("add-column")} - disabled={!$config.allowAddColumns} + disabled={!$config.allowSchemaChanges} > Add column diff --git a/packages/frontend-core/src/components/grid/layout/Grid.svelte b/packages/frontend-core/src/components/grid/layout/Grid.svelte index ae4409ddca..e33cb65940 100644 --- a/packages/frontend-core/src/components/grid/layout/Grid.svelte +++ b/packages/frontend-core/src/components/grid/layout/Grid.svelte @@ -35,11 +35,10 @@ export let tableId = null export let schemaOverrides = null export let allowAddRows = true - export let allowAddColumns = true - export let allowEditColumns = true export let allowExpandRows = true export let allowEditRows = true export let allowDeleteRows = true + export let allowSchemaChanges = true export let stripeRows = false export let collaboration = true export let showAvatars = true @@ -53,8 +52,7 @@ const schemaOverridesStore = writable(schemaOverrides) const config = writable({ allowAddRows, - allowAddColumns, - allowEditColumns, + allowSchemaChanges, allowExpandRows, allowEditRows, allowDeleteRows, @@ -88,8 +86,7 @@ $: schemaOverridesStore.set(schemaOverrides) $: config.set({ allowAddRows, - allowAddColumns, - allowEditColumns, + allowSchemaChanges, allowExpandRows, allowEditRows, allowDeleteRows, diff --git a/packages/frontend-core/src/components/grid/layout/HeaderRow.svelte b/packages/frontend-core/src/components/grid/layout/HeaderRow.svelte index 9d6cc2275b..c22ee511a3 100644 --- a/packages/frontend-core/src/components/grid/layout/HeaderRow.svelte +++ b/packages/frontend-core/src/components/grid/layout/HeaderRow.svelte @@ -29,7 +29,7 @@ {/each}
- {#if $config.allowAddColumns} + {#if $config.allowSchemaChanges}
{ } export const deriveStores = context => { - const { table, columns, stickyColumn, API, dispatch } = context + const { table, columns, stickyColumn, API, dispatch, config } = context // Updates the tables primary display column const changePrimaryDisplay = async column => { @@ -95,7 +95,9 @@ export const deriveStores = context => { dispatch("updatetable", newTable) // Update server - await API.saveTable(newTable) + if (get(config).allowSchemaChanges) { + await API.saveTable(newTable) + } } return { From 557e7ad209d9a89e7a483951222da1a541567339 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Tue, 13 Jun 2023 16:48:59 +0100 Subject: [PATCH 005/158] Request password on import app --- .../components/start/CreateAppModal.svelte | 174 ++++++++++++------ 1 file changed, 119 insertions(+), 55 deletions(-) diff --git a/packages/builder/src/components/start/CreateAppModal.svelte b/packages/builder/src/components/start/CreateAppModal.svelte index 9e055cd798..ab42d27023 100644 --- a/packages/builder/src/components/start/CreateAppModal.svelte +++ b/packages/builder/src/components/start/CreateAppModal.svelte @@ -1,6 +1,12 @@ - {#if template && !template?.fromFile} - - {/if} - {#if template?.fromFile} - { - $values.file = e.detail?.[0] - $validation.touched.file = true - }} - /> - {/if} - ($validation.touched.name = true)} - on:change={nameToUrl($values.name)} - label="Name" - placeholder={defaultAppName} - /> - - ($validation.touched.url = true)} - on:change={tidyUrl($values.url)} - label="URL" - placeholder={$values.url - ? $values.url - : `/${resolveAppUrl(template, $values.name)}`} - /> - {#if $values.url && $values.url !== "" && !$validation.errors.url} -
- {appUrl} -
+ {#if currentStep === Step.CONFIG} + {#if template && !template?.fromFile} + {/if} -
+ {#if template?.fromFile} + { + $values.file = e.detail?.[0] + $validation.touched.file = true + }} + /> + {/if} + ($validation.touched.name = true)} + on:change={nameToUrl($values.name)} + label="Name" + placeholder={defaultAppName} + /> + + ($validation.touched.url = true)} + on:change={tidyUrl($values.url)} + label="URL" + placeholder={$values.url + ? $values.url + : `/${resolveAppUrl(template, $values.name)}`} + /> + {#if $values.url && $values.url !== "" && !$validation.errors.url} +
+ {appUrl} +
+ {/if} +
+ {/if} + {#if currentStep === Step.SET_PASSWORD} + ($encryptionValidation.touched.encryptionPassword = true)} + error={$encryptionValidation.touched.encryptionPassword && + $encryptionValidation.errors.encryptionPassword} + /> + {/if}
diff --git a/packages/frontend-core/src/components/grid/layout/Grid.svelte b/packages/frontend-core/src/components/grid/layout/Grid.svelte index e33cb65940..e6550fa5a5 100644 --- a/packages/frontend-core/src/components/grid/layout/Grid.svelte +++ b/packages/frontend-core/src/components/grid/layout/Grid.svelte @@ -232,7 +232,7 @@ border-bottom: 2px solid var(--spectrum-global-color-gray-200); padding: var(--cell-padding); gap: var(--cell-spacing); - background: var(--background); + background: var(--spectrum-global-color-gray-100); z-index: 2; } .controls-left, diff --git a/packages/frontend-core/src/components/grid/layout/NewRow.svelte b/packages/frontend-core/src/components/grid/layout/NewRow.svelte index 85b430f79b..4581e37746 100644 --- a/packages/frontend-core/src/components/grid/layout/NewRow.svelte +++ b/packages/frontend-core/src/components/grid/layout/NewRow.svelte @@ -141,6 +141,17 @@ }) + +{#if !visible} +
dispatch("add-row-inline")} + transition:fade|local={{ duration: 130 }} + > + +
+{/if} + {#if visible}
+ /* New row FAB */ + .new-row-fab { + position: absolute; + top: var(--default-row-height); + left: calc(var(--gutter-width) / 2); + transform: translateX(8px) translateY(-50%); + background: var(--cell-background); + padding: 4px; + border-radius: 50%; + border: var(--cell-border); + z-index: 10; + } + .new-row-fab:hover { + background: var(--cell-background-hover); + cursor: pointer; + } + .container { position: absolute; top: var(--default-row-height); From f56bd3ad13257fbede01e1a1d9004941c526da33 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 13 Jun 2023 17:19:12 +0100 Subject: [PATCH 009/158] Fix grid loading overlay color in client apps --- packages/frontend-core/src/components/grid/layout/Grid.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend-core/src/components/grid/layout/Grid.svelte b/packages/frontend-core/src/components/grid/layout/Grid.svelte index e6550fa5a5..c4828e2791 100644 --- a/packages/frontend-core/src/components/grid/layout/Grid.svelte +++ b/packages/frontend-core/src/components/grid/layout/Grid.svelte @@ -268,7 +268,7 @@ left: 0; width: 100%; height: 100%; - background: var(--background); + background: var(--spectrum-global-color-gray-100); opacity: 0.6; } From 9991fd9558bbb877525ed8fe69ffce6120dfaca0 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 14 Jun 2023 09:09:59 +0100 Subject: [PATCH 010/158] Add grid block setting for striping row colours --- packages/client/manifest.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 883d6fa0a6..327b05a320 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -5261,6 +5261,12 @@ "label": "Delete rows", "key": "allowDeleteRows", "defaultValue": true + }, + { + "type": "boolean", + "label": "Stripe rows", + "key": "stripeRows", + "defaultValue": false } ] } From ed9065aae3c76b33706d62fc84054aef7f9577e6 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 14 Jun 2023 09:10:09 +0100 Subject: [PATCH 011/158] Hide add row FAB when selecting rows --- packages/client/src/components/app/GridBlock.svelte | 8 +++++--- .../components/grid/controls/BulkDeleteHandler.svelte | 10 ++-------- .../src/components/grid/layout/Grid.svelte | 2 ++ .../src/components/grid/layout/NewRow.svelte | 7 +++++-- .../src/components/grid/layout/StickyColumn.svelte | 2 +- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/packages/client/src/components/app/GridBlock.svelte b/packages/client/src/components/app/GridBlock.svelte index 7e69fcdcea..6fe436c0e2 100644 --- a/packages/client/src/components/app/GridBlock.svelte +++ b/packages/client/src/components/app/GridBlock.svelte @@ -5,9 +5,10 @@ import { Grid } from "@budibase/frontend-core" export let table - export let allowAddRows - export let allowEditRows - export let allowDeleteRows + export let allowAddRows = true + export let allowEditRows = true + export let allowDeleteRows = true + export let stripeRows = false const component = getContext("component") const { styleable, API, builderStore } = getContext("sdk") @@ -23,6 +24,7 @@ {allowAddRows} {allowEditRows} {allowDeleteRows} + {stripeRows} showControls={false} allowExpandRows={false} allowSchemaChanges={false} diff --git a/packages/frontend-core/src/components/grid/controls/BulkDeleteHandler.svelte b/packages/frontend-core/src/components/grid/controls/BulkDeleteHandler.svelte index f87b529390..3218ef9ffe 100644 --- a/packages/frontend-core/src/components/grid/controls/BulkDeleteHandler.svelte +++ b/packages/frontend-core/src/components/grid/controls/BulkDeleteHandler.svelte @@ -6,15 +6,9 @@ let modal - $: selectedRowCount = Object.values($selectedRows).filter(x => !!x).length + $: selectedRowCount = Object.values($selectedRows).length $: rowsToDelete = Object.entries($selectedRows) - .map(entry => { - if (entry[1] === true) { - return $rows.find(x => x._id === entry[0]) - } else { - return null - } - }) + .map(entry => $rows.find(x => x._id === entry[0])) .filter(x => x != null) // Deletion callback when confirmed diff --git a/packages/frontend-core/src/components/grid/layout/Grid.svelte b/packages/frontend-core/src/components/grid/layout/Grid.svelte index c4828e2791..8cf5803f23 100644 --- a/packages/frontend-core/src/components/grid/layout/Grid.svelte +++ b/packages/frontend-core/src/components/grid/layout/Grid.svelte @@ -57,6 +57,7 @@ allowEditRows, allowDeleteRows, stripeRows, + showControls, }) // Build up context @@ -91,6 +92,7 @@ allowEditRows, allowDeleteRows, stripeRows, + showControls, }) // Set context for children to consume diff --git a/packages/frontend-core/src/components/grid/layout/NewRow.svelte b/packages/frontend-core/src/components/grid/layout/NewRow.svelte index 4581e37746..06e4f0bfd6 100644 --- a/packages/frontend-core/src/components/grid/layout/NewRow.svelte +++ b/packages/frontend-core/src/components/grid/layout/NewRow.svelte @@ -26,6 +26,8 @@ maxScrollTop, rowVerticalInversionIndex, columnHorizontalInversionIndex, + config, + selectedRows, } = getContext("grid") let visible = false @@ -37,6 +39,7 @@ $: width = GutterWidth + ($stickyColumn?.width || 0) $: $tableId, (visible = false) $: invertY = shouldInvertY(offset, $rowVerticalInversionIndex, $renderedRows) + $: selectedRowCount = Object.values($selectedRows).length const shouldInvertY = (offset, inversionIndex, rows) => { if (offset === 0) { @@ -142,7 +145,7 @@ -{#if !visible} +{#if !visible && !$config.showControls && !selectedRowCount}
dispatch("add-row-inline")} @@ -243,7 +246,7 @@ position: absolute; top: var(--default-row-height); left: calc(var(--gutter-width) / 2); - transform: translateX(8px) translateY(-50%); + transform: translateX(6px) translateY(-50%); background: var(--cell-background); padding: 4px; border-radius: 50%; diff --git a/packages/frontend-core/src/components/grid/layout/StickyColumn.svelte b/packages/frontend-core/src/components/grid/layout/StickyColumn.svelte index 801772ed51..f8a65faadb 100644 --- a/packages/frontend-core/src/components/grid/layout/StickyColumn.svelte +++ b/packages/frontend-core/src/components/grid/layout/StickyColumn.svelte @@ -26,7 +26,7 @@ } = getContext("grid") $: rowCount = $rows.length - $: selectedRowCount = Object.values($selectedRows).filter(x => !!x).length + $: selectedRowCount = Object.values($selectedRows).length $: width = GutterWidth + ($stickyColumn?.width || 0) const selectAll = () => { From 328336463c1c47955bc37104e965737f783d08c3 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 14 Jun 2023 09:19:11 +0100 Subject: [PATCH 012/158] Standardise usage of CSS variables to work inside client and builder --- .../grid/cells/AttachmentCell.svelte | 2 +- .../components/grid/cells/HeaderCell.svelte | 2 +- .../components/grid/cells/OptionsCell.svelte | 2 +- .../grid/cells/RelationshipCell.svelte | 2 +- .../src/components/grid/layout/Grid.svelte | 28 ++++++++++--------- .../components/grid/layout/HeaderRow.svelte | 4 +-- .../grid/layout/StickyColumn.svelte | 2 +- 7 files changed, 22 insertions(+), 20 deletions(-) diff --git a/packages/frontend-core/src/components/grid/cells/AttachmentCell.svelte b/packages/frontend-core/src/components/grid/cells/AttachmentCell.svelte index 4d830723c2..c054c57498 100644 --- a/packages/frontend-core/src/components/grid/cells/AttachmentCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/AttachmentCell.svelte @@ -138,7 +138,7 @@ top: 100%; left: 0; width: 320px; - background: var(--background); + background: var(--grid-background-alt); border: var(--cell-border); padding: var(--cell-padding); box-shadow: 0 0 20px -4px rgba(0, 0, 0, 0.15); diff --git a/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte b/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte index db2e1a729b..e773af9e14 100644 --- a/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/HeaderCell.svelte @@ -218,7 +218,7 @@ .header-cell :global(.cell) { padding: 0 var(--cell-padding); gap: calc(2 * var(--cell-spacing)); - background: var(--spectrum-global-color-gray-100); + background: var(--grid-background-alt); } .name { diff --git a/packages/frontend-core/src/components/grid/cells/OptionsCell.svelte b/packages/frontend-core/src/components/grid/cells/OptionsCell.svelte index 9399617eb7..46ad048c20 100644 --- a/packages/frontend-core/src/components/grid/cells/OptionsCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/OptionsCell.svelte @@ -240,7 +240,7 @@ justify-content: space-between; align-items: center; gap: var(--cell-spacing); - background-color: var(--background); + background-color: var(--grid-background-alt); } .option:hover, .option.focused { diff --git a/packages/frontend-core/src/components/grid/cells/RelationshipCell.svelte b/packages/frontend-core/src/components/grid/cells/RelationshipCell.svelte index 40b6de5eaa..2bd0a17054 100644 --- a/packages/frontend-core/src/components/grid/cells/RelationshipCell.svelte +++ b/packages/frontend-core/src/components/grid/cells/RelationshipCell.svelte @@ -453,7 +453,7 @@ var(--max-cell-render-height) + var(--row-height) - var(--max-relationship-height) ); - background: var(--background); + background: var(--grid-background-alt); border: var(--cell-border); box-shadow: 0 0 20px -4px rgba(0, 0, 0, 0.15); display: flex; diff --git a/packages/frontend-core/src/components/grid/layout/Grid.svelte b/packages/frontend-core/src/components/grid/layout/Grid.svelte index 8cf5803f23..39a67d44eb 100644 --- a/packages/frontend-core/src/components/grid/layout/Grid.svelte +++ b/packages/frontend-core/src/components/grid/layout/Grid.svelte @@ -168,6 +168,18 @@ diff --git a/packages/frontend-core/src/components/grid/layout/HeaderRow.svelte b/packages/frontend-core/src/components/grid/layout/HeaderRow.svelte index c22ee511a3..f31cc198fb 100644 --- a/packages/frontend-core/src/components/grid/layout/HeaderRow.svelte +++ b/packages/frontend-core/src/components/grid/layout/HeaderRow.svelte @@ -42,7 +42,7 @@ From 887b980b11c8a6bf87b1da4f155c4cbe40f71e7a Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Fri, 16 Jun 2023 11:34:02 +0100 Subject: [PATCH 026/158] Revert "Merge pull request #10927 from Budibase/revert-merge-develop-1" This reverts commit 548b3037e5c3b4428cbc410cf74a54cc66ee59aa, reversing changes made to 179f06f106d7b1dc262cc744c936d3380467e15e. --- lerna.json | 1 - package.json | 4 +- .../middleware/passport/datasource/google.ts | 46 +- .../backend-core/src/security/encryption.ts | 125 +- packages/backend-core/src/security/roles.ts | 9 +- .../bbui/src/FancyForm/FancyCheckbox.svelte | 20 +- .../src/FancyForm/FancyCheckboxGroup.svelte | 68 + packages/bbui/src/FancyForm/FancyField.svelte | 15 +- packages/bbui/src/FancyForm/index.js | 1 + packages/bbui/src/Form/Core/Checkbox.svelte | 2 + packages/bbui/src/Modal/Modal.svelte | 3 +- .../builder/src/builderStore/datasource.js | 16 +- .../src/builderStore/store/frontend.js | 1 + .../SetupPanel/AutomationBlockSetup.svelte | 412 +++--- .../PlusConfigForm.svelte | 36 +- .../_components/GoogleButton.svelte | 14 +- .../DatasourceNavigator/icons/index.js | 3 + .../modals/DatasourceConfigModal.svelte | 94 +- .../modals/GoogleDatasourceConfigModal.svelte | 206 ++- .../commandPalette/CommandPalette.svelte | 2 +- .../src/components/deploy/AppActions.svelte | 5 +- .../components/start/ExportAppModal.svelte | 133 +- .../src/helpers/validation/validation.js | 5 +- .../src/helpers/validation/yup/index.js | 64 + .../_components/PreviewOverlay.svelte | 91 ++ .../builder/app/[application]/_layout.svelte | 11 +- .../datasource/[datasourceId]/index.svelte | 25 +- .../builder/app/[application]/data/new.svelte | 23 +- .../portal/settings/auth/google.svelte | 235 +++ .../builder/portal/settings/auth/index.svelte | 154 +- .../builder/portal/users/users/index.svelte | 2 +- .../builder/src/stores/backend/datasources.js | 6 +- packages/cli/package.json | 2 +- packages/client/src/api/api.js | 10 +- .../client/src/components/ClientApp.svelte | 11 +- .../components/devtools/DevToolsHeader.svelte | 47 +- packages/client/src/index.js | 6 - .../client/src/stores/derived/currentRole.js | 7 +- .../src/stores/derived/devToolsEnabled.js | 10 + packages/client/src/stores/derived/index.js | 1 + packages/client/src/stores/devTools.js | 10 +- packages/frontend-core/src/api/datasources.js | 16 +- packages/server/package.json | 6 +- packages/server/src/api/controllers/backup.ts | 30 +- .../server/src/api/controllers/datasource.ts | 65 +- packages/server/src/api/controllers/role.ts | 10 +- .../server/src/api/controllers/routing.ts | 6 +- packages/server/src/api/routes/backup.ts | 2 +- .../src/api/routes/tests/backup.spec.ts | 20 +- .../src/automations/steps/sendSmtpEmail.ts | 59 +- .../automations/tests/sendSmtpEmail.spec.js | 71 - .../automations/tests/sendSmtpEmail.spec.ts | 74 + .../server/src/events/docUpdates/syncUsers.ts | 4 + .../server/src/integrations/googlesheets.ts | 51 +- packages/server/src/integrations/mongodb.ts | 6 +- packages/server/src/integrations/postgres.ts | 24 +- packages/server/src/middleware/currentapp.ts | 2 +- .../server/src/sdk/app/backups/exports.ts | 38 +- .../server/src/sdk/app/backups/imports.ts | 22 +- .../src/sdk/app/datasources/datasources.ts | 1 + .../server/src/utilities/workerRequests.ts | 29 +- packages/shared-core/src/utils.ts | 39 + packages/types/src/api/web/app/datasource.ts | 1 + .../types/src/documents/app/automation.ts | 30 + packages/worker/package.json | 1 + .../worker/src/api/controllers/global/auth.ts | 1 - .../src/api/controllers/global/email.ts | 2 + packages/worker/src/utilities/email.ts | 41 +- qa-core/package.json | 2 +- qa-core/scripts/testResultsWebhook.js | 10 +- .../src/account-api/api/apis/AccountAPI.ts | 12 +- .../validators/mongo.integration.spec.ts | 2 +- .../validators/postgres.integration.spec.ts | 1 + qa-core/src/jest/globalTeardown.ts | 1 + yarn.lock | 1310 ++++++++--------- 75 files changed, 2501 insertions(+), 1424 deletions(-) create mode 100644 packages/bbui/src/FancyForm/FancyCheckboxGroup.svelte create mode 100644 packages/builder/src/pages/builder/app/[application]/_components/PreviewOverlay.svelte create mode 100644 packages/builder/src/pages/builder/portal/settings/auth/google.svelte create mode 100644 packages/client/src/stores/derived/devToolsEnabled.js delete mode 100644 packages/server/src/automations/tests/sendSmtpEmail.spec.js create mode 100644 packages/server/src/automations/tests/sendSmtpEmail.spec.ts diff --git a/lerna.json b/lerna.json index 86de1e4387..2bded7151f 100644 --- a/lerna.json +++ b/lerna.json @@ -16,7 +16,6 @@ "packages/worker", "packages/pro/packages/pro" ], - "useWorkspaces": true, "command": { "publish": { "ignoreChanges": [ diff --git a/package.json b/package.json index 56f015f8c0..49ffc5fef7 100644 --- a/package.json +++ b/package.json @@ -15,10 +15,10 @@ "husky": "^8.0.3", "js-yaml": "^4.1.0", "kill-port": "^1.6.1", - "lerna": "7.0.0-alpha.0", + "lerna": "^7.0.1", "madge": "^6.0.0", "minimist": "^1.2.8", - "nx": "^16.2.1", + "nx": "^16.3.2", "prettier": "^2.3.1", "prettier-plugin-svelte": "^2.3.0", "rimraf": "^3.0.2", diff --git a/packages/backend-core/src/middleware/passport/datasource/google.ts b/packages/backend-core/src/middleware/passport/datasource/google.ts index 6fd4e9ff32..ae6b3b4913 100644 --- a/packages/backend-core/src/middleware/passport/datasource/google.ts +++ b/packages/backend-core/src/middleware/passport/datasource/google.ts @@ -1,10 +1,11 @@ import * as google from "../sso/google" import { Cookie } from "../../../constants" -import { clearCookie, getCookie } from "../../../utils" -import { doWithDB } from "../../../db" import * as configs from "../../../configs" -import { BBContext, Database, SSOProfile } from "@budibase/types" +import * as cache from "../../../cache" +import * as utils from "../../../utils" +import { UserCtx, SSOProfile } from "@budibase/types" import { ssoSaveUserNoOp } from "../sso/sso" + const GoogleStrategy = require("passport-google-oauth").OAuth2Strategy type Passport = { @@ -22,7 +23,7 @@ async function fetchGoogleCreds() { export async function preAuth( passport: Passport, - ctx: BBContext, + ctx: UserCtx, next: Function ) { // get the relevant config @@ -36,8 +37,8 @@ export async function preAuth( ssoSaveUserNoOp ) - if (!ctx.query.appId || !ctx.query.datasourceId) { - ctx.throw(400, "appId and datasourceId query params not present.") + if (!ctx.query.appId) { + ctx.throw(400, "appId query param not present.") } return passport.authenticate(strategy, { @@ -49,7 +50,7 @@ export async function preAuth( export async function postAuth( passport: Passport, - ctx: BBContext, + ctx: UserCtx, next: Function ) { // get the relevant config @@ -57,7 +58,7 @@ export async function postAuth( const platformUrl = await configs.getPlatformUrl({ tenantAware: false }) let callbackUrl = `${platformUrl}/api/global/auth/datasource/google/callback` - const authStateCookie = getCookie(ctx, Cookie.DatasourceAuth) + const authStateCookie = utils.getCookie(ctx, Cookie.DatasourceAuth) return passport.authenticate( new GoogleStrategy( @@ -69,33 +70,26 @@ export async function postAuth( ( accessToken: string, refreshToken: string, - profile: SSOProfile, + _profile: SSOProfile, done: Function ) => { - clearCookie(ctx, Cookie.DatasourceAuth) + utils.clearCookie(ctx, Cookie.DatasourceAuth) done(null, { accessToken, refreshToken }) } ), { successRedirect: "/", failureRedirect: "/error" }, async (err: any, tokens: string[]) => { const baseUrl = `/builder/app/${authStateCookie.appId}/data` - // update the DB for the datasource with all the user info - await doWithDB(authStateCookie.appId, async (db: Database) => { - let datasource - try { - datasource = await db.get(authStateCookie.datasourceId) - } catch (err: any) { - if (err.status === 404) { - ctx.redirect(baseUrl) - } + + const id = utils.newid() + await cache.store( + `datasource:creation:${authStateCookie.appId}:google:${id}`, + { + tokens, } - if (!datasource.config) { - datasource.config = {} - } - datasource.config.auth = { type: "google", ...tokens } - await db.put(datasource) - ctx.redirect(`${baseUrl}/datasource/${authStateCookie.datasourceId}`) - }) + ) + + ctx.redirect(`${baseUrl}/new?continue_google_setup=${id}`) } )(ctx, next) } diff --git a/packages/backend-core/src/security/encryption.ts b/packages/backend-core/src/security/encryption.ts index f9adb68955..7a8cfaf04a 100644 --- a/packages/backend-core/src/security/encryption.ts +++ b/packages/backend-core/src/security/encryption.ts @@ -1,12 +1,17 @@ import crypto from "crypto" +import fs from "fs" +import zlib from "zlib" import env from "../environment" +import { join } from "path" const ALGO = "aes-256-ctr" const SEPARATOR = "-" const ITERATIONS = 10000 -const RANDOM_BYTES = 16 const STRETCH_LENGTH = 32 +const SALT_LENGTH = 16 +const IV_LENGTH = 16 + export enum SecretOption { API = "api", ENCRYPTION = "encryption", @@ -31,15 +36,15 @@ export function getSecret(secretOption: SecretOption): string { return secret } -function stretchString(string: string, salt: Buffer) { - return crypto.pbkdf2Sync(string, salt, ITERATIONS, STRETCH_LENGTH, "sha512") +function stretchString(secret: string, salt: Buffer) { + return crypto.pbkdf2Sync(secret, salt, ITERATIONS, STRETCH_LENGTH, "sha512") } export function encrypt( input: string, secretOption: SecretOption = SecretOption.API ) { - const salt = crypto.randomBytes(RANDOM_BYTES) + const salt = crypto.randomBytes(SALT_LENGTH) const stretched = stretchString(getSecret(secretOption), salt) const cipher = crypto.createCipheriv(ALGO, stretched, salt) const base = cipher.update(input) @@ -60,3 +65,115 @@ export function decrypt( const final = decipher.final() return Buffer.concat([base, final]).toString() } + +export async function encryptFile( + { dir, filename }: { dir: string; filename: string }, + secret: string +) { + const outputFileName = `${filename}.enc` + + const filePath = join(dir, filename) + const inputFile = fs.createReadStream(filePath) + const outputFile = fs.createWriteStream(join(dir, outputFileName)) + + const salt = crypto.randomBytes(SALT_LENGTH) + const iv = crypto.randomBytes(IV_LENGTH) + const stretched = stretchString(secret, salt) + const cipher = crypto.createCipheriv(ALGO, stretched, iv) + + outputFile.write(salt) + outputFile.write(iv) + + inputFile.pipe(zlib.createGzip()).pipe(cipher).pipe(outputFile) + + return new Promise<{ filename: string; dir: string }>(r => { + outputFile.on("finish", () => { + r({ + filename: outputFileName, + dir, + }) + }) + }) +} + +async function getSaltAndIV(path: string) { + const fileStream = fs.createReadStream(path) + + const salt = await readBytes(fileStream, SALT_LENGTH) + const iv = await readBytes(fileStream, IV_LENGTH) + fileStream.close() + return { salt, iv } +} + +export async function decryptFile( + inputPath: string, + outputPath: string, + secret: string +) { + const { salt, iv } = await getSaltAndIV(inputPath) + const inputFile = fs.createReadStream(inputPath, { + start: SALT_LENGTH + IV_LENGTH, + }) + + const outputFile = fs.createWriteStream(outputPath) + + const stretched = stretchString(secret, salt) + const decipher = crypto.createDecipheriv(ALGO, stretched, iv) + + const unzip = zlib.createGunzip() + + inputFile.pipe(decipher).pipe(unzip).pipe(outputFile) + + return new Promise((res, rej) => { + outputFile.on("finish", () => { + outputFile.close() + res() + }) + + inputFile.on("error", e => { + outputFile.close() + rej(e) + }) + + decipher.on("error", e => { + outputFile.close() + rej(e) + }) + + unzip.on("error", e => { + outputFile.close() + rej(e) + }) + + outputFile.on("error", e => { + outputFile.close() + rej(e) + }) + }) +} + +function readBytes(stream: fs.ReadStream, length: number) { + return new Promise((resolve, reject) => { + let bytesRead = 0 + const data: Buffer[] = [] + + stream.on("readable", () => { + let chunk + + while ((chunk = stream.read(length - bytesRead)) !== null) { + data.push(chunk) + bytesRead += chunk.length + } + + resolve(Buffer.concat(data)) + }) + + stream.on("end", () => { + reject(new Error("Insufficient data in the stream.")) + }) + + stream.on("error", error => { + reject(error) + }) + }) +} diff --git a/packages/backend-core/src/security/roles.ts b/packages/backend-core/src/security/roles.ts index bdf7a38726..e8a3c76c0a 100644 --- a/packages/backend-core/src/security/roles.ts +++ b/packages/backend-core/src/security/roles.ts @@ -140,9 +140,13 @@ export function lowerBuiltinRoleID(roleId1?: string, roleId2?: string): string { * Gets the role object, this is mainly useful for two purposes, to check if the level exists and * to check if the role inherits any others. * @param {string|null} roleId The level ID to lookup. + * @param {object|null} opts options for the function, like whether to halt errors, instead return public. * @returns {Promise} The role object, which may contain an "inherits" property. */ -export async function getRole(roleId?: string): Promise { +export async function getRole( + roleId?: string, + opts?: { defaultPublic?: boolean } +): Promise { if (!roleId) { return undefined } @@ -161,6 +165,9 @@ export async function getRole(roleId?: string): Promise { // finalise the ID role._id = getExternalRoleID(role._id) } catch (err) { + if (!isBuiltin(roleId) && opts?.defaultPublic) { + return cloneDeep(BUILTIN_ROLES.PUBLIC) + } // only throw an error if there is no role at all if (Object.keys(role).length === 0) { throw err diff --git a/packages/bbui/src/FancyForm/FancyCheckbox.svelte b/packages/bbui/src/FancyForm/FancyCheckbox.svelte index 191cc79485..0a2e5ac159 100644 --- a/packages/bbui/src/FancyForm/FancyCheckbox.svelte +++ b/packages/bbui/src/FancyForm/FancyCheckbox.svelte @@ -8,6 +8,8 @@ export let disabled = false export let error = null export let validate = null + export let indeterminate = false + export let compact = false const dispatch = createEventDispatcher() @@ -21,11 +23,19 @@ } - + - + -
+
{#if text} {text} {/if} @@ -47,6 +57,10 @@ line-clamp: 2; -webkit-box-orient: vertical; } + .text.compact { + font-size: 13px; + line-height: 15px; + } .text > :global(*) { font-size: inherit !important; } diff --git a/packages/bbui/src/FancyForm/FancyCheckboxGroup.svelte b/packages/bbui/src/FancyForm/FancyCheckboxGroup.svelte new file mode 100644 index 0000000000..aaea388c36 --- /dev/null +++ b/packages/bbui/src/FancyForm/FancyCheckboxGroup.svelte @@ -0,0 +1,68 @@ + + +{#if options && Array.isArray(options)} +
+ + {#if showSelectAll} + + {/if} + {#each options as option, i} + + {/each} + +
+{/if} + + diff --git a/packages/bbui/src/FancyForm/FancyField.svelte b/packages/bbui/src/FancyForm/FancyField.svelte index 0c99394599..455f4b38fb 100644 --- a/packages/bbui/src/FancyForm/FancyField.svelte +++ b/packages/bbui/src/FancyForm/FancyField.svelte @@ -11,6 +11,7 @@ export let value export let ref export let autoHeight + export let compact = false const formContext = getContext("fancy-form") const id = Math.random() @@ -42,6 +43,7 @@ class:disabled class:focused class:clickable + class:compact class:auto-height={autoHeight} >
@@ -61,7 +63,6 @@ diff --git a/packages/builder/src/components/backend/DatasourceNavigator/_components/GoogleButton.svelte b/packages/builder/src/components/backend/DatasourceNavigator/_components/GoogleButton.svelte index b7d70d88b7..ceb8fd7f4b 100644 --- a/packages/builder/src/components/backend/DatasourceNavigator/_components/GoogleButton.svelte +++ b/packages/builder/src/components/backend/DatasourceNavigator/_components/GoogleButton.svelte @@ -3,8 +3,6 @@ import { store } from "builderStore" import { auth } from "stores/portal" - export let preAuthStep - export let datasource export let disabled export let samePage @@ -15,18 +13,8 @@ class:disabled {disabled} on:click={async () => { - let ds = datasource let appId = $store.appId - if (!ds) { - const resp = await preAuthStep() - if (resp.datasource && resp.appId) { - ds = resp.datasource - appId = resp.appId - } else { - ds = resp - } - } - const url = `/api/global/auth/${tenantId}/datasource/google?datasourceId=${ds._id}&appId=${appId}` + const url = `/api/global/auth/${tenantId}/datasource/google?appId=${appId}` if (samePage) { window.location = url } else { diff --git a/packages/builder/src/components/backend/DatasourceNavigator/icons/index.js b/packages/builder/src/components/backend/DatasourceNavigator/icons/index.js index 18aa361570..2486942dea 100644 --- a/packages/builder/src/components/backend/DatasourceNavigator/icons/index.js +++ b/packages/builder/src/components/backend/DatasourceNavigator/icons/index.js @@ -44,6 +44,9 @@ export default ICONS export function getIcon(integrationType, schema) { const integrationList = get(integrations) + if (!integrationList) { + return + } if (integrationList[integrationType]?.iconUrl) { return { url: integrationList[integrationType].iconUrl } } else if (schema?.custom || !ICONS[integrationType]) { diff --git a/packages/builder/src/components/backend/DatasourceNavigator/modals/DatasourceConfigModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/modals/DatasourceConfigModal.svelte index 31a0d21cd8..1d84dbbe39 100644 --- a/packages/builder/src/components/backend/DatasourceNavigator/modals/DatasourceConfigModal.svelte +++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/DatasourceConfigModal.svelte @@ -1,12 +1,19 @@ saveDatasource()} - confirmText={datasource.plus ? "Connect" : "Save and continue to query"} - cancelText="Back" - showSecondaryButton={datasource.plus} + {title} + onConfirm={() => nextStep()} + {confirmText} + cancelText={fetchTableStep ? "Cancel" : "Back"} + showSecondaryButton={datasourcePlus} size="L" disabled={!isValid} > - Connect your database to Budibase using the config below. + + {#if !fetchTableStep} + Connect your database to Budibase using the config below + {:else} + Choose what tables you want to sync with Budibase + {/if} - (isValid = e.detail)} - /> + {#if !fetchTableStep} + (isValid = e.detail)} + /> + {:else} +
+ +
+ {/if}
+ + diff --git a/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte b/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte index 0783a9fe53..14f81f915c 100644 --- a/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte +++ b/packages/builder/src/components/backend/DatasourceNavigator/modals/GoogleDatasourceConfigModal.svelte @@ -1,43 +1,207 @@ - - {#if isGoogleConfigured === true} - + {#if step === GoogleDatasouceConfigStep.AUTH} + + {#if isGoogleConfigured === true} + + Authenticate with your google account to use the {integrationName} integration. + + + {:else if isGoogleConfigured === false} Authenticate with your google account to use the {IntegrationNames[ - datasource.type - ]} integration.Google authentication is not enabled, please complete Google SSO + configuration. + Configure Google SSO + {/if} + {/if} + {#if step === GoogleDatasouceConfigStep.SET_URL} + + Add the URL of the sheet you want to connect. + + (isValid = e.detail)} + /> + + {/if} + {#if step === GoogleDatasouceConfigStep.SET_SHEETS} + + Select which spreadsheets you want to connect. + + + + {#if setSheetsErrorTitle || setSheetsErrorMessage} + + {/if} - save(datasource, true)} /> - {:else if isGoogleConfigured === false} - Google authentication is not enabled, please complete Google SSO - configuration. - Configure Google SSO {/if} diff --git a/packages/builder/src/components/commandPalette/CommandPalette.svelte b/packages/builder/src/components/commandPalette/CommandPalette.svelte index ae946dc10c..3a369446a3 100644 --- a/packages/builder/src/components/commandPalette/CommandPalette.svelte +++ b/packages/builder/src/components/commandPalette/CommandPalette.svelte @@ -69,7 +69,7 @@ name: "App", description: "", icon: "Play", - action: () => window.open(`/${$store.appId}`), + action: () => store.update(state => ({ ...state, showPreview: true })), }, { type: "Preview", diff --git a/packages/builder/src/components/deploy/AppActions.svelte b/packages/builder/src/components/deploy/AppActions.svelte index 9813237317..a85eb5a154 100644 --- a/packages/builder/src/components/deploy/AppActions.svelte +++ b/packages/builder/src/components/deploy/AppActions.svelte @@ -62,7 +62,10 @@ } const previewApp = () => { - window.open(`/${application}`) + store.update(state => ({ + ...state, + showPreview: true, + })) } const viewApp = () => { diff --git a/packages/builder/src/components/start/ExportAppModal.svelte b/packages/builder/src/components/start/ExportAppModal.svelte index 948416b192..4a69aaef74 100644 --- a/packages/builder/src/components/start/ExportAppModal.svelte +++ b/packages/builder/src/components/start/ExportAppModal.svelte @@ -1,27 +1,128 @@ - - - Apps can be exported with or without data that is within internal tables - - select this below. - + + {#if currentStep === Step.CONFIG} + + + + + {#if !encypt} + + {/if} + {/if} + {#if currentStep === Step.SET_PASSWORD} + + {/if} diff --git a/packages/builder/src/helpers/validation/validation.js b/packages/builder/src/helpers/validation/validation.js index db5dfe4430..f64bf56835 100644 --- a/packages/builder/src/helpers/validation/validation.js +++ b/packages/builder/src/helpers/validation/validation.js @@ -6,7 +6,6 @@ export function createValidationStore(initialValue, ...validators) { let touched = false const value = writable(initialValue || "") - const error = derived(value, $v => validate($v, validators)) const touchedStore = derived(value, () => { if (!touched) { touched = true @@ -14,6 +13,10 @@ export function createValidationStore(initialValue, ...validators) { } return touched }) + const error = derived( + [value, touchedStore], + ([$v, $t]) => $t && validate($v, validators) + ) return [value, error, touchedStore] } diff --git a/packages/builder/src/helpers/validation/yup/index.js b/packages/builder/src/helpers/validation/yup/index.js index 20ddaebb1a..b5bdf030a5 100644 --- a/packages/builder/src/helpers/validation/yup/index.js +++ b/packages/builder/src/helpers/validation/yup/index.js @@ -5,6 +5,7 @@ import { notifications } from "@budibase/bbui" export const createValidationStore = () => { const DEFAULT = { + values: {}, errors: {}, touched: {}, valid: false, @@ -33,6 +34,9 @@ export const createValidationStore = () => { case "email": propertyValidator = string().email().nullable() break + case "password": + propertyValidator = string().nullable() + break default: propertyValidator = string().nullable() } @@ -41,9 +45,68 @@ export const createValidationStore = () => { propertyValidator = propertyValidator.required() } + // We want to do this after the possible required validation, to prioritise the required error + switch (type) { + case "password": + propertyValidator = propertyValidator.min(8) + break + } + validator[propertyName] = propertyValidator } + const observe = async (propertyName, value) => { + const values = get(validation).values + let fieldIsValid + if (!values.hasOwnProperty(propertyName)) { + // Initial setup + values[propertyName] = value + return + } + + if (value === values[propertyName]) { + return + } + + const obj = object().shape(validator) + try { + validation.update(store => { + store.errors[propertyName] = null + return store + }) + await obj.validateAt(propertyName, { [propertyName]: value }) + fieldIsValid = true + } catch (error) { + const [fieldError] = error.errors + if (fieldError) { + validation.update(store => { + store.errors[propertyName] = capitalise(fieldError) + store.valid = false + return store + }) + } + } + + if (fieldIsValid) { + // Validate the rest of the fields + try { + await obj.validate( + { ...values, [propertyName]: value }, + { abortEarly: false } + ) + validation.update(store => { + store.valid = true + return store + }) + } catch { + validation.update(store => { + store.valid = false + return store + }) + } + } + } + const check = async values => { const obj = object().shape(validator) // clear the previous errors @@ -87,5 +150,6 @@ export const createValidationStore = () => { check, addValidator, addValidatorType, + observe, } } diff --git a/packages/builder/src/pages/builder/app/[application]/_components/PreviewOverlay.svelte b/packages/builder/src/pages/builder/app/[application]/_components/PreviewOverlay.svelte new file mode 100644 index 0000000000..d069d1b4c7 --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/_components/PreviewOverlay.svelte @@ -0,0 +1,91 @@ + + +
+
+
+
+ +
+