From 1d0ab398cd22de9b5f26531d523078d728e2ea21 Mon Sep 17 00:00:00 2001 From: Gerard Burns Date: Tue, 18 Jul 2023 15:55:06 +0100 Subject: [PATCH 001/138] New Design Section Nav Component --- .../builder/src/components/design/Pane.svelte | 21 +++ .../src/components/design/RightPanel.svelte | 112 +++++++++++ .../_components/NavigationInfoPanel.svelte | 33 ---- .../NavigationInfoPanel/CustomizePane.svelte | 176 ++++++++++++++++++ .../NavigationInfoPanel/SettingsPane.svelte | 31 +++ .../NavigationInfoPanel/index.svelte | 10 + .../design/[screenId]/navigation/index.svelte | 2 +- 7 files changed, 351 insertions(+), 34 deletions(-) create mode 100644 packages/builder/src/components/design/Pane.svelte create mode 100644 packages/builder/src/components/design/RightPanel.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel.svelte create mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/CustomizePane.svelte create mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/SettingsPane.svelte create mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/index.svelte diff --git a/packages/builder/src/components/design/Pane.svelte b/packages/builder/src/components/design/Pane.svelte new file mode 100644 index 0000000000..88b6ea1c05 --- /dev/null +++ b/packages/builder/src/components/design/Pane.svelte @@ -0,0 +1,21 @@ + + +{#if $paneStore} +
+ +
+{/if} + + diff --git a/packages/builder/src/components/design/RightPanel.svelte b/packages/builder/src/components/design/RightPanel.svelte new file mode 100644 index 0000000000..f9075600f9 --- /dev/null +++ b/packages/builder/src/components/design/RightPanel.svelte @@ -0,0 +1,112 @@ + + +
+
+
+ +
+ {title} +
+
+ {#each Object.entries(panes) as [id, pane]} +
+ +
+ {/each} +
+
+ + +
+ + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel.svelte deleted file mode 100644 index 614e1eed80..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel.svelte +++ /dev/null @@ -1,33 +0,0 @@ - - - - - {#if $selectedScreen.layoutId} - - You can't preview your navigation settings using this screen as it uses - a custom layout, which is deprecated - - {/if} - - Your navigation is configured for all the screens within your app. - - - You can hide and show your navigation for each screen in the screen - settings. - - - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/CustomizePane.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/CustomizePane.svelte new file mode 100644 index 0000000000..05108b1736 --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/CustomizePane.svelte @@ -0,0 +1,176 @@ + + + +
+
+ + CHANGES WILL APPLY TO ALL SCREENS +
+ + Your navigation is configured for all the screens within your app. + +
+ +
+
+ +
+ + update("navigation", "Top")} + /> + update("navigation", "Left")} + /> + + + {#if $store.navigation.navigation === "Top"} +
+ +
+ update("sticky", e.detail)} + /> +
+ +
+ update("logoUrl", e.detail)} + updateOnChange={false} + /> + {/if} +
+ +
+ update("hideTitle", !e.detail)} + /> + {#if !$store.navigation.hideTitle} +
+ +
+ update("title", e.detail)} + updateOnChange={false} + /> + {/if} +
+ +
+ update("navBackground", e.detail)} + /> +
+ +
+ update("navTextColor", e.detail)} + /> +
+
+ + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/SettingsPane.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/SettingsPane.svelte new file mode 100644 index 0000000000..d3ce720994 --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/SettingsPane.svelte @@ -0,0 +1,31 @@ + + + +
+ + Show nav on this screen +
+
+ + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/index.svelte new file mode 100644 index 0000000000..6ce5405f93 --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/index.svelte @@ -0,0 +1,10 @@ + + + + + + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/index.svelte index fc2e03d8e8..2331d8b285 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/index.svelte @@ -1,6 +1,6 @@ From 00c04ec9acb5c4657402c05b57910af18242f0e8 Mon Sep 17 00:00:00 2001 From: Gerard Burns Date: Thu, 20 Jul 2023 10:05:50 +0100 Subject: [PATCH 002/138] New Design Section Nav Component --- .../builder/src/components/design/Pane.svelte | 21 +++ .../src/components/design/RightPanel.svelte | 112 +++++++++++ .../_components/NavigationInfoPanel.svelte | 33 ---- .../NavigationInfoPanel/CustomizePane.svelte | 176 ++++++++++++++++++ .../NavigationInfoPanel/SettingsPane.svelte | 31 +++ .../NavigationInfoPanel/index.svelte | 10 + .../design/[screenId]/navigation/index.svelte | 2 +- 7 files changed, 351 insertions(+), 34 deletions(-) create mode 100644 packages/builder/src/components/design/Pane.svelte create mode 100644 packages/builder/src/components/design/RightPanel.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel.svelte create mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/CustomizePane.svelte create mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/SettingsPane.svelte create mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/index.svelte diff --git a/packages/builder/src/components/design/Pane.svelte b/packages/builder/src/components/design/Pane.svelte new file mode 100644 index 0000000000..88b6ea1c05 --- /dev/null +++ b/packages/builder/src/components/design/Pane.svelte @@ -0,0 +1,21 @@ + + +{#if $paneStore} +
+ +
+{/if} + + diff --git a/packages/builder/src/components/design/RightPanel.svelte b/packages/builder/src/components/design/RightPanel.svelte new file mode 100644 index 0000000000..f9075600f9 --- /dev/null +++ b/packages/builder/src/components/design/RightPanel.svelte @@ -0,0 +1,112 @@ + + +
+
+
+ +
+ {title} +
+
+ {#each Object.entries(panes) as [id, pane]} +
+ +
+ {/each} +
+
+ + +
+ + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel.svelte deleted file mode 100644 index 614e1eed80..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel.svelte +++ /dev/null @@ -1,33 +0,0 @@ - - - - - {#if $selectedScreen.layoutId} - - You can't preview your navigation settings using this screen as it uses - a custom layout, which is deprecated - - {/if} - - Your navigation is configured for all the screens within your app. - - - You can hide and show your navigation for each screen in the screen - settings. - - - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/CustomizePane.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/CustomizePane.svelte new file mode 100644 index 0000000000..05108b1736 --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/CustomizePane.svelte @@ -0,0 +1,176 @@ + + + +
+
+ + CHANGES WILL APPLY TO ALL SCREENS +
+ + Your navigation is configured for all the screens within your app. + +
+ +
+
+ +
+ + update("navigation", "Top")} + /> + update("navigation", "Left")} + /> + + + {#if $store.navigation.navigation === "Top"} +
+ +
+ update("sticky", e.detail)} + /> +
+ +
+ update("logoUrl", e.detail)} + updateOnChange={false} + /> + {/if} +
+ +
+ update("hideTitle", !e.detail)} + /> + {#if !$store.navigation.hideTitle} +
+ +
+ update("title", e.detail)} + updateOnChange={false} + /> + {/if} +
+ +
+ update("navBackground", e.detail)} + /> +
+ +
+ update("navTextColor", e.detail)} + /> +
+
+ + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/SettingsPane.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/SettingsPane.svelte new file mode 100644 index 0000000000..d3ce720994 --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/SettingsPane.svelte @@ -0,0 +1,31 @@ + + + +
+ + Show nav on this screen +
+
+ + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/index.svelte new file mode 100644 index 0000000000..6ce5405f93 --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/index.svelte @@ -0,0 +1,10 @@ + + + + + + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/index.svelte index fc2e03d8e8..2331d8b285 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/index.svelte @@ -1,6 +1,6 @@ From d94fe7c2eb880c53cdd57d64020790f73ca46d75 Mon Sep 17 00:00:00 2001 From: Dean Date: Thu, 20 Jul 2023 11:32:48 +0100 Subject: [PATCH 003/138] Moved screen settings/theme into the new rightpanel structure. Refactord the color picker to help with positioning. Removed dead home link --- .../bbui/src/Actions/position_dropdown.js | 3 +- .../bbui/src/ColorPicker/ColorPicker.svelte | 75 +++---- packages/bbui/src/Popover/Popover.svelte | 8 + .../builder/src/components/design/Pane.svelte | 2 +- .../controls/ColumnEditor/CellDrawer.svelte | 2 - .../design/[screenId]/_layout.svelte | 6 - .../ScreenSettingsPanel/GeneralPane.svelte | 198 ++++++++++++++++++ .../ScreenSettingsPanel/ThemePane.svelte | 98 +++++++++ .../ScreenSettingsPanel/index.svelte | 15 ++ .../theme}/AppThemeSelect.svelte | 0 .../theme}/ButtonRoundnessSelect.svelte | 0 .../design/[screenId]/screens/index.svelte | 2 +- .../theme/_components/ThemeInfoPanel.svelte | 12 -- .../_components/ThemeSettingsPanel.svelte | 55 ----- .../design/[screenId]/theme/index.svelte | 7 - .../server/src/api/controllers/application.ts | 7 +- 16 files changed, 354 insertions(+), 136 deletions(-) create mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenSettingsPanel/GeneralPane.svelte create mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenSettingsPanel/ThemePane.svelte create mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenSettingsPanel/index.svelte rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{theme/_components => screens/_components/ScreenSettingsPanel/theme}/AppThemeSelect.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{theme/_components => screens/_components/ScreenSettingsPanel/theme}/ButtonRoundnessSelect.svelte (100%) delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/_components/ThemeInfoPanel.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/_components/ThemeSettingsPanel.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/index.svelte diff --git a/packages/bbui/src/Actions/position_dropdown.js b/packages/bbui/src/Actions/position_dropdown.js index 01555446d9..d73b3b4d6a 100644 --- a/packages/bbui/src/Actions/position_dropdown.js +++ b/packages/bbui/src/Actions/position_dropdown.js @@ -32,11 +32,10 @@ export default function positionDropdown(element, opts) { left: null, top: null, } - // Determine vertical styles if (align === "right-outside") { styles.top = anchorBounds.top - } else if (window.innerHeight - anchorBounds.bottom < 100) { + } else if (window.innerHeight - anchorBounds.bottom < (maxHeight || 100)) { styles.top = anchorBounds.top - elementBounds.height - offset styles.maxHeight = maxHeight || 240 } else { diff --git a/packages/bbui/src/ColorPicker/ColorPicker.svelte b/packages/bbui/src/ColorPicker/ColorPicker.svelte index 9a70134fb6..2ba5309860 100644 --- a/packages/bbui/src/ColorPicker/ColorPicker.svelte +++ b/packages/bbui/src/ColorPicker/ColorPicker.svelte @@ -1,8 +1,8 @@ -
-
(open = true)}> -
-
- {#if open} -
+
{ + dropdown.toggle() + }} +> +
+
+ + + +
{#each categories as category}
{category.label}
@@ -187,8 +184,8 @@
- {/if} -
+ + diff --git a/packages/builder/src/components/design/settings/controls/ColumnEditor/CellDrawer.svelte b/packages/builder/src/components/design/settings/controls/ColumnEditor/CellDrawer.svelte index a03d22386d..8e3079101a 100644 --- a/packages/builder/src/components/design/settings/controls/ColumnEditor/CellDrawer.svelte +++ b/packages/builder/src/components/design/settings/controls/ColumnEditor/CellDrawer.svelte @@ -42,7 +42,6 @@ (column.background = e.detail)} - alignRight spectrumTheme={$store.theme} /> @@ -51,7 +50,6 @@ (column.color = e.detail)} - alignRight spectrumTheme={$store.theme} /> diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte index 8bc0dcc3e5..72d959c18b 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte @@ -38,12 +38,6 @@ active={$isActive("./components")} on:click={() => $goto("./components")} /> - $goto("./theme")} - /> + + + + + {#if $selectedScreen.layoutId} + + This screen uses a custom layout, which is deprecated + + {/if} + + {#each screenSettings as setting (setting.key)} + setScreenSetting(setting, val)} + props={{ ...setting.props, error: errors[setting.key] }} + {bindings} + /> + {/each} + + + + + + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenSettingsPanel/ThemePane.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenSettingsPanel/ThemePane.svelte new file mode 100644 index 0000000000..2e59ad5f7d --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenSettingsPanel/ThemePane.svelte @@ -0,0 +1,98 @@ + + + +
+
+ + CHANGES WILL APPLY TO ALL SCREENS +
+ + Your navigation is configured for all the screens within your app. + +
+ + + + + + + update("buttonBorderRadius", e.detail)} + /> + + update("primaryColor", val)} + props={{ + spectrumTheme: $store.theme, + }} + /> + update("primaryColorHover", val)} + props={{ + spectrumTheme: $store.theme, + }} + /> + +
+ + + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenSettingsPanel/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenSettingsPanel/index.svelte new file mode 100644 index 0000000000..554527ca4a --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenSettingsPanel/index.svelte @@ -0,0 +1,15 @@ + + + + + + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/_components/AppThemeSelect.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenSettingsPanel/theme/AppThemeSelect.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/_components/AppThemeSelect.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenSettingsPanel/theme/AppThemeSelect.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/_components/ButtonRoundnessSelect.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenSettingsPanel/theme/ButtonRoundnessSelect.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/_components/ButtonRoundnessSelect.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenSettingsPanel/theme/ButtonRoundnessSelect.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/index.svelte index 6236721e1a..77019abebf 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/index.svelte @@ -1,7 +1,7 @@ diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/_components/ThemeInfoPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/_components/ThemeInfoPanel.svelte deleted file mode 100644 index c3325852c8..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/_components/ThemeInfoPanel.svelte +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - Your theme is set across all the screens within your app. - - - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/_components/ThemeSettingsPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/_components/ThemeSettingsPanel.svelte deleted file mode 100644 index 1c86a51f67..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/_components/ThemeSettingsPanel.svelte +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - update("buttonBorderRadius", e.detail)} - /> - - - - update("primaryColor", e.detail)} - /> - - - - update("primaryColorHover", e.detail)} - /> - - - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/index.svelte deleted file mode 100644 index 013257d8e1..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/index.svelte +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/packages/server/src/api/controllers/application.ts b/packages/server/src/api/controllers/application.ts index c068a422b0..6f9acb3efe 100644 --- a/packages/server/src/api/controllers/application.ts +++ b/packages/server/src/api/controllers/application.ts @@ -298,12 +298,7 @@ async function performAppCreate(ctx: UserCtx) { title: name, navWidth: "Large", navBackground: "var(--spectrum-global-color-gray-100)", - links: [ - { - url: "/home", - text: "Home", - }, - ], + links: [], }, theme: "spectrum--light", customTheme: { From a2e12a693c046e9ba9c89198e8c2f85dd4c9f5a1 Mon Sep 17 00:00:00 2001 From: Dean Date: Thu, 20 Jul 2023 12:16:59 +0100 Subject: [PATCH 004/138] Corrected theme info copy --- .../screens/_components/ScreenSettingsPanel/ThemePane.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenSettingsPanel/ThemePane.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenSettingsPanel/ThemePane.svelte index 2e59ad5f7d..20d5054648 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenSettingsPanel/ThemePane.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenSettingsPanel/ThemePane.svelte @@ -38,7 +38,7 @@ CHANGES WILL APPLY TO ALL SCREENS
- Your navigation is configured for all the screens within your app. + Your theme is configured for all the screens within your app.
From a2667c6d72fdd6b2a6774d6cafc77926ea394a68 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 4 Aug 2023 15:43:02 +0100 Subject: [PATCH 005/138] Removing the ability to set roles, builder and admin structure through basic public API. --- .../api/controllers/public/applications.ts | 18 ++++---- .../src/api/controllers/public/queries.ts | 6 ++- .../server/src/api/controllers/public/rows.ts | 13 +++--- .../src/api/controllers/public/tables.ts | 13 +++--- .../src/api/controllers/public/users.ts | 44 ++++++++++++------- packages/server/src/utilities/users.ts | 17 ++----- 6 files changed, 60 insertions(+), 51 deletions(-) diff --git a/packages/server/src/api/controllers/public/applications.ts b/packages/server/src/api/controllers/public/applications.ts index c4041bedcf..fd72db95d3 100644 --- a/packages/server/src/api/controllers/public/applications.ts +++ b/packages/server/src/api/controllers/public/applications.ts @@ -3,6 +3,8 @@ import { search as stringSearch, addRev } from "./utils" import * as controller from "../application" import * as deployController from "../deploy" import { Application } from "../../../definitions/common" +import { UserCtx } from "@budibase/types" +import { Next } from "koa" function fixAppID(app: Application, params: any) { if (!params) { @@ -14,7 +16,7 @@ function fixAppID(app: Application, params: any) { return app } -async function setResponseApp(ctx: any) { +async function setResponseApp(ctx: UserCtx) { const appId = ctx.body?.appId if (appId && (!ctx.params || !ctx.params.appId)) { ctx.params = { appId } @@ -28,14 +30,14 @@ async function setResponseApp(ctx: any) { } } -export async function search(ctx: any, next: any) { +export async function search(ctx: UserCtx, next: Next) { const { name } = ctx.request.body const apps = await dbCore.getAllApps({ all: true }) ctx.body = stringSearch(apps, name) await next() } -export async function create(ctx: any, next: any) { +export async function create(ctx: UserCtx, next: Next) { if (!ctx.request.body || !ctx.request.body.useTemplate) { ctx.request.body = { useTemplate: false, @@ -47,14 +49,14 @@ export async function create(ctx: any, next: any) { await next() } -export async function read(ctx: any, next: any) { +export async function read(ctx: UserCtx, next: Next) { await context.doInAppContext(ctx.params.appId, async () => { await setResponseApp(ctx) await next() }) } -export async function update(ctx: any, next: any) { +export async function update(ctx: UserCtx, next: Next) { ctx.request.body = await addRev(fixAppID(ctx.request.body, ctx.params)) await context.doInAppContext(ctx.params.appId, async () => { await controller.update(ctx) @@ -63,7 +65,7 @@ export async function update(ctx: any, next: any) { }) } -export async function destroy(ctx: any, next: any) { +export async function destroy(ctx: UserCtx, next: Next) { await context.doInAppContext(ctx.params.appId, async () => { // get the app before deleting it await setResponseApp(ctx) @@ -75,14 +77,14 @@ export async function destroy(ctx: any, next: any) { }) } -export async function unpublish(ctx: any, next: any) { +export async function unpublish(ctx: UserCtx, next: Next) { await context.doInAppContext(ctx.params.appId, async () => { await controller.unpublish(ctx) await next() }) } -export async function publish(ctx: any, next: any) { +export async function publish(ctx: UserCtx, next: Next) { await context.doInAppContext(ctx.params.appId, async () => { await deployController.publishApp(ctx) await next() diff --git a/packages/server/src/api/controllers/public/queries.ts b/packages/server/src/api/controllers/public/queries.ts index 57ec608379..3cb1ab3812 100644 --- a/packages/server/src/api/controllers/public/queries.ts +++ b/packages/server/src/api/controllers/public/queries.ts @@ -1,14 +1,16 @@ import { search as stringSearch } from "./utils" import * as queryController from "../query" +import { UserCtx } from "@budibase/types" +import { Next } from "koa" -export async function search(ctx: any, next: any) { +export async function search(ctx: UserCtx, next: Next) { await queryController.fetch(ctx) const { name } = ctx.request.body ctx.body = stringSearch(ctx.body, name) await next() } -export async function execute(ctx: any, next: any) { +export async function execute(ctx: UserCtx, next: Next) { // don't wrap this, already returns "data" await queryController.executeV2(ctx) await next() diff --git a/packages/server/src/api/controllers/public/rows.ts b/packages/server/src/api/controllers/public/rows.ts index 39cf85a2a3..16403b06c9 100644 --- a/packages/server/src/api/controllers/public/rows.ts +++ b/packages/server/src/api/controllers/public/rows.ts @@ -1,7 +1,8 @@ import * as rowController from "../row" import { addRev } from "./utils" -import { Row } from "@budibase/types" +import { Row, UserCtx } from "@budibase/types" import { convertBookmark } from "../../../utilities" +import { Next } from "koa" // makes sure that the user doesn't need to pass in the type, tableId or _id params for // the call to be correct @@ -21,7 +22,7 @@ export function fixRow(row: Row, params: any) { return row } -export async function search(ctx: any, next: any) { +export async function search(ctx: UserCtx, next: Next) { let { sort, paginate, bookmark, limit, query } = ctx.request.body // update the body to the correct format of the internal search if (!sort) { @@ -40,25 +41,25 @@ export async function search(ctx: any, next: any) { await next() } -export async function create(ctx: any, next: any) { +export async function create(ctx: UserCtx, next: Next) { ctx.request.body = fixRow(ctx.request.body, ctx.params) await rowController.save(ctx) await next() } -export async function read(ctx: any, next: any) { +export async function read(ctx: UserCtx, next: Next) { await rowController.fetchEnrichedRow(ctx) await next() } -export async function update(ctx: any, next: any) { +export async function update(ctx: UserCtx, next: Next) { const { tableId } = ctx.params ctx.request.body = await addRev(fixRow(ctx.request.body, ctx.params), tableId) await rowController.save(ctx) await next() } -export async function destroy(ctx: any, next: any) { +export async function destroy(ctx: UserCtx, next: Next) { const { tableId } = ctx.params // set the body as expected, with the _id and _rev fields ctx.request.body = await addRev( diff --git a/packages/server/src/api/controllers/public/tables.ts b/packages/server/src/api/controllers/public/tables.ts index a346a750da..7486172fa3 100644 --- a/packages/server/src/api/controllers/public/tables.ts +++ b/packages/server/src/api/controllers/public/tables.ts @@ -1,6 +1,7 @@ import { search as stringSearch, addRev } from "./utils" import * as controller from "../table" -import { Table } from "@budibase/types" +import { Table, UserCtx } from "@budibase/types" +import { Next } from "koa" function fixTable(table: Table, params: any) { if (!params || !table) { @@ -15,24 +16,24 @@ function fixTable(table: Table, params: any) { return table } -export async function search(ctx: any, next: any) { +export async function search(ctx: UserCtx, next: Next) { const { name } = ctx.request.body await controller.fetch(ctx) ctx.body = stringSearch(ctx.body, name) await next() } -export async function create(ctx: any, next: any) { +export async function create(ctx: UserCtx, next: Next) { await controller.save(ctx) await next() } -export async function read(ctx: any, next: any) { +export async function read(ctx: UserCtx, next: Next) { await controller.find(ctx) await next() } -export async function update(ctx: any, next: any) { +export async function update(ctx: UserCtx, next: Next) { ctx.request.body = await addRev( fixTable(ctx.request.body, ctx.params), ctx.params.tableId @@ -41,7 +42,7 @@ export async function update(ctx: any, next: any) { await next() } -export async function destroy(ctx: any, next: any) { +export async function destroy(ctx: UserCtx, next: Next) { await controller.destroy(ctx) ctx.body = ctx.table await next() diff --git a/packages/server/src/api/controllers/public/users.ts b/packages/server/src/api/controllers/public/users.ts index 7192077d04..7aaf520dc4 100644 --- a/packages/server/src/api/controllers/public/users.ts +++ b/packages/server/src/api/controllers/public/users.ts @@ -7,16 +7,32 @@ import { import { publicApiUserFix } from "../../../utilities/users" import { db as dbCore } from "@budibase/backend-core" import { search as stringSearch } from "./utils" -import { BBContext, User } from "@budibase/types" +import { UserCtx, User } from "@budibase/types" +import { Next } from "koa" -function isLoggedInUser(ctx: BBContext, user: User) { +function removeRoles(ctx: UserCtx, oldUser?: User) { + const user = ctx.request.body + if (user.builder) { + user.builder = oldUser?.builder || undefined + } + if (user.admin) { + user.admin = oldUser?.admin || undefined + } + if (user.roles) { + user.roles = oldUser?.roles || {} + } + ctx.request.body = user + return ctx +} + +function isLoggedInUser(ctx: UserCtx, user: User) { const loggedInId = ctx.user?._id const globalUserId = dbCore.getGlobalIDFromUserMetadataID(loggedInId!) // check both just incase return globalUserId === user._id || loggedInId === user._id } -function getUser(ctx: BBContext, userId?: string) { +function getUser(ctx: UserCtx, userId?: string) { if (userId) { ctx.params = { userId } } else if (!ctx.params?.userId) { @@ -25,42 +41,38 @@ function getUser(ctx: BBContext, userId?: string) { return readGlobalUser(ctx) } -export async function search(ctx: BBContext, next: any) { +export async function search(ctx: UserCtx, next: Next) { const { name } = ctx.request.body const users = await allGlobalUsers(ctx) ctx.body = stringSearch(users, name, "email") await next() } -export async function create(ctx: BBContext, next: any) { - const response = await saveGlobalUser(publicApiUserFix(ctx)) +export async function create(ctx: UserCtx, next: Next) { + ctx = publicApiUserFix(removeRoles(ctx)) + const response = await saveGlobalUser(ctx) ctx.body = await getUser(ctx, response._id) await next() } -export async function read(ctx: BBContext, next: any) { +export async function read(ctx: UserCtx, next: Next) { ctx.body = await readGlobalUser(ctx) await next() } -export async function update(ctx: BBContext, next: any) { +export async function update(ctx: UserCtx, next: Next) { const user = await readGlobalUser(ctx) ctx.request.body = { ...ctx.request.body, _rev: user._rev, } - // disallow updating your own role - always overwrite with DB roles - if (isLoggedInUser(ctx, user)) { - ctx.request.body.builder = user.builder - ctx.request.body.admin = user.admin - ctx.request.body.roles = user.roles - } - const response = await saveGlobalUser(publicApiUserFix(ctx)) + ctx = publicApiUserFix(removeRoles(ctx, user)) + const response = await saveGlobalUser(ctx) ctx.body = await getUser(ctx, response._id) await next() } -export async function destroy(ctx: BBContext, next: any) { +export async function destroy(ctx: UserCtx, next: Next) { const user = await getUser(ctx) // disallow deleting yourself if (isLoggedInUser(ctx, user)) { diff --git a/packages/server/src/utilities/users.ts b/packages/server/src/utilities/users.ts index 1498a79719..f841ec3646 100644 --- a/packages/server/src/utilities/users.ts +++ b/packages/server/src/utilities/users.ts @@ -1,9 +1,9 @@ import { InternalTables } from "../db/utils" import { getGlobalUser } from "./global" -import { context, db as dbCore, roles } from "@budibase/backend-core" -import { BBContext } from "@budibase/types" +import { context, roles } from "@budibase/backend-core" +import { UserCtx } from "@budibase/types" -export async function getFullUser(ctx: BBContext, userId: string) { +export async function getFullUser(ctx: UserCtx, userId: string) { const global = await getGlobalUser(userId) let metadata: any = {} @@ -29,21 +29,12 @@ export async function getFullUser(ctx: BBContext, userId: string) { } } -export function publicApiUserFix(ctx: BBContext) { +export function publicApiUserFix(ctx: UserCtx) { if (!ctx.request.body) { return ctx } if (!ctx.request.body._id && ctx.params.userId) { ctx.request.body._id = ctx.params.userId } - if (!ctx.request.body.roles) { - ctx.request.body.roles = {} - } else { - const newRoles: { [key: string]: any } = {} - for (let [appId, role] of Object.entries(ctx.request.body.roles)) { - newRoles[dbCore.getProdAppID(appId)] = role - } - ctx.request.body.roles = newRoles - } return ctx } From ec761c238712d4ac04cebbc0763caad596a74ad9 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 4 Aug 2023 18:01:45 +0100 Subject: [PATCH 006/138] Building out public API for role assignment and un-assignment - need to flesh out pro component. --- packages/server/specs/openapi.json | 275 ++++++++++++------ packages/server/specs/openapi.yaml | 195 ++++++++----- packages/server/specs/resources/index.ts | 2 + packages/server/specs/resources/roles.ts | 65 +++++ packages/server/specs/resources/user.ts | 32 -- .../src/api/controllers/public/roles.ts | 15 + .../server/src/api/routes/public/roles.ts | 54 ++++ packages/server/src/definitions/openapi.ts | 133 ++++++--- 8 files changed, 545 insertions(+), 226 deletions(-) create mode 100644 packages/server/specs/resources/roles.ts create mode 100644 packages/server/src/api/controllers/public/roles.ts create mode 100644 packages/server/src/api/routes/public/roles.ts diff --git a/packages/server/specs/openapi.json b/packages/server/specs/openapi.json index d97b09568c..1071a39c29 100644 --- a/packages/server/specs/openapi.json +++ b/packages/server/specs/openapi.json @@ -1519,34 +1519,6 @@ "forceResetPassword": { "description": "If set to true forces the user to reset their password on first login.", "type": "boolean" - }, - "builder": { - "description": "Describes if the user is a builder user or not.", - "type": "object", - "properties": { - "global": { - "description": "If set to true the user will be able to build any app in the system.", - "type": "boolean" - } - } - }, - "admin": { - "description": "Describes if the user is an admin user or not.", - "type": "object", - "properties": { - "global": { - "description": "If set to true the user will be able to administrate the system.", - "type": "boolean" - } - } - }, - "roles": { - "description": "Contains the roles of the user per app (assuming they are not a builder user).", - "type": "object", - "additionalProperties": { - "type": "string", - "description": "A map of app ID (production app ID, minus the _dev component) to a role ID, e.g. ADMIN." - } } }, "required": [ @@ -1587,34 +1559,6 @@ "description": "If set to true forces the user to reset their password on first login.", "type": "boolean" }, - "builder": { - "description": "Describes if the user is a builder user or not.", - "type": "object", - "properties": { - "global": { - "description": "If set to true the user will be able to build any app in the system.", - "type": "boolean" - } - } - }, - "admin": { - "description": "Describes if the user is an admin user or not.", - "type": "object", - "properties": { - "global": { - "description": "If set to true the user will be able to administrate the system.", - "type": "boolean" - } - } - }, - "roles": { - "description": "Contains the roles of the user per app (assuming they are not a builder user).", - "type": "object", - "additionalProperties": { - "type": "string", - "description": "A map of app ID (production app ID, minus the _dev component) to a role ID, e.g. ADMIN." - } - }, "_id": { "description": "The ID of the user.", "type": "string" @@ -1666,34 +1610,6 @@ "description": "If set to true forces the user to reset their password on first login.", "type": "boolean" }, - "builder": { - "description": "Describes if the user is a builder user or not.", - "type": "object", - "properties": { - "global": { - "description": "If set to true the user will be able to build any app in the system.", - "type": "boolean" - } - } - }, - "admin": { - "description": "Describes if the user is an admin user or not.", - "type": "object", - "properties": { - "global": { - "description": "If set to true the user will be able to administrate the system.", - "type": "boolean" - } - } - }, - "roles": { - "description": "Contains the roles of the user per app (assuming they are not a builder user).", - "type": "object", - "additionalProperties": { - "type": "string", - "description": "A map of app ID (production app ID, minus the _dev component) to a role ID, e.g. ADMIN." - } - }, "_id": { "description": "The ID of the user.", "type": "string" @@ -1833,6 +1749,135 @@ "required": [ "name" ] + }, + "rolesAssign": { + "type": "object", + "properties": { + "builder": { + "type": "object", + "properties": { + "global": { + "type": "boolean" + } + }, + "description": "Add/remove global builder permissions from the list of users.", + "required": [ + "global" + ] + }, + "admin": { + "type": "object", + "properties": { + "global": { + "type": "boolean" + } + }, + "description": "Add/remove global admin permissions from the list of users.", + "required": [ + "global" + ] + }, + "role": { + "type": "object", + "properties": { + "roleId": { + "description": "The role ID, such as BASIC, ADMIN or a custom role ID.", + "type": "string" + }, + "appId": { + "description": "The app that the role relates to.", + "type": "string" + } + }, + "description": "Add/remove a per-app role, such as BASIC, ADMIN etc.", + "required": [ + "roleId", + "appId" + ] + }, + "userIds": { + "description": "The user IDs to be updated to add/remove the specified roles.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "userIds" + ] + }, + "rolesUnAssign": { + "type": "object", + "properties": { + "builder": { + "type": "object", + "properties": { + "global": { + "type": "boolean" + } + }, + "description": "Add/remove global builder permissions from the list of users.", + "required": [ + "global" + ] + }, + "admin": { + "type": "object", + "properties": { + "global": { + "type": "boolean" + } + }, + "description": "Add/remove global admin permissions from the list of users.", + "required": [ + "global" + ] + }, + "role": { + "type": "object", + "properties": { + "roleId": { + "description": "The role ID, such as BASIC, ADMIN or a custom role ID.", + "type": "string" + }, + "appId": { + "description": "The app that the role relates to.", + "type": "string" + } + }, + "description": "Add/remove a per-app role, such as BASIC, ADMIN etc.", + "required": [ + "roleId", + "appId" + ] + }, + "userIds": { + "description": "The user IDs to be updated to add/remove the specified roles.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "userIds" + ] + }, + "rolesOutput": { + "type": "object", + "properties": { + "userIds": { + "description": "The updated users' IDs", + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "userIds" + ] } } }, @@ -2186,6 +2231,68 @@ } } }, + "/roles/assign": { + "post": { + "operationId": "roleAssign", + "summary": "Assign a role to a list of users", + "tags": [ + "roles" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/rolesAssign" + } + } + } + }, + "responses": { + "200": { + "description": "Returns a list of updated user IDs", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/rolesOutput" + } + } + } + } + } + } + }, + "/roles/unassign": { + "post": { + "operationId": "roleUnAssign", + "summary": "Un-assign a role from a list of users", + "tags": [ + "roles" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/rolesUnAssign" + } + } + } + }, + "responses": { + "200": { + "description": "Returns a list of updated user IDs", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/rolesOutput" + } + } + } + } + } + } + }, "/tables/{tableId}/rows": { "post": { "operationId": "rowCreate", diff --git a/packages/server/specs/openapi.yaml b/packages/server/specs/openapi.yaml index 86807c9981..aa7b3ddb51 100644 --- a/packages/server/specs/openapi.yaml +++ b/packages/server/specs/openapi.yaml @@ -1296,29 +1296,6 @@ components: description: If set to true forces the user to reset their password on first login. type: boolean - builder: - description: Describes if the user is a builder user or not. - type: object - properties: - global: - description: If set to true the user will be able to build any app in the - system. - type: boolean - admin: - description: Describes if the user is an admin user or not. - type: object - properties: - global: - description: If set to true the user will be able to administrate the system. - type: boolean - roles: - description: Contains the roles of the user per app (assuming they are not a - builder user). - type: object - additionalProperties: - type: string - description: A map of app ID (production app ID, minus the _dev component) to a - role ID, e.g. ADMIN. required: - email - roles @@ -1351,29 +1328,6 @@ components: description: If set to true forces the user to reset their password on first login. type: boolean - builder: - description: Describes if the user is a builder user or not. - type: object - properties: - global: - description: If set to true the user will be able to build any app in the - system. - type: boolean - admin: - description: Describes if the user is an admin user or not. - type: object - properties: - global: - description: If set to true the user will be able to administrate the system. - type: boolean - roles: - description: Contains the roles of the user per app (assuming they are not a - builder user). - type: object - additionalProperties: - type: string - description: A map of app ID (production app ID, minus the _dev component) to a - role ID, e.g. ADMIN. _id: description: The ID of the user. type: string @@ -1414,29 +1368,6 @@ components: description: If set to true forces the user to reset their password on first login. type: boolean - builder: - description: Describes if the user is a builder user or not. - type: object - properties: - global: - description: If set to true the user will be able to build any app in the - system. - type: boolean - admin: - description: Describes if the user is an admin user or not. - type: object - properties: - global: - description: If set to true the user will be able to administrate the system. - type: boolean - roles: - description: Contains the roles of the user per app (assuming they are not a - builder user). - type: object - additionalProperties: - type: string - description: A map of app ID (production app ID, minus the _dev component) to a - role ID, e.g. ADMIN. _id: description: The ID of the user. type: string @@ -1547,6 +1478,94 @@ components: insensitive starts with match. required: - name + rolesAssign: + type: object + properties: + builder: + type: object + properties: + global: + type: boolean + description: Add/remove global builder permissions from the list of users. + required: + - global + admin: + type: object + properties: + global: + type: boolean + description: Add/remove global admin permissions from the list of users. + required: + - global + role: + type: object + properties: + roleId: + description: The role ID, such as BASIC, ADMIN or a custom role ID. + type: string + appId: + description: The app that the role relates to. + type: string + description: Add/remove a per-app role, such as BASIC, ADMIN etc. + required: + - roleId + - appId + userIds: + description: The user IDs to be updated to add/remove the specified roles. + type: array + items: + type: string + required: + - userIds + rolesUnAssign: + type: object + properties: + builder: + type: object + properties: + global: + type: boolean + description: Add/remove global builder permissions from the list of users. + required: + - global + admin: + type: object + properties: + global: + type: boolean + description: Add/remove global admin permissions from the list of users. + required: + - global + role: + type: object + properties: + roleId: + description: The role ID, such as BASIC, ADMIN or a custom role ID. + type: string + appId: + description: The app that the role relates to. + type: string + description: Add/remove a per-app role, such as BASIC, ADMIN etc. + required: + - roleId + - appId + userIds: + description: The user IDs to be updated to add/remove the specified roles. + type: array + items: + type: string + required: + - userIds + rolesOutput: + type: object + properties: + userIds: + description: The updated users' IDs + type: array + items: + type: string + required: + - userIds security: - ApiKeyAuth: [] paths: @@ -1757,6 +1776,44 @@ paths: examples: queries: $ref: "#/components/examples/queries" + /roles/assign: + post: + operationId: roleAssign + summary: Assign a role to a list of users + tags: + - roles + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/rolesAssign" + responses: + "200": + description: Returns a list of updated user IDs + content: + application/json: + schema: + $ref: "#/components/schemas/rolesOutput" + /roles/unassign: + post: + operationId: roleUnAssign + summary: Un-assign a role from a list of users + tags: + - roles + requestBody: + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/rolesUnAssign" + responses: + "200": + description: Returns a list of updated user IDs + content: + application/json: + schema: + $ref: "#/components/schemas/rolesOutput" "/tables/{tableId}/rows": post: operationId: rowCreate diff --git a/packages/server/specs/resources/index.ts b/packages/server/specs/resources/index.ts index 6b8a1aa437..c06148b7de 100644 --- a/packages/server/specs/resources/index.ts +++ b/packages/server/specs/resources/index.ts @@ -5,6 +5,7 @@ import query from "./query" import user from "./user" import metrics from "./metrics" import misc from "./misc" +import roles from "./roles" export const examples = { ...application.getExamples(), @@ -23,4 +24,5 @@ export const schemas = { ...query.getSchemas(), ...user.getSchemas(), ...misc.getSchemas(), + ...roles.getSchemas(), } diff --git a/packages/server/specs/resources/roles.ts b/packages/server/specs/resources/roles.ts new file mode 100644 index 0000000000..02254261be --- /dev/null +++ b/packages/server/specs/resources/roles.ts @@ -0,0 +1,65 @@ +import { object } from "./utils" +import Resource from "./utils/Resource" + +const roleSchema = object( + { + builder: object( + { + global: { + type: "boolean", + }, + }, + { + description: + "Add/remove global builder permissions from the list of users.", + } + ), + admin: object( + { + global: { + type: "boolean", + }, + }, + { + description: + "Add/remove global admin permissions from the list of users.", + } + ), + role: object( + { + roleId: { + description: "The role ID, such as BASIC, ADMIN or a custom role ID.", + type: "string", + }, + appId: { + description: "The app that the role relates to.", + type: "string", + }, + }, + { description: "Add/remove a per-app role, such as BASIC, ADMIN etc." } + ), + userIds: { + description: + "The user IDs to be updated to add/remove the specified roles.", + type: "array", + items: { + type: "string", + }, + }, + }, + { required: ["userIds"] } +) + +export default new Resource().setSchemas({ + rolesAssign: roleSchema, + rolesUnAssign: roleSchema, + rolesOutput: object({ + userIds: { + description: "The updated users' IDs", + type: "array", + items: { + type: "string", + }, + }, + }), +}) diff --git a/packages/server/specs/resources/user.ts b/packages/server/specs/resources/user.ts index a7b9f1ddb9..9ec5388672 100644 --- a/packages/server/specs/resources/user.ts +++ b/packages/server/specs/resources/user.ts @@ -57,38 +57,6 @@ const userSchema = object( "If set to true forces the user to reset their password on first login.", type: "boolean", }, - builder: { - description: "Describes if the user is a builder user or not.", - type: "object", - properties: { - global: { - description: - "If set to true the user will be able to build any app in the system.", - type: "boolean", - }, - }, - }, - admin: { - description: "Describes if the user is an admin user or not.", - type: "object", - properties: { - global: { - description: - "If set to true the user will be able to administrate the system.", - type: "boolean", - }, - }, - }, - roles: { - description: - "Contains the roles of the user per app (assuming they are not a builder user).", - type: "object", - additionalProperties: { - type: "string", - description: - "A map of app ID (production app ID, minus the _dev component) to a role ID, e.g. ADMIN.", - }, - }, }, { required: ["email", "roles"] } ) diff --git a/packages/server/src/api/controllers/public/roles.ts b/packages/server/src/api/controllers/public/roles.ts new file mode 100644 index 0000000000..3b70094ae1 --- /dev/null +++ b/packages/server/src/api/controllers/public/roles.ts @@ -0,0 +1,15 @@ +import { UserCtx } from "@budibase/types" +import { Next } from "koa" + +async function assign(ctx: UserCtx, next: Next) { + ctx.body = { message: "roles assigned" } +} + +async function unAssign(ctx: UserCtx, next: Next) { + ctx.body = { message: "roles un-assigned" } +} + +export default { + assign, + unAssign, +} diff --git a/packages/server/src/api/routes/public/roles.ts b/packages/server/src/api/routes/public/roles.ts new file mode 100644 index 0000000000..2332a0ffd0 --- /dev/null +++ b/packages/server/src/api/routes/public/roles.ts @@ -0,0 +1,54 @@ +import controller from "../../controllers/public/roles" +import Endpoint from "./utils/Endpoint" + +const write = [] + +/** + * @openapi + * /roles/assign: + * post: + * operationId: roleAssign + * summary: Assign a role to a list of users + * tags: + * - roles + * requestBody: + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/rolesAssign' + * responses: + * 200: + * description: Returns a list of updated user IDs + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/rolesOutput' + */ +write.push(new Endpoint("post", "/roles/assign", controller.assign)) + +/** + * @openapi + * /roles/unassign: + * post: + * operationId: roleUnAssign + * summary: Un-assign a role from a list of users + * tags: + * - roles + * requestBody: + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/rolesUnAssign' + * responses: + * 200: + * description: Returns a list of updated user IDs + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/rolesOutput' + */ +write.push(new Endpoint("post", "/roles/unassign", controller.unAssign)) + +export default { write, read: [] } diff --git a/packages/server/src/definitions/openapi.ts b/packages/server/src/definitions/openapi.ts index 5ca4990647..ee078d0821 100644 --- a/packages/server/src/definitions/openapi.ts +++ b/packages/server/src/definitions/openapi.ts @@ -34,6 +34,12 @@ export interface paths { /** Based on query properties (currently only name) search for queries. */ post: operations["querySearch"]; }; + "/roles/assign": { + post: operations["roleAssign"]; + }; + "/roles/unassign": { + post: operations["roleUnAssign"]; + }; "/tables/{tableId}/rows": { /** Creates a row within the specified table. */ post: operations["rowCreate"]; @@ -256,7 +262,8 @@ export interface components { | "auto" | "json" | "internal" - | "barcodeqr"; + | "barcodeqr" + | "bigint"; /** @description A constraint can be applied to the column which will be validated against when a row is saved. */ constraints?: { /** @enum {string} */ @@ -362,7 +369,8 @@ export interface components { | "auto" | "json" | "internal" - | "barcodeqr"; + | "barcodeqr" + | "bigint"; /** @description A constraint can be applied to the column which will be validated against when a row is saved. */ constraints?: { /** @enum {string} */ @@ -470,7 +478,8 @@ export interface components { | "auto" | "json" | "internal" - | "barcodeqr"; + | "barcodeqr" + | "bigint"; /** @description A constraint can be applied to the column which will be validated against when a row is saved. */ constraints?: { /** @enum {string} */ @@ -577,18 +586,8 @@ export interface components { lastName?: string; /** @description If set to true forces the user to reset their password on first login. */ forceResetPassword?: boolean; - /** @description Describes if the user is a builder user or not. */ - builder?: { - /** @description If set to true the user will be able to build any app in the system. */ - global?: boolean; - }; - /** @description Describes if the user is an admin user or not. */ - admin?: { - /** @description If set to true the user will be able to administrate the system. */ - global?: boolean; - }; - /** @description Contains the roles of the user per app (assuming they are not a builder user). */ - roles: { [key: string]: string }; + } & { + roles: unknown; }; userOutput: { data: { @@ -607,24 +606,14 @@ export interface components { lastName?: string; /** @description If set to true forces the user to reset their password on first login. */ forceResetPassword?: boolean; - /** @description Describes if the user is a builder user or not. */ - builder?: { - /** @description If set to true the user will be able to build any app in the system. */ - global?: boolean; - }; - /** @description Describes if the user is an admin user or not. */ - admin?: { - /** @description If set to true the user will be able to administrate the system. */ - global?: boolean; - }; - /** @description Contains the roles of the user per app (assuming they are not a builder user). */ - roles: { [key: string]: string }; /** @description The ID of the user. */ _id: string; + } & { + roles: unknown; }; }; userSearch: { - data: { + data: ({ /** @description The email address of the user, this must be unique. */ email: string; /** @description The password of the user if using password based login - this will never be returned. This can be left out of subsequent requests (updates) and will be enriched back into the user structure. */ @@ -640,21 +629,11 @@ export interface components { lastName?: string; /** @description If set to true forces the user to reset their password on first login. */ forceResetPassword?: boolean; - /** @description Describes if the user is a builder user or not. */ - builder?: { - /** @description If set to true the user will be able to build any app in the system. */ - global?: boolean; - }; - /** @description Describes if the user is an admin user or not. */ - admin?: { - /** @description If set to true the user will be able to administrate the system. */ - global?: boolean; - }; - /** @description Contains the roles of the user per app (assuming they are not a builder user). */ - roles: { [key: string]: string }; /** @description The ID of the user. */ _id: string; - }[]; + } & { + roles: unknown; + })[]; }; rowSearch: { query: { @@ -712,6 +691,48 @@ export interface components { /** @description The name to be used when searching - this will be used in a case insensitive starts with match. */ name: string; }; + rolesAssign: { + /** @description Add/remove global builder permissions from the list of users. */ + builder?: { + global: boolean; + }; + /** @description Add/remove global admin permissions from the list of users. */ + admin?: { + global: boolean; + }; + /** @description Add/remove a per-app role, such as BASIC, ADMIN etc. */ + role?: { + /** @description The role ID, such as BASIC, ADMIN or a custom role ID. */ + roleId: string; + /** @description The app that the role relates to. */ + appId: string; + }; + /** @description The user IDs to be updated to add/remove the specified roles. */ + userIds: string[]; + }; + rolesUnAssign: { + /** @description Add/remove global builder permissions from the list of users. */ + builder?: { + global: boolean; + }; + /** @description Add/remove global admin permissions from the list of users. */ + admin?: { + global: boolean; + }; + /** @description Add/remove a per-app role, such as BASIC, ADMIN etc. */ + role?: { + /** @description The role ID, such as BASIC, ADMIN or a custom role ID. */ + roleId: string; + /** @description The app that the role relates to. */ + appId: string; + }; + /** @description The user IDs to be updated to add/remove the specified roles. */ + userIds: string[]; + }; + rolesOutput: { + /** @description The updated users' IDs */ + userIds: string[]; + }; }; parameters: { /** @description The ID of the table which this request is targeting. */ @@ -907,6 +928,36 @@ export interface operations { }; }; }; + roleAssign: { + responses: { + /** Returns a list of updated user IDs */ + 200: { + content: { + "application/json": components["schemas"]["rolesOutput"]; + }; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["rolesAssign"]; + }; + }; + }; + roleUnAssign: { + responses: { + /** Returns a list of updated user IDs */ + 200: { + content: { + "application/json": components["schemas"]["rolesOutput"]; + }; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["rolesUnAssign"]; + }; + }; + }; /** Creates a row within the specified table. */ rowCreate: { parameters: { From d66a020b3cbae9c8f16d6e2b6080e8a1ddc8c0c5 Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 10 Aug 2023 11:48:18 +0300 Subject: [PATCH 007/138] Fix build script with no pro locally --- scripts/build.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/build.js b/scripts/build.js index 2ca41b5f7d..50620d94f4 100755 --- a/scripts/build.js +++ b/scripts/build.js @@ -22,7 +22,10 @@ function runBuild(entry, outfile) { fs.readFileSync(tsconfig, "utf-8") ) - if (!fs.existsSync("../pro/src")) { + if ( + !fs.existsSync("../pro/src") && + tsconfigPathPluginContent.compilerOptions?.paths + ) { // If we don't have pro, we cannot bundle backend-core. // Otherwise, the main context will not be shared between libraries delete tsconfigPathPluginContent.compilerOptions.paths[ From 5b29e879a448ae4b993c9218d6e9d9ef84a6214d Mon Sep 17 00:00:00 2001 From: Adria Navarro Date: Thu, 10 Aug 2023 16:03:37 +0300 Subject: [PATCH 008/138] Fix dev when no pro loaded --- packages/server/package.json | 15 +++++++++++++++ packages/worker/package.json | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/packages/server/package.json b/packages/server/package.json index 7d0d8f5feb..29b8666746 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -179,5 +179,20 @@ }, "optionalDependencies": { "oracledb": "5.3.0" + }, + "nx": { + "targets": { + "dev:builder": { + "dependsOn": [ + { + "comment": "Required for pro usage when submodule not loaded", + "projects": [ + "@budibase/backend-core" + ], + "target": "build" + } + ] + } + } } } diff --git a/packages/worker/package.json b/packages/worker/package.json index a71e9519d9..3b66df264e 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -102,5 +102,20 @@ "tsconfig-paths": "4.0.0", "typescript": "4.7.3", "update-dotenv": "1.1.1" + }, + "nx": { + "targets": { + "dev:builder": { + "dependsOn": [ + { + "comment": "Required for pro usage when submodule not loaded", + "projects": [ + "@budibase/backend-core" + ], + "target": "build" + } + ] + } + } } } From f7c1db5926279cacace49e97d8f7420228dd27ed Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Fri, 11 Aug 2023 11:59:40 +0100 Subject: [PATCH 009/138] focus input when popover opens --- .../DataTable/modals/CreateEditColumn.svelte | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte index 7c3e13f39a..537d34a735 100644 --- a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte +++ b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte @@ -12,7 +12,7 @@ OptionSelectDnD, Layout, } from "@budibase/bbui" - import { createEventDispatcher, getContext } from "svelte" + import { createEventDispatcher, getContext, onMount } from "svelte" import { cloneDeep } from "lodash/fp" import { tables, datasources } from "stores/backend" import { TableNames, UNEDITABLE_USER_FIELDS } from "constants" @@ -47,6 +47,7 @@ export let field + let mounted = false let fieldDefinitions = cloneDeep(FIELDS) let originalName let linkEditDisabled @@ -95,6 +96,7 @@ } else { editableColumn.name = "Column 01" } + focus = true } allowedTypes = getAllowedTypes() } @@ -413,16 +415,24 @@ } return newError } + + onMount(() => { + mounted = true + }) + + $: console.log(editableColumn.name) - - + {/if} - {/if} + autofocus + bind:value={editableColumn.name} + disabled={uneditable || + (linkEditDisabled && editableColumn.type === LINK_TYPE)} + error={errors?.name} + /> + {/if} opt.label} + getOptionValue={opt => opt.value} + on:change={e => (onEmptyFilter = e.detail)} + placeholder={null} + /> + {/if}
diff --git a/packages/server/jest.config.ts b/packages/server/jest.config.ts index f36864f999..21bb92388f 100644 --- a/packages/server/jest.config.ts +++ b/packages/server/jest.config.ts @@ -12,6 +12,7 @@ const baseConfig: Config.InitialProjectOptions = { }, moduleNameMapper: { "@budibase/backend-core/(.*)": "/../backend-core/$1", + "@budibase/shared-core/(.*)": "/../shared-core/$1", "@budibase/backend-core": "/../backend-core/src", "@budibase/shared-core": "/../shared-core/src", "@budibase/types": "/../types/src", diff --git a/packages/server/src/api/controllers/row/external.ts b/packages/server/src/api/controllers/row/external.ts index bc4edbd661..91b0abc772 100644 --- a/packages/server/src/api/controllers/row/external.ts +++ b/packages/server/src/api/controllers/row/external.ts @@ -13,8 +13,10 @@ import { Row, Table, UserCtx, + EmptyFilterOption, } from "@budibase/types" import sdk from "../../../sdk" +import { hasFilters } from "@budibase/shared-core/src/filters" import * as utils from "./utils" export async function handleRequest( @@ -38,6 +40,13 @@ export async function handleRequest( } } + if ( + !hasFilters(opts?.filters) && + opts?.filters?.onEmptyFilter === EmptyFilterOption.RETURN_NONE + ) { + return [] + } + return new ExternalRequest(operation, tableId, opts?.datasource).run( opts || {} ) diff --git a/packages/server/src/automations/steps/queryRows.ts b/packages/server/src/automations/steps/queryRows.ts index 1abb8c6a31..e0680017e7 100644 --- a/packages/server/src/automations/steps/queryRows.ts +++ b/packages/server/src/automations/steps/queryRows.ts @@ -11,6 +11,7 @@ import { AutomationStepInput, AutomationStepSchema, AutomationStepType, + EmptyFilterOption, SearchFilters, Table, } from "@budibase/types" @@ -26,16 +27,6 @@ const SortOrderPretty = { [SortOrder.DESCENDING]: "Descending", } -enum EmptyFilterOption { - RETURN_ALL = "all", - RETURN_NONE = "none", -} - -const EmptyFilterOptionPretty = { - [EmptyFilterOption.RETURN_ALL]: "Return all table rows", - [EmptyFilterOption.RETURN_NONE]: "Return no rows", -} - export const definition: AutomationStepSchema = { description: "Query rows from the database", icon: "Search", @@ -77,12 +68,6 @@ export const definition: AutomationStepSchema = { title: "Limit", customType: AutomationCustomIOType.QUERY_LIMIT, }, - onEmptyFilter: { - pretty: Object.values(EmptyFilterOptionPretty), - enum: Object.values(EmptyFilterOption), - type: AutomationIOType.STRING, - title: "When Filter Empty", - }, }, required: ["tableId"], }, diff --git a/packages/server/src/sdk/app/rows/search/tests/external.spec.ts b/packages/server/src/sdk/app/rows/search/tests/external.spec.ts index b3bddfbc97..9a5c89f20f 100644 --- a/packages/server/src/sdk/app/rows/search/tests/external.spec.ts +++ b/packages/server/src/sdk/app/rows/search/tests/external.spec.ts @@ -2,6 +2,7 @@ import { GenericContainer } from "testcontainers" import { Datasource, + EmptyFilterOption, FieldType, Row, SourceName, @@ -123,6 +124,22 @@ describe.skip("external", () => { }) }) + it("empty filters search returns no data", async () => { + await config.doInContext(config.appId, async () => { + const tableId = config.table!._id! + + const searchParams: SearchParams = { + tableId, + query: { + onEmptyFilter: EmptyFilterOption.RETURN_NONE, + }, + } + const result = await search(searchParams) + + expect(result.rows).toHaveLength(0) + }) + }) + it("querying by fields will always return data attribute columns", async () => { await config.doInContext(config.appId, async () => { const tableId = config.table!._id! diff --git a/packages/shared-core/src/filters.ts b/packages/shared-core/src/filters.ts index 8739db1b40..2cd6fa8c13 100644 --- a/packages/shared-core/src/filters.ts +++ b/packages/shared-core/src/filters.ts @@ -1,11 +1,11 @@ import { Datasource, FieldType, + SortDirection, + SortType, SearchFilter, SearchQuery, SearchQueryFields, - SortDirection, - SortType, } from "@budibase/types" import { OperatorOptions, SqlNumberTypeRangeMap } from "./constants" import { deepGet } from "./helpers" @@ -138,7 +138,8 @@ export const buildLuceneQuery = (filter: SearchFilter[]) => { } if (Array.isArray(filter)) { filter.forEach(expression => { - let { operator, field, type, value, externalType } = expression + let { operator, field, type, value, externalType, onEmptyFilter } = + expression const isHbs = typeof value === "string" && (value.match(HBS_REGEX) || []).length > 0 // Parse all values into correct types @@ -146,6 +147,10 @@ export const buildLuceneQuery = (filter: SearchFilter[]) => { query.allOr = true return } + if (onEmptyFilter) { + query.onEmptyFilter = onEmptyFilter + return + } if ( type === "datetime" && !isHbs && @@ -203,7 +208,7 @@ export const buildLuceneQuery = (filter: SearchFilter[]) => { ) { query.range[field].high = value } - } else if (query[operator]) { + } else if (query[operator] && operator !== "onEmptyFilter") { if (type === "boolean") { // Transform boolean filters to cope with null. // "equals false" needs to be "not equals true" @@ -418,7 +423,7 @@ export const hasFilters = (query?: SearchQuery) => { if (!query) { return false } - const skipped = ["allOr"] + const skipped = ["allOr", "onEmptyFilter"] for (let [key, value] of Object.entries(query)) { if (skipped.includes(key) || typeof value !== "object") { continue diff --git a/packages/types/src/api/web/searchFilter.ts b/packages/types/src/api/web/searchFilter.ts index 1b5948e50c..6980bc117b 100644 --- a/packages/types/src/api/web/searchFilter.ts +++ b/packages/types/src/api/web/searchFilter.ts @@ -1,7 +1,9 @@ import { FieldType } from "../../documents" +import { EmptyFilterOption } from "../../sdk" export type SearchFilter = { operator: keyof SearchQuery + onEmptyFilter?: EmptyFilterOption field: string type?: FieldType value: any @@ -10,6 +12,7 @@ export type SearchFilter = { export type SearchQuery = { allOr?: boolean + onEmptyFilter?: EmptyFilterOption string?: { [key: string]: string } @@ -48,4 +51,4 @@ export type SearchQuery = { } } -export type SearchQueryFields = Omit +export type SearchQueryFields = Omit diff --git a/packages/types/src/sdk/search.ts b/packages/types/src/sdk/search.ts index ae9aec66a2..35fd148c05 100644 --- a/packages/types/src/sdk/search.ts +++ b/packages/types/src/sdk/search.ts @@ -4,6 +4,7 @@ import { SortType } from "../api" export interface SearchFilters { allOr?: boolean + onEmptyFilter?: EmptyFilterOption string?: { [key: string]: string } @@ -99,3 +100,8 @@ export interface SqlQuery { sql: string bindings?: string[] } + +export enum EmptyFilterOption { + RETURN_ALL = "all", + RETURN_NONE = "none", +} From fce22c07512650528d667b3f1214be51c4428c80 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Thu, 17 Aug 2023 12:32:10 +0000 Subject: [PATCH 023/138] Bump version to 2.9.26-alpha.4 --- lerna.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lerna.json b/lerna.json index c23b30da74..b516b7cda2 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.9.26-alpha.3", + "version": "2.9.26-alpha.4", "npmClient": "yarn", "packages": [ "packages/*" From 95b8a4ea10911916b3d8fb1a502aaf293891ecd2 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 17 Aug 2023 16:39:25 +0100 Subject: [PATCH 024/138] Adding feature flagging, the option to only start the automations, or the API, meaning we can split the service if needed. --- packages/server/src/app.ts | 123 ++++-------------- packages/server/src/automations/index.ts | 4 + packages/server/src/automations/utils.ts | 6 +- packages/server/src/environment.ts | 2 + packages/server/src/features.ts | 36 +++++ packages/server/src/koa.ts | 102 +++++++++++++++ packages/server/src/startup.ts | 5 +- .../src/tests/utilities/TestConfiguration.ts | 4 +- packages/worker/src/environment.ts | 2 + packages/worker/src/features.ts | 26 ++++ 10 files changed, 205 insertions(+), 105 deletions(-) create mode 100644 packages/server/src/features.ts create mode 100644 packages/server/src/koa.ts create mode 100644 packages/worker/src/features.ts diff --git a/packages/server/src/app.ts b/packages/server/src/app.ts index d41f908059..6cb122480a 100644 --- a/packages/server/src/app.ts +++ b/packages/server/src/app.ts @@ -1,120 +1,41 @@ +import Sentry from "@sentry/node" + if (process.env.DD_APM_ENABLED) { require("./ddApm") } // need to load environment first import env from "./environment" - -import { ExtendableContext } from "koa" import * as db from "./db" db.init() -import Koa from "koa" -import koaBody from "koa-body" -import http from "http" -import * as api from "./api" -import * as automations from "./automations" -import { Thread } from "./threads" -import * as redis from "./utilities/redis" import { ServiceType } from "@budibase/types" -import { - events, - logging, - middleware, - timers, - env as coreEnv, -} from "@budibase/backend-core" +import { env as coreEnv } from "@budibase/backend-core" coreEnv._set("SERVICE_TYPE", ServiceType.APPS) +import { apiEnabled } from "./features" +import createKoaApp from "./koa" +import Koa from "koa" +import { Server } from "http" import { startup } from "./startup" -const Sentry = require("@sentry/node") -const destroyable = require("server-destroy") -const { userAgent } = require("koa-useragent") -const app = new Koa() +let app: Koa, server: Server -let mbNumber = parseInt(env.HTTP_MB_LIMIT || "10") -if (!mbNumber || isNaN(mbNumber)) { - mbNumber = 10 -} -// set up top level koa middleware -app.use( - koaBody({ - multipart: true, - formLimit: `${mbNumber}mb`, - jsonLimit: `${mbNumber}mb`, - textLimit: `${mbNumber}mb`, - // @ts-ignore - enableTypes: ["json", "form", "text"], - parsedMethods: ["POST", "PUT", "PATCH", "DELETE"], - }) -) - -app.use(middleware.correlation) -app.use(middleware.pino) -app.use(userAgent) - -if (env.isProd()) { - env._set("NODE_ENV", "production") - Sentry.init() - - app.on("error", (err: any, ctx: ExtendableContext) => { - Sentry.withScope(function (scope: any) { - scope.addEventProcessor(function (event: any) { - return Sentry.Handlers.parseRequest(event, ctx.request) - }) - Sentry.captureException(err) - }) - }) -} - -const server = http.createServer(app.callback()) -destroyable(server) - -let shuttingDown = false, - errCode = 0 - -server.on("close", async () => { - // already in process - if (shuttingDown) { - return +async function start() { + if (apiEnabled()) { + const koa = createKoaApp() + app = koa.app + server = koa.server } - shuttingDown = true - console.log("Server Closed") - timers.cleanup() - await automations.shutdown() - await redis.shutdown() - events.shutdown() - await Thread.shutdown() - api.shutdown() - if (!env.isTest()) { - process.exit(errCode) - } -}) - -export default server.listen(env.PORT || 0, async () => { await startup(app, server) -}) - -const shutdown = () => { - server.close() - // @ts-ignore - server.destroy() + if (env.isProd()) { + env._set("NODE_ENV", "production") + Sentry.init() + } } -process.on("uncaughtException", err => { - // @ts-ignore - // don't worry about this error, comes from zlib isn't important - if (err && err["code"] === "ERR_INVALID_CHAR") { - return - } - errCode = -1 - logging.logAlert("Uncaught exception.", err) - shutdown() +start().catch(err => { + console.error(`Failed server startup - ${err.message}`) }) -process.on("SIGTERM", () => { - shutdown() -}) - -process.on("SIGINT", () => { - shutdown() -}) +export function getServer() { + return app +} diff --git a/packages/server/src/automations/index.ts b/packages/server/src/automations/index.ts index 9bbab95a27..4ef3210932 100644 --- a/packages/server/src/automations/index.ts +++ b/packages/server/src/automations/index.ts @@ -2,6 +2,7 @@ import { processEvent } from "./utils" import { automationQueue } from "./bullboard" import { rebootTrigger } from "./triggers" import BullQueue from "bull" +import { automationsEnabled } from "../features" export { automationQueue } from "./bullboard" export { shutdown } from "./bullboard" @@ -12,6 +13,9 @@ export { BUILTIN_ACTION_DEFINITIONS, getActionDefinitions } from "./actions" * This module is built purely to kick off the worker farm and manage the inputs/outputs */ export async function init() { + if (!automationsEnabled()) { + return + } // this promise will not complete const promise = automationQueue.process(async job => { await processEvent(job) diff --git a/packages/server/src/automations/utils.ts b/packages/server/src/automations/utils.ts index 14835820d9..18d2d30f82 100644 --- a/packages/server/src/automations/utils.ts +++ b/packages/server/src/automations/utils.ts @@ -15,9 +15,13 @@ import { WebhookActionType, } from "@budibase/types" import sdk from "../sdk" +import { automationsEnabled } from "../features" const WH_STEP_ID = definitions.WEBHOOK.stepId -const Runner = new Thread(ThreadType.AUTOMATION) +let Runner: Thread +if (automationsEnabled()) { + Runner = new Thread(ThreadType.AUTOMATION) +} function loggingArgs( job: AutomationJob, diff --git a/packages/server/src/environment.ts b/packages/server/src/environment.ts index 2d3b717efd..06fd659911 100644 --- a/packages/server/src/environment.ts +++ b/packages/server/src/environment.ts @@ -38,6 +38,8 @@ function parseIntSafe(number?: string) { } const environment = { + // features + APP_FEATURES: process.env.APP_FEATURES, // important - prefer app port to generic port PORT: process.env.APP_PORT || process.env.PORT, COUCH_DB_URL: process.env.COUCH_DB_URL, diff --git a/packages/server/src/features.ts b/packages/server/src/features.ts new file mode 100644 index 0000000000..0120e48e2a --- /dev/null +++ b/packages/server/src/features.ts @@ -0,0 +1,36 @@ +import env from "./environment" + +enum AppFeature { + API = "api", + AUTOMATIONS = "automations", +} + +const featureList = processFeatureList() + +function processFeatureList() { + const fullList = Object.values(AppFeature) as string[] + let list + if (!env.APP_FEATURES) { + list = fullList + } else { + list = env.APP_FEATURES.split(",") + } + for (let feature of list) { + if (!fullList.includes(feature)) { + throw new Error(`Feature: ${feature} is not an allowed option`) + } + } + return list +} + +export function isFeatureEnabled(feature: AppFeature) { + return featureList.includes(feature) +} + +export function automationsEnabled() { + return featureList.includes(AppFeature.AUTOMATIONS) +} + +export function apiEnabled() { + return featureList.includes(AppFeature.API) +} diff --git a/packages/server/src/koa.ts b/packages/server/src/koa.ts new file mode 100644 index 0000000000..de11bf973a --- /dev/null +++ b/packages/server/src/koa.ts @@ -0,0 +1,102 @@ +import env from "./environment" +import { ExtendableContext } from "koa" +import Koa from "koa" +import koaBody from "koa-body" +import http from "http" +import * as api from "./api" +import * as automations from "./automations" +import { Thread } from "./threads" +import * as redis from "./utilities/redis" +import { events, logging, middleware, timers } from "@budibase/backend-core" +const Sentry = require("@sentry/node") +const destroyable = require("server-destroy") +const { userAgent } = require("koa-useragent") + +export default function createKoaApp() { + const app = new Koa() + + let mbNumber = parseInt(env.HTTP_MB_LIMIT || "10") + if (!mbNumber || isNaN(mbNumber)) { + mbNumber = 10 + } + // set up top level koa middleware + app.use( + koaBody({ + multipart: true, + formLimit: `${mbNumber}mb`, + jsonLimit: `${mbNumber}mb`, + textLimit: `${mbNumber}mb`, + // @ts-ignore + enableTypes: ["json", "form", "text"], + parsedMethods: ["POST", "PUT", "PATCH", "DELETE"], + }) + ) + + app.use(middleware.correlation) + app.use(middleware.pino) + app.use(userAgent) + + if (env.isProd()) { + app.on("error", (err: any, ctx: ExtendableContext) => { + Sentry.withScope(function (scope: any) { + scope.addEventProcessor(function (event: any) { + return Sentry.Handlers.parseRequest(event, ctx.request) + }) + Sentry.captureException(err) + }) + }) + } + + const server = http.createServer(app.callback()) + destroyable(server) + + let shuttingDown = false, + errCode = 0 + + server.on("close", async () => { + // already in process + if (shuttingDown) { + return + } + shuttingDown = true + console.log("Server Closed") + timers.cleanup() + await automations.shutdown() + await redis.shutdown() + events.shutdown() + await Thread.shutdown() + api.shutdown() + if (!env.isTest()) { + process.exit(errCode) + } + }) + + const listener = server.listen(env.PORT || 0) + + const shutdown = () => { + server.close() + // @ts-ignore + server.destroy() + } + + process.on("uncaughtException", err => { + // @ts-ignore + // don't worry about this error, comes from zlib isn't important + if (err && err["code"] === "ERR_INVALID_CHAR") { + return + } + errCode = -1 + logging.logAlert("Uncaught exception.", err) + shutdown() + }) + + process.on("SIGTERM", () => { + shutdown() + }) + + process.on("SIGINT", () => { + shutdown() + }) + + return { app, server: listener } +} diff --git a/packages/server/src/startup.ts b/packages/server/src/startup.ts index 9da26ac2aa..b4a287d2d4 100644 --- a/packages/server/src/startup.ts +++ b/packages/server/src/startup.ts @@ -17,6 +17,7 @@ import * as pro from "@budibase/pro" import * as api from "./api" import sdk from "./sdk" import { initialise as initialiseWebsockets } from "./websockets" +import { automationsEnabled } from "./features" let STARTUP_RAN = false @@ -97,7 +98,9 @@ export async function startup(app?: any, server?: any) { // configure events to use the pro audit log write // can't integrate directly into backend-core due to cyclic issues queuePromises.push(events.processors.init(pro.sdk.auditLogs.write)) - queuePromises.push(automations.init()) + if (automationsEnabled()) { + queuePromises.push(automations.init()) + } queuePromises.push(initPro()) if (app) { // bring routes online as final step once everything ready diff --git a/packages/server/src/tests/utilities/TestConfiguration.ts b/packages/server/src/tests/utilities/TestConfiguration.ts index a93c78d5fc..c8b917f626 100644 --- a/packages/server/src/tests/utilities/TestConfiguration.ts +++ b/packages/server/src/tests/utilities/TestConfiguration.ts @@ -87,7 +87,7 @@ class TestConfiguration { if (openServer) { // use a random port because it doesn't matter env.PORT = "0" - this.server = require("../../app").default + this.server = require("../../app").getServer() // we need the request for logging in, involves cookies, hard to fake this.request = supertest(this.server) this.started = true @@ -178,7 +178,7 @@ class TestConfiguration { if (this.server) { this.server.close() } else { - require("../../app").default.close() + require("../../app").getServer().close() } if (this.allApps) { cleanup(this.allApps.map(app => app.appId)) diff --git a/packages/worker/src/environment.ts b/packages/worker/src/environment.ts index 6ef6dab03c..c357ceb65b 100644 --- a/packages/worker/src/environment.ts +++ b/packages/worker/src/environment.ts @@ -31,6 +31,8 @@ function parseIntSafe(number: any) { } const environment = { + // features + WORKER_FEATURES: process.env.WORKER_FEATURES, // auth MINIO_ACCESS_KEY: process.env.MINIO_ACCESS_KEY, MINIO_SECRET_KEY: process.env.MINIO_SECRET_KEY, diff --git a/packages/worker/src/features.ts b/packages/worker/src/features.ts new file mode 100644 index 0000000000..c9b5af7fad --- /dev/null +++ b/packages/worker/src/features.ts @@ -0,0 +1,26 @@ +import env from "./environment" + +enum WorkerFeature {} + +const featureList: WorkerFeature[] = processFeatureList() + +function processFeatureList() { + const fullList = Object.values(WorkerFeature) as string[] + let list + if (!env.WORKER_FEATURES) { + list = fullList + } else { + list = env.WORKER_FEATURES.split(",") + } + for (let feature of list) { + if (!fullList.includes(feature)) { + throw new Error(`Feature: ${feature} is not an allowed option`) + } + } + // casting ok - confirmed definitely is a list of worker features + return list as unknown as WorkerFeature[] +} + +export function isFeatureEnabled(feature: WorkerFeature) { + return featureList.includes(feature) +} From 4c6c0f3002434476ce1581ae266806e956c1dbb4 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 17 Aug 2023 16:51:11 +0100 Subject: [PATCH 025/138] Quick fix based on tests. --- packages/server/src/app.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/app.ts b/packages/server/src/app.ts index 6cb122480a..1f38448efb 100644 --- a/packages/server/src/app.ts +++ b/packages/server/src/app.ts @@ -37,5 +37,5 @@ start().catch(err => { }) export function getServer() { - return app + return server } From d32e9d58a015024f1b96b857595f425c1a6bf0f2 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Thu, 17 Aug 2023 16:35:15 +0000 Subject: [PATCH 026/138] Bump version to 2.9.30-alpha.0 --- lerna.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lerna.json b/lerna.json index 2a426ca610..8998a06f91 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.9.29", + "version": "2.9.30-alpha.0", "npmClient": "yarn", "packages": [ "packages/*" @@ -19,4 +19,4 @@ "loadEnvFiles": false } } -} +} \ No newline at end of file From ba5e390b3f19f9b9b9d43af33c99ce7f39ec09ca Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 17 Aug 2023 17:44:59 +0100 Subject: [PATCH 027/138] Quick PR comments. --- .../src/{featureFlags => features}/index.ts | 1 + .../backend-core/src/features/installation.ts | 17 ++++++++++++++ .../tests/featureFlags.spec.ts | 0 packages/backend-core/src/index.ts | 3 ++- packages/server/src/features.ts | 22 ++++-------------- packages/worker/src/features.ts | 23 ++++--------------- 6 files changed, 30 insertions(+), 36 deletions(-) rename packages/backend-core/src/{featureFlags => features}/index.ts (98%) create mode 100644 packages/backend-core/src/features/installation.ts rename packages/backend-core/src/{featureFlags => features}/tests/featureFlags.spec.ts (100%) diff --git a/packages/backend-core/src/featureFlags/index.ts b/packages/backend-core/src/features/index.ts similarity index 98% rename from packages/backend-core/src/featureFlags/index.ts rename to packages/backend-core/src/features/index.ts index 877cd60e1a..8f5c903e05 100644 --- a/packages/backend-core/src/featureFlags/index.ts +++ b/packages/backend-core/src/features/index.ts @@ -1,5 +1,6 @@ import env from "../environment" import * as context from "../context" +export * from "./installation" /** * Read the TENANT_FEATURE_FLAGS env var and return an array of features flags for each tenant. diff --git a/packages/backend-core/src/features/installation.ts b/packages/backend-core/src/features/installation.ts new file mode 100644 index 0000000000..defc8bf987 --- /dev/null +++ b/packages/backend-core/src/features/installation.ts @@ -0,0 +1,17 @@ +export function processFeatureEnvVar( + fullList: string[], + featureList?: string +) { + let list + if (!featureList) { + list = fullList + } else { + list = featureList.split(",") + } + for (let feature of list) { + if (!fullList.includes(feature)) { + throw new Error(`Feature: ${feature} is not an allowed option`) + } + } + return list as unknown as T[] +} diff --git a/packages/backend-core/src/featureFlags/tests/featureFlags.spec.ts b/packages/backend-core/src/features/tests/featureFlags.spec.ts similarity index 100% rename from packages/backend-core/src/featureFlags/tests/featureFlags.spec.ts rename to packages/backend-core/src/features/tests/featureFlags.spec.ts diff --git a/packages/backend-core/src/index.ts b/packages/backend-core/src/index.ts index 7b98674788..ffffd8240a 100644 --- a/packages/backend-core/src/index.ts +++ b/packages/backend-core/src/index.ts @@ -6,7 +6,8 @@ export * as roles from "./security/roles" export * as permissions from "./security/permissions" export * as accounts from "./accounts" export * as installation from "./installation" -export * as featureFlags from "./featureFlags" +export * as featureFlags from "./features" +export * as features from "./features/installation" export * as sessions from "./security/sessions" export * as platform from "./platform" export * as auth from "./auth" diff --git a/packages/server/src/features.ts b/packages/server/src/features.ts index 0120e48e2a..d641bd00b8 100644 --- a/packages/server/src/features.ts +++ b/packages/server/src/features.ts @@ -1,3 +1,4 @@ +import { features } from "@budibase/backend-core" import env from "./environment" enum AppFeature { @@ -5,23 +6,10 @@ enum AppFeature { AUTOMATIONS = "automations", } -const featureList = processFeatureList() - -function processFeatureList() { - const fullList = Object.values(AppFeature) as string[] - let list - if (!env.APP_FEATURES) { - list = fullList - } else { - list = env.APP_FEATURES.split(",") - } - for (let feature of list) { - if (!fullList.includes(feature)) { - throw new Error(`Feature: ${feature} is not an allowed option`) - } - } - return list -} +const featureList = features.processFeatureEnvVar( + Object.keys(AppFeature), + env.APP_FEATURES +) export function isFeatureEnabled(feature: AppFeature) { return featureList.includes(feature) diff --git a/packages/worker/src/features.ts b/packages/worker/src/features.ts index c9b5af7fad..075b3b81ca 100644 --- a/packages/worker/src/features.ts +++ b/packages/worker/src/features.ts @@ -1,25 +1,12 @@ +import { features } from "@budibase/backend-core" import env from "./environment" enum WorkerFeature {} -const featureList: WorkerFeature[] = processFeatureList() - -function processFeatureList() { - const fullList = Object.values(WorkerFeature) as string[] - let list - if (!env.WORKER_FEATURES) { - list = fullList - } else { - list = env.WORKER_FEATURES.split(",") - } - for (let feature of list) { - if (!fullList.includes(feature)) { - throw new Error(`Feature: ${feature} is not an allowed option`) - } - } - // casting ok - confirmed definitely is a list of worker features - return list as unknown as WorkerFeature[] -} +const featureList: WorkerFeature[] = features.processFeatureEnvVar( + Object.values(WorkerFeature), + env.WORKER_FEATURES +) export function isFeatureEnabled(feature: WorkerFeature) { return featureList.includes(feature) From d8c95fce1923a4647d69db8dbb661898f1996c33 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Fri, 18 Aug 2023 09:54:24 +0100 Subject: [PATCH 028/138] remove log --- .../src/components/grid/layout/NewColumnButton.svelte | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/frontend-core/src/components/grid/layout/NewColumnButton.svelte b/packages/frontend-core/src/components/grid/layout/NewColumnButton.svelte index 6b20a1bc46..2fbeb316f9 100644 --- a/packages/frontend-core/src/components/grid/layout/NewColumnButton.svelte +++ b/packages/frontend-core/src/components/grid/layout/NewColumnButton.svelte @@ -11,7 +11,6 @@ (total, col) => (total += col.width), 0 ) - $: console.log($renderedColumns) $: end = $hiddenColumnsWidth + columnsWidth - 1 - $scroll.left $: left = Math.min($width - 40, end) From 66a94d3857f5bd1ad7208c88fa68c34c2165fa96 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 18 Aug 2023 10:56:13 +0100 Subject: [PATCH 029/138] Quick fix for server tests. --- packages/server/src/features.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/features.ts b/packages/server/src/features.ts index d641bd00b8..e12260ea32 100644 --- a/packages/server/src/features.ts +++ b/packages/server/src/features.ts @@ -7,7 +7,7 @@ enum AppFeature { } const featureList = features.processFeatureEnvVar( - Object.keys(AppFeature), + Object.values(AppFeature), env.APP_FEATURES ) From e3cfdd537a505e38e1859dbdeac2aaa696af5548 Mon Sep 17 00:00:00 2001 From: Gerard Burns Date: Tue, 15 Aug 2023 09:59:20 +0100 Subject: [PATCH 030/138] New Nav component (#11266) --- .../builder/src/components/design/Pane.svelte | 21 +++ .../src/components/design/RightPanel.svelte | 112 +++++++++++ .../_components/NavigationInfoPanel.svelte | 33 ---- .../NavigationInfoPanel/CustomizePane.svelte | 176 ++++++++++++++++++ .../NavigationInfoPanel/SettingsPane.svelte | 31 +++ .../NavigationInfoPanel/index.svelte | 10 + .../design/[screenId]/navigation/index.svelte | 2 +- 7 files changed, 351 insertions(+), 34 deletions(-) create mode 100644 packages/builder/src/components/design/Pane.svelte create mode 100644 packages/builder/src/components/design/RightPanel.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel.svelte create mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/CustomizePane.svelte create mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/SettingsPane.svelte create mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/index.svelte diff --git a/packages/builder/src/components/design/Pane.svelte b/packages/builder/src/components/design/Pane.svelte new file mode 100644 index 0000000000..88b6ea1c05 --- /dev/null +++ b/packages/builder/src/components/design/Pane.svelte @@ -0,0 +1,21 @@ + + +{#if $paneStore} +
+ +
+{/if} + + diff --git a/packages/builder/src/components/design/RightPanel.svelte b/packages/builder/src/components/design/RightPanel.svelte new file mode 100644 index 0000000000..f9075600f9 --- /dev/null +++ b/packages/builder/src/components/design/RightPanel.svelte @@ -0,0 +1,112 @@ + + +
+
+
+ +
+ {title} +
+
+ {#each Object.entries(panes) as [id, pane]} +
+ +
+ {/each} +
+
+ + +
+ + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel.svelte deleted file mode 100644 index 614e1eed80..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel.svelte +++ /dev/null @@ -1,33 +0,0 @@ - - - - - {#if $selectedScreen.layoutId} - - You can't preview your navigation settings using this screen as it uses - a custom layout, which is deprecated - - {/if} - - Your navigation is configured for all the screens within your app. - - - You can hide and show your navigation for each screen in the screen - settings. - - - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/CustomizePane.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/CustomizePane.svelte new file mode 100644 index 0000000000..05108b1736 --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/CustomizePane.svelte @@ -0,0 +1,176 @@ + + + +
+
+ + CHANGES WILL APPLY TO ALL SCREENS +
+ + Your navigation is configured for all the screens within your app. + +
+ +
+
+ +
+ + update("navigation", "Top")} + /> + update("navigation", "Left")} + /> + + + {#if $store.navigation.navigation === "Top"} +
+ +
+ update("sticky", e.detail)} + /> +
+ +
+ update("logoUrl", e.detail)} + updateOnChange={false} + /> + {/if} +
+ +
+ update("hideTitle", !e.detail)} + /> + {#if !$store.navigation.hideTitle} +
+ +
+ update("title", e.detail)} + updateOnChange={false} + /> + {/if} +
+ +
+ update("navBackground", e.detail)} + /> +
+ +
+ update("navTextColor", e.detail)} + /> +
+
+ + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/SettingsPane.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/SettingsPane.svelte new file mode 100644 index 0000000000..d3ce720994 --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/SettingsPane.svelte @@ -0,0 +1,31 @@ + + + +
+ + Show nav on this screen +
+
+ + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/index.svelte new file mode 100644 index 0000000000..6ce5405f93 --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/index.svelte @@ -0,0 +1,10 @@ + + + + + + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/index.svelte index fc2e03d8e8..2331d8b285 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/index.svelte @@ -1,6 +1,6 @@ From 6886a312c5dbfa07905ca3124d0a23d610dcfe10 Mon Sep 17 00:00:00 2001 From: Gerard Burns Date: Mon, 14 Aug 2023 13:31:12 +0100 Subject: [PATCH 031/138] New Left Panel for Design --- packages/builder/src/builderStore/index.js | 6 + .../src/builderStore/store/frontend.js | 6 +- .../NewScreen}/CreateScreenModal.svelte | 0 .../design/NewScreen}/DatasourceModal.svelte | 0 .../design/NewScreen}/ScreenRoleModal.svelte | 0 .../design/NewScreen}/blank.png | Bin .../components/design/NewScreen/index.svelte | 105 +++++++ .../design/NewScreen}/table.png | Bin .../design/[screenId]/_fallback.svelte | 5 - .../design/[screenId]/_layout.svelte | 86 +----- .../_components/AppPanel.svelte | 46 +--- .../_components/AppPreview.svelte | 55 +--- .../ComponentInfoSection.svelte | 0 .../ComponentSettingsPanel.svelte | 0 .../ComponentSettingsSection.svelte | 0 .../ConditionalUIDrawer.svelte | 0 .../ConditionalUISection.svelte | 0 .../CustomStylesSection.svelte | 0 .../DesignSection.svelte | 0 .../StyleSection.svelte | 0 .../componentStyles.js | 0 .../_components/DevicePreviewSelect.svelte | 0 .../Components}/ComponentDropdownMenu.svelte | 0 .../Components}/ComponentKeyHandler.svelte | 17 +- .../Components}/ComponentScrollWrapper.svelte | 19 +- .../Components}/ComponentTree.svelte | 0 .../Components}/DNDPositionIndicator.svelte | 0 .../Components}/ScreenslotDropdownMenu.svelte | 0 .../Components}/dndStore.js | 0 .../LeftPanel/Components/index.svelte | 156 +++++++++++ .../LeftPanel/Screens/DropdownMenu.svelte} | 0 .../LeftPanel/Screens}/RoleIndicator.svelte | 8 +- .../LeftPanel/Screens/index.svelte | 233 ++++++++++++++++ .../_components/LeftPanel/index.svelte | 24 ++ .../_components/Navigation/index.svelte | 260 ++++++++++++++++++ .../_components/Screen/SettingsPanel.svelte} | 0 .../navigation/ComponentListPanel.svelte | 90 ------ .../components/[componentId]/_layout.svelte | 56 +++- .../design/[screenId]/components/index.svelte | 12 +- .../design/[screenId]/index.svelte | 5 +- .../_components/LayoutDropdownMenu.svelte | 41 --- .../_components/LayoutListPanel.svelte | 29 -- .../_components/LayoutSettingsPanel.svelte | 53 ---- .../layouts/[layoutId]/_layout.svelte | 20 -- .../layouts/[layoutId]/index.svelte | 7 - .../design/[screenId]/layouts/_layout.svelte | 12 - .../design/[screenId]/layouts/index.svelte | 12 - .../NavigationInfoPanel/CustomizePane.svelte | 176 ------------ .../NavigationInfoPanel/SettingsPane.svelte | 31 --- .../NavigationInfoPanel/index.svelte | 10 - .../_components/NavigationLinksDrawer.svelte | 130 --------- .../_components/NavigationLinksEditor.svelte | 34 --- .../NavigationSettingsPanel.svelte | 110 -------- .../design/[screenId]/navigation/index.svelte | 7 - .../_components/ScreenListPanel.svelte | 75 ----- .../design/[screenId]/screens/index.svelte | 12 - .../theme/_components/AppThemeSelect.svelte | 64 ----- .../_components/ButtonRoundnessSelect.svelte | 38 --- .../theme/_components/ThemeInfoPanel.svelte | 12 - .../_components/ThemeSettingsPanel.svelte | 55 ---- .../design/[screenId]/theme/index.svelte | 7 - .../app/[application]/design/index.svelte | 2 +- .../app/[application]/design/new.svelte | 103 +------ .../client/src/components/Component.svelte | 10 +- packages/client/src/components/Screen.svelte | 2 +- .../client/src/components/app/Layout.svelte | 11 +- .../src/components/preview/SettingsBar.svelte | 6 +- 67 files changed, 916 insertions(+), 1342 deletions(-) rename packages/builder/src/{pages/builder/app/[application]/design/_components => components/design/NewScreen}/CreateScreenModal.svelte (100%) rename packages/builder/src/{pages/builder/app/[application]/design/_components => components/design/NewScreen}/DatasourceModal.svelte (100%) rename packages/builder/src/{pages/builder/app/[application]/design/_components => components/design/NewScreen}/ScreenRoleModal.svelte (100%) rename packages/builder/src/{pages/builder/app/[application]/design => components/design/NewScreen}/blank.png (100%) create mode 100644 packages/builder/src/components/design/NewScreen/index.svelte rename packages/builder/src/{pages/builder/app/[application]/design => components/design/NewScreen}/table.png (100%) delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/_fallback.svelte rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{ => components/[componentId]}/_components/AppPanel.svelte (52%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{ => components/[componentId]}/_components/AppPreview.svelte (86%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/{settings => Component}/ComponentInfoSection.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/{settings => Component}/ComponentSettingsPanel.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/{settings => Component}/ComponentSettingsSection.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/{settings => Component}/ConditionalUIDrawer.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/{settings => Component}/ConditionalUISection.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/{settings => Component}/CustomStylesSection.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/{settings => Component}/DesignSection.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/{settings => Component}/StyleSection.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/{settings => Component}/componentStyles.js (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{ => components/[componentId]}/_components/DevicePreviewSelect.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/{navigation => LeftPanel/Components}/ComponentDropdownMenu.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/{navigation => LeftPanel/Components}/ComponentKeyHandler.svelte (91%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/{navigation => LeftPanel/Components}/ComponentScrollWrapper.svelte (84%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/{navigation => LeftPanel/Components}/ComponentTree.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/{navigation => LeftPanel/Components}/DNDPositionIndicator.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/{navigation => LeftPanel/Components}/ScreenslotDropdownMenu.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/{navigation => LeftPanel/Components}/dndStore.js (100%) create mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/Components/index.svelte rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{screens/_components/ScreenDropdownMenu.svelte => components/[componentId]/_components/LeftPanel/Screens/DropdownMenu.svelte} (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{screens/_components => components/[componentId]/_components/LeftPanel/Screens}/RoleIndicator.svelte (87%) create mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/Screens/index.svelte create mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/index.svelte create mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Navigation/index.svelte rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{screens/_components/ScreenSettingsPanel.svelte => components/[componentId]/_components/Screen/SettingsPanel.svelte} (100%) delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/navigation/ComponentListPanel.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/_components/LayoutDropdownMenu.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/_components/LayoutListPanel.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/_components/LayoutSettingsPanel.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/_layout.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/index.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/_layout.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/index.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/CustomizePane.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/SettingsPane.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/index.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationLinksDrawer.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationLinksEditor.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationSettingsPanel.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/index.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenListPanel.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/index.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/_components/AppThemeSelect.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/_components/ButtonRoundnessSelect.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/_components/ThemeInfoPanel.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/_components/ThemeSettingsPanel.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/theme/index.svelte diff --git a/packages/builder/src/builderStore/index.js b/packages/builder/src/builderStore/index.js index 2ca8057b48..3cd387fe95 100644 --- a/packages/builder/src/builderStore/index.js +++ b/packages/builder/src/builderStore/index.js @@ -61,6 +61,12 @@ export const selectedLayout = derived(store, $store => { export const selectedComponent = derived( [store, selectedScreen], ([$store, $selectedScreen]) => { + if ( + $selectedScreen && + ["navigation", "screen"].includes($store.selectedComponentId) + ) { + return findComponent($selectedScreen?.props, $selectedScreen?.props._id) + } if (!$selectedScreen || !$store.selectedComponentId) { return null } diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index f312a58e97..038fb661b9 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -769,9 +769,13 @@ export const getFrontendStore = () => { else { await store.actions.screens.patch(screen => { // Find the selected component + let selectedComponentId = state.selectedComponentId + if (["navigation", "screen"].includes(selectedComponentId)) { + selectedComponentId = screen?.props._id + } const currentComponent = findComponent( screen.props, - state.selectedComponentId + selectedComponentId ) if (!currentComponent) { return false diff --git a/packages/builder/src/pages/builder/app/[application]/design/_components/CreateScreenModal.svelte b/packages/builder/src/components/design/NewScreen/CreateScreenModal.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/_components/CreateScreenModal.svelte rename to packages/builder/src/components/design/NewScreen/CreateScreenModal.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/_components/DatasourceModal.svelte b/packages/builder/src/components/design/NewScreen/DatasourceModal.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/_components/DatasourceModal.svelte rename to packages/builder/src/components/design/NewScreen/DatasourceModal.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/_components/ScreenRoleModal.svelte b/packages/builder/src/components/design/NewScreen/ScreenRoleModal.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/_components/ScreenRoleModal.svelte rename to packages/builder/src/components/design/NewScreen/ScreenRoleModal.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/blank.png b/packages/builder/src/components/design/NewScreen/blank.png similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/blank.png rename to packages/builder/src/components/design/NewScreen/blank.png diff --git a/packages/builder/src/components/design/NewScreen/index.svelte b/packages/builder/src/components/design/NewScreen/index.svelte new file mode 100644 index 0000000000..b504940ca7 --- /dev/null +++ b/packages/builder/src/components/design/NewScreen/index.svelte @@ -0,0 +1,105 @@ + + +
+ +
+ Start from scratch or create screens from your data +
+ +
+
createScreenModal.show("blank")}> +
+ +
+
+ Blank screen + Add an empty blank screen +
+
+ +
createScreenModal.show("table")}> +
+ +
+
+ Table + View, edit and delete rows on a table +
+
+
+
+
+ + + + diff --git a/packages/builder/src/pages/builder/app/[application]/design/table.png b/packages/builder/src/components/design/NewScreen/table.png similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/table.png rename to packages/builder/src/components/design/NewScreen/table.png diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_fallback.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_fallback.svelte deleted file mode 100644 index 00165e4ee9..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_fallback.svelte +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte index 8bc0dcc3e5..77510951b1 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte @@ -1,11 +1,8 @@ -
-
- - $goto("./screens")} - /> - $goto("./components")} - /> - $goto("./theme")} - /> - $goto("./navigation")} - /> - {#if $store.layouts?.length} - $goto("./layouts")} - /> - {/if} - -
- -
- {#if $selectedScreen} - - - {/if} -
-
- - + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/AppPanel.svelte similarity index 52% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPanel.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/AppPanel.svelte index 785b221239..379cebca37 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/AppPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/AppPanel.svelte @@ -1,9 +1,7 @@ @@ -11,22 +9,11 @@
- +
+ Screens +
+
+ +
+
+ +
+
+
+ {#each filteredScreens as screen (screen._id)} + store.actions.screens.select(screen._id)} + rightAlignIcon + showTooltip + selectedBy={$userSelectedResourceMap[screen._id]} + > + + + + {/each} +
+ {#if !filteredScreens?.length} + + + There aren't any screens matching the current filters + + + {/if} +
+ +
+ (newScreen = false)} /> +
+ + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/index.svelte new file mode 100644 index 0000000000..3f521b23c7 --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/index.svelte @@ -0,0 +1,24 @@ + + +
+ +
+ +
+ + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Navigation/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Navigation/index.svelte new file mode 100644 index 0000000000..f442e3a275 --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Navigation/index.svelte @@ -0,0 +1,260 @@ + + +
+
+
+ +
+ Navigation +
+
+
+
+ General +
+
+ + Show nav on this screen +
+
+
+
+
+ Customize +
+
+
+ + These settings apply to all screens +
+
+ +
+
+ +
+ + update("navigation", "Top")} + /> + update("navigation", "Left")} + /> + + + {#if $store.navigation.navigation === "Top"} +
+ +
+ update("sticky", e.detail)} + /> +
+ +
+ update("logoUrl", e.detail)} + updateOnChange={false} + /> + {/if} +
+ +
+ update("hideTitle", !e.detail)} + /> + {#if !$store.navigation.hideTitle} +
+ +
+ update("title", e.detail)} + updateOnChange={false} + /> + {/if} +
+ +
+ update("navBackground", e.detail)} + /> +
+ +
+ update("navTextColor", e.detail)} + /> +
+
+
+ + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenSettingsPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Screen/SettingsPanel.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenSettingsPanel.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Screen/SettingsPanel.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/navigation/ComponentListPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/navigation/ComponentListPanel.svelte deleted file mode 100644 index 9513753d76..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/navigation/ComponentListPanel.svelte +++ /dev/null @@ -1,90 +0,0 @@ - - - -
- -
- -
    -
  • - { - $store.selectedComponentId = $selectedScreen?.props._id - }} - id={`component-${$selectedScreen?.props._id}`} - selectedBy={$userSelectedResourceMap[$selectedScreen?.props._id]} - > - - - - - - {#if $dndStore.dragging && $dndStore.valid} - - {#if $dndStore.dropPosition !== DropPosition.INSIDE} - - {/if} - {/if} -
  • -
-
-
- - - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_layout.svelte index 860258c940..1dcf40a3c5 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_layout.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_layout.svelte @@ -1,14 +1,19 @@ - - - +
+
+ {#if $selectedScreen} + + + {#if routeComponentId === "screen"} + + {:else if routeComponentId === "navigation"} + + {:else} + + {/if} + + {/if} +
+
+ + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/index.svelte index f8c4cc0868..9361415cb7 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/index.svelte @@ -1,18 +1,8 @@ diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/index.svelte index f5e3806bd6..496467c546 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/index.svelte @@ -1,5 +1,8 @@ diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/_components/LayoutDropdownMenu.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/_components/LayoutDropdownMenu.svelte deleted file mode 100644 index cba68f899d..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/_components/LayoutDropdownMenu.svelte +++ /dev/null @@ -1,41 +0,0 @@ - - - -
- -
- Delete -
- - - - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/_components/LayoutListPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/_components/LayoutListPanel.svelte deleted file mode 100644 index cc895317fd..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/_components/LayoutListPanel.svelte +++ /dev/null @@ -1,29 +0,0 @@ - - - -
- {#each $store.layouts as layout (layout._id)} - store.actions.layouts.select(layout._id)} - > - - - {/each} -
-
- - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/_components/LayoutSettingsPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/_components/LayoutSettingsPanel.svelte deleted file mode 100644 index bfc2f94f43..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/_components/LayoutSettingsPanel.svelte +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - Custom layouts are being deprecated. They will be removed in a future - release. - - - You can save the content of this layout by pressing the button below. - - - This will copy all components inside your layout, which you can then paste - into a screen. - - - - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/_layout.svelte deleted file mode 100644 index c82fefab3e..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/_layout.svelte +++ /dev/null @@ -1,20 +0,0 @@ - - - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/index.svelte deleted file mode 100644 index 4d39403bc3..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/[layoutId]/index.svelte +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/_layout.svelte deleted file mode 100644 index 1333c6afe3..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/_layout.svelte +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/index.svelte deleted file mode 100644 index 09d45f8fde..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/layouts/index.svelte +++ /dev/null @@ -1,12 +0,0 @@ - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/CustomizePane.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/CustomizePane.svelte deleted file mode 100644 index 05108b1736..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/CustomizePane.svelte +++ /dev/null @@ -1,176 +0,0 @@ - - - -
-
- - CHANGES WILL APPLY TO ALL SCREENS -
- - Your navigation is configured for all the screens within your app. - -
- -
-
- -
- - update("navigation", "Top")} - /> - update("navigation", "Left")} - /> - - - {#if $store.navigation.navigation === "Top"} -
- -
- update("sticky", e.detail)} - /> -
- -
- update("logoUrl", e.detail)} - updateOnChange={false} - /> - {/if} -
- -
- update("hideTitle", !e.detail)} - /> - {#if !$store.navigation.hideTitle} -
- -
- update("title", e.detail)} - updateOnChange={false} - /> - {/if} -
- -
- update("navBackground", e.detail)} - /> -
- -
- update("navTextColor", e.detail)} - /> -
-
- - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/SettingsPane.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/SettingsPane.svelte deleted file mode 100644 index d3ce720994..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/SettingsPane.svelte +++ /dev/null @@ -1,31 +0,0 @@ - - - -
- - Show nav on this screen -
-
- - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/index.svelte deleted file mode 100644 index 6ce5405f93..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationInfoPanel/index.svelte +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationLinksDrawer.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationLinksDrawer.svelte deleted file mode 100644 index 5ffccc5800..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationLinksDrawer.svelte +++ /dev/null @@ -1,130 +0,0 @@ - - - -
- - {#if links?.length} - - {/if} -
- -
-
-
-
- - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationLinksEditor.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationLinksEditor.svelte deleted file mode 100644 index 895c82495d..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationLinksEditor.svelte +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - Configure the links in your navigation bar. - - - - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationSettingsPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationSettingsPanel.svelte deleted file mode 100644 index c6d43984b2..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/_components/NavigationSettingsPanel.svelte +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - update("navigation", "Top")} - /> - update("navigation", "Left")} - /> - - - {#if $store.navigation.navigation === "Top"} - update("sticky", e.detail)} - /> - update("logoUrl", e.detail)} - placeholder="Add logo URL" - updateOnChange={false} - /> - {/if} - - - update("hideTitle", !e.detail)} - /> - {#if !$store.navigation.hideTitle} - update("title", e.detail)} - placeholder="Add title" - updateOnChange={false} - /> - {/if} - - - - update("navBackground", e.detail)} - /> - - - - update("navTextColor", e.detail)} - /> - - - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/index.svelte deleted file mode 100644 index 2331d8b285..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/navigation/index.svelte +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenListPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenListPanel.svelte deleted file mode 100644 index 6362af3073..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/screens/_components/ScreenListPanel.svelte +++ /dev/null @@ -1,75 +0,0 @@ - - - - - - (searchString = e.detail)} - /> - + + + removeLink(link.id)} + /> +
+ {/each} +
+ {/if} +
+ +
+ +
+ + + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Navigation/LinksEditor.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Navigation/LinksEditor.svelte new file mode 100644 index 0000000000..9ab6681273 --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Navigation/LinksEditor.svelte @@ -0,0 +1,34 @@ + + + + + + Configure the links in your navigation bar. + + + + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Navigation/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Navigation/index.svelte index 6da744a44a..16baa3bfff 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Navigation/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Navigation/index.svelte @@ -1,4 +1,5 @@ - + Configure the links in your navigation bar. From 0ea81f98d6fd317367b60e76d9ac14f8f602a9bc Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 22 Aug 2023 16:29:40 +0100 Subject: [PATCH 090/138] Update panel headings to match new designs --- packages/builder/src/components/design/Panel.svelte | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/builder/src/components/design/Panel.svelte b/packages/builder/src/components/design/Panel.svelte index 3968292ba9..db8d9b9096 100644 --- a/packages/builder/src/components/design/Panel.svelte +++ b/packages/builder/src/components/design/Panel.svelte @@ -1,5 +1,5 @@
-
+
Components
@@ -116,15 +116,16 @@ } .header { - padding: 15px 12px; + height: 50px; + box-sizing: border-box; + padding: var(--spacing-l); display: flex; align-items: center; border-bottom: 2px solid transparent; - transition: border-bottom 300ms; + transition: border-bottom 130ms ease-out; } - - .headerScrolling { - border-bottom: 2px solid var(--grey-2); + .header.scrolling { + border-bottom: var(--border-light); } .components :global(.nav-item) { From a07f343f839323f9149ebc01cc5ec6388f86bdb0 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 22 Aug 2023 16:45:37 +0100 Subject: [PATCH 093/138] Fix component scroll offsets not working --- .../Components/ComponentScrollWrapper.svelte | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/Components/ComponentScrollWrapper.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/Components/ComponentScrollWrapper.svelte index 226aff88ab..484b56f21c 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/Components/ComponentScrollWrapper.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/Components/ComponentScrollWrapper.svelte @@ -16,7 +16,7 @@ let newOffsets = {} // Calculate left offset - const offsetX = bounds.left + bounds.width + scrollLeft - 36 + const offsetX = bounds.left + bounds.width + scrollLeft + 16 if (offsetX > sidebarWidth) { newOffsets.left = offsetX - sidebarWidth } else { @@ -79,19 +79,4 @@ overflow: auto; height: 0; } - - div::-webkit-scrollbar-track { - background: var(--background-alt); - } - - div::-webkit-scrollbar { - width: 18px; - } - - div::-webkit-scrollbar-thumb { - background-color: var(--grey-3); - border-radius: 20px; - border: 1px solid var(--background-alt); - border-width: 5px 5px; - } From a4a639c2ba98e088a8cc4a0e1fba496ac440f155 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 22 Aug 2023 16:49:04 +0100 Subject: [PATCH 094/138] Update screen list size slightly --- .../[componentId]/_components/LeftPanel/Screens/index.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/Screens/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/Screens/index.svelte index a3762b81ed..c11e933624 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/Screens/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/Screens/index.svelte @@ -135,7 +135,7 @@ } .screens { - height: 212px; + height: 210px; display: flex; flex-direction: column; transition: height 300ms ease-out; From d0414812cf6f90e6be635b2d7feeff972f28015b Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 22 Aug 2023 17:51:47 +0100 Subject: [PATCH 095/138] Adjust design section page layouts to stop remounting left nav on screen change --- .../app/[application]/design/[screenId]/_layout.svelte | 2 ++ .../[componentId]/_components/LeftPanel/index.svelte | 9 ++++++--- .../[screenId]/components/[componentId]/_layout.svelte | 10 ---------- 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte index 9bc1806349..8471cc03ed 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte @@ -4,6 +4,7 @@ import { syncURLToState } from "helpers/urlStateSync" import { store } from "builderStore" import { onDestroy } from "svelte" + import LeftPanel from "./components/[componentId]/_components/LeftPanel/index.svelte" $: screenId = $store.selectedScreenId $: store.actions.websocket.selectResource(screenId) @@ -23,6 +24,7 @@
+
diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/index.svelte index 86c0df8cac..c1fe15f625 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/index.svelte @@ -1,25 +1,28 @@
- + {#if $selectedScreen} + + {/if}
diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_layout.svelte index 807109326a..51c3c64321 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_layout.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_layout.svelte @@ -1,5 +1,4 @@ -
- -
{#if routeComponentId === "screen"} {:else if routeComponentId === "navigation"} @@ -58,9 +54,3 @@ {/if} - - From 656870db8b9ec5314f7e62329d71b6f225b2016c Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 22 Aug 2023 18:14:08 +0100 Subject: [PATCH 096/138] Adding last of support for per app group builder support, enriching the user on self return, as well as adding the functionality required to server middlewares. --- packages/pro | 2 +- packages/server/src/api/controllers/auth.ts | 9 +- packages/server/src/utilities/global.ts | 85 ++++++++----------- .../server/src/utilities/workerRequests.ts | 31 ++----- .../worker/src/api/controllers/global/self.ts | 4 +- .../src/api/controllers/global/users.ts | 8 +- 6 files changed, 55 insertions(+), 84 deletions(-) diff --git a/packages/pro b/packages/pro index a054a51726..39d76da212 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit a054a51726fa3f17879a469a04675778185b7ed7 +Subproject commit 39d76da2124d96b1bcec0f2352ca5ef9b0c84318 diff --git a/packages/server/src/api/controllers/auth.ts b/packages/server/src/api/controllers/auth.ts index bca6c4e64e..ae98d92332 100644 --- a/packages/server/src/api/controllers/auth.ts +++ b/packages/server/src/api/controllers/auth.ts @@ -2,9 +2,9 @@ import { outputProcessing } from "../../utilities/rowProcessor" import { InternalTables } from "../../db/utils" import { getFullUser } from "../../utilities/users" import { roles, context } from "@budibase/backend-core" -import { groups } from "@budibase/pro" -import { ContextUser, User, Row, UserCtx } from "@budibase/types" +import { ContextUser, Row, UserCtx } from "@budibase/types" import sdk from "../../sdk" +import { processUser } from "src/utilities/global" const PUBLIC_ROLE = roles.BUILTIN_ROLE_IDS.PUBLIC @@ -26,7 +26,7 @@ export async function fetchSelf(ctx: UserCtx) { } const appId = context.getAppId() - const user: ContextUser = await getFullUser(ctx, userId) + let user: ContextUser = await getFullUser(ctx, userId) // this shouldn't be returned by the app self delete user.roles // forward the csrf token from the session @@ -36,8 +36,7 @@ export async function fetchSelf(ctx: UserCtx) { const db = context.getAppDB() // check for group permissions if (!user.roleId || user.roleId === PUBLIC_ROLE) { - const groupRoleId = await groups.getGroupRoleId(user as User, appId) - user.roleId = groupRoleId || user.roleId + user = await processUser(user, { appId }) } // remove the full roles structure delete user.roles diff --git a/packages/server/src/utilities/global.ts b/packages/server/src/utilities/global.ts index 5561b59233..1cb7956d5e 100644 --- a/packages/server/src/utilities/global.ts +++ b/packages/server/src/utilities/global.ts @@ -12,75 +12,64 @@ import { groups } from "@budibase/pro" import { UserCtx, ContextUser, User, UserGroup } from "@budibase/types" import cloneDeep from "lodash/cloneDeep" -export function updateAppRole( +export async function processUser( user: ContextUser, - { appId }: { appId?: string } = {} + opts: { appId?: string; groups?: UserGroup[] } = {} ) { - appId = appId || context.getAppId() - if (!user || (!user.roles && !user.userGroups)) { return user } - // if in an multi-tenancy environment make sure roles are never updated + user = cloneDeep(user) + delete user.password + const appId = opts.appId || context.getAppId() + if (!appId) { + throw new Error("Unable to process user without app ID") + } + // if in a multi-tenancy environment and in wrong tenant make sure roles are never updated if (env.MULTI_TENANCY && appId && !tenancy.isUserInAppTenant(appId, user)) { user = users.removePortalUserPermissions(user) user.roleId = roles.BUILTIN_ROLE_IDS.PUBLIC return user } - // always use the deployed app - if (appId && user.roles) { + let groupList: UserGroup[] = [] + if (appId && user?.userGroups?.length) { + groupList = opts.groups + ? opts.groups + : await groups.getBulk(user.userGroups) + } + // check if a group provides builder access + const builderAppIds = await groups.getGroupBuilderAppIds(user, appId, { + groups: groupList, + }) + if (builderAppIds.length && !users.isBuilder(user, appId)) { + const existingApps = user.builder?.apps || [] + user.builder = { + apps: [...new Set(existingApps.concat(builderAppIds))], + } + } + // builders are always admins within the app + if (users.isBuilder(user, appId)) { + user.roleId = roles.BUILTIN_ROLE_IDS.ADMIN + } + // try to get the role from the user list + if (!user.roleId && appId && user.roles) { user.roleId = user.roles[dbCore.getProdAppID(appId)] } - // if a role wasn't found then either set as admin (builder) or public (everyone else) - if (!user.roleId && users.isBuilder(user, appId)) { - user.roleId = roles.BUILTIN_ROLE_IDS.ADMIN - } else if (!user.roleId && !user?.userGroups?.length) { - user.roleId = roles.BUILTIN_ROLE_IDS.PUBLIC - } - - delete user.roles - return user -} - -async function checkGroupRoles( - user: ContextUser, - opts: { appId?: string; groups?: UserGroup[] } = {} -) { - if (user.roleId && user.roleId !== roles.BUILTIN_ROLE_IDS.PUBLIC) { - return user - } - if (opts.appId) { - user.roleId = await groups.getGroupRoleId(user as User, opts.appId, { - groups: opts.groups, + // try to get the role from the group list + if (!user.roleId && groupList) { + user.roleId = await groups.getGroupRoleId(user, appId, { + groups: groupList, }) } // final fallback, simply couldn't find a role - user must be public if (!user.roleId) { user.roleId = roles.BUILTIN_ROLE_IDS.PUBLIC } + // remove the roles as it is now set + delete user.roles return user } -export async function processUser( - user: ContextUser, - opts: { appId?: string; groups?: UserGroup[] } = {} -) { - let clonedUser = cloneDeep(user) - if (clonedUser) { - delete clonedUser.password - } - const appId = opts.appId || context.getAppId() - clonedUser = updateAppRole(clonedUser, { appId }) - if (!clonedUser.roleId && clonedUser?.userGroups?.length) { - clonedUser = await checkGroupRoles(clonedUser, { - appId, - groups: opts?.groups, - }) - } - - return clonedUser -} - export async function getCachedSelf(ctx: UserCtx, appId: string) { // this has to be tenant aware, can't depend on the context to find it out // running some middlewares before the tenancy causes context to break diff --git a/packages/server/src/utilities/workerRequests.ts b/packages/server/src/utilities/workerRequests.ts index 5230e25bf7..fa9fde7297 100644 --- a/packages/server/src/utilities/workerRequests.ts +++ b/packages/server/src/utilities/workerRequests.ts @@ -8,10 +8,9 @@ import { logging, env as coreEnv, } from "@budibase/backend-core" -import { updateAppRole } from "./global" -import { BBContext, User, EmailInvite } from "@budibase/types" +import { Ctx, User, EmailInvite } from "@budibase/types" -export function request(ctx?: BBContext, request?: any) { +export function request(ctx?: Ctx, request?: any) { if (!request.headers) { request.headers = {} } @@ -43,7 +42,7 @@ export function request(ctx?: BBContext, request?: any) { async function checkResponse( response: any, errorMsg: string, - { ctx }: { ctx?: BBContext } = {} + { ctx }: { ctx?: Ctx } = {} ) { if (response.status !== 200) { let error @@ -105,21 +104,7 @@ export async function sendSmtpEmail({ return checkResponse(response, "send email") } -export async function getGlobalSelf(ctx: BBContext, appId?: string) { - const endpoint = `/api/global/self` - const response = await fetch( - checkSlashesInUrl(env.WORKER_URL + endpoint), - // we don't want to use API key when getting self - request(ctx, { method: "GET" }) - ) - let json = await checkResponse(response, "get self globally", { ctx }) - if (appId) { - json = updateAppRole(json) - } - return json -} - -export async function removeAppFromUserRoles(ctx: BBContext, appId: string) { +export async function removeAppFromUserRoles(ctx: Ctx, appId: string) { const prodAppId = dbCore.getProdAppID(appId) const response = await fetch( checkSlashesInUrl(env.WORKER_URL + `/api/global/roles/${prodAppId}`), @@ -130,7 +115,7 @@ export async function removeAppFromUserRoles(ctx: BBContext, appId: string) { return checkResponse(response, "remove app role") } -export async function allGlobalUsers(ctx: BBContext) { +export async function allGlobalUsers(ctx: Ctx) { const response = await fetch( checkSlashesInUrl(env.WORKER_URL + "/api/global/users"), // we don't want to use API key when getting self @@ -139,7 +124,7 @@ export async function allGlobalUsers(ctx: BBContext) { return checkResponse(response, "get users", { ctx }) } -export async function saveGlobalUser(ctx: BBContext) { +export async function saveGlobalUser(ctx: Ctx) { const response = await fetch( checkSlashesInUrl(env.WORKER_URL + "/api/global/users"), // we don't want to use API key when getting self @@ -148,7 +133,7 @@ export async function saveGlobalUser(ctx: BBContext) { return checkResponse(response, "save user", { ctx }) } -export async function deleteGlobalUser(ctx: BBContext) { +export async function deleteGlobalUser(ctx: Ctx) { const response = await fetch( checkSlashesInUrl( env.WORKER_URL + `/api/global/users/${ctx.params.userId}` @@ -159,7 +144,7 @@ export async function deleteGlobalUser(ctx: BBContext) { return checkResponse(response, "delete user", { ctx }) } -export async function readGlobalUser(ctx: BBContext): Promise { +export async function readGlobalUser(ctx: Ctx): Promise { const response = await fetch( checkSlashesInUrl( env.WORKER_URL + `/api/global/users/${ctx.params.userId}` diff --git a/packages/worker/src/api/controllers/global/self.ts b/packages/worker/src/api/controllers/global/self.ts index 7167d91b23..47dbef964e 100644 --- a/packages/worker/src/api/controllers/global/self.ts +++ b/packages/worker/src/api/controllers/global/self.ts @@ -48,7 +48,7 @@ export async function generateAPIKey(ctx: any) { } catch (err) { devInfo = { _id: id, userId } } - devInfo.apiKey = await apiKey + devInfo.apiKey = apiKey await db.put(devInfo) ctx.body = cleanupDevInfo(devInfo) } @@ -63,7 +63,7 @@ export async function fetchAPIKey(ctx: any) { devInfo = { _id: id, userId: ctx.user._id, - apiKey: await newApiKey(), + apiKey: newApiKey(), } await db.put(devInfo) } diff --git a/packages/worker/src/api/controllers/global/users.ts b/packages/worker/src/api/controllers/global/users.ts index a8207ea89e..ad906c8688 100644 --- a/packages/worker/src/api/controllers/global/users.ts +++ b/packages/worker/src/api/controllers/global/users.ts @@ -25,11 +25,11 @@ import { import { accounts, cache, + ErrorCode, events, migrations, - tenancy, platform, - ErrorCode, + tenancy, } from "@budibase/backend-core" import { checkAnyUserExists } from "../../../utilities/users" import { isEmailConfigured } from "../../../utilities/email" @@ -280,7 +280,7 @@ export const onboardUsers = async (ctx: Ctx) => { let bulkCreateReponse = await userSdk.db.bulkCreate(users, []) // Apply temporary credentials - let createWithCredentials = { + ctx.body = { ...bulkCreateReponse, successful: bulkCreateReponse?.successful.map(user => { return { @@ -290,8 +290,6 @@ export const onboardUsers = async (ctx: Ctx) => { }), created: true, } - - ctx.body = createWithCredentials } else { ctx.throw(400, "User onboarding failed") } From a83e987dcdeeb81d968fb93dcb6d38d665782f3b Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Tue, 22 Aug 2023 18:55:36 +0100 Subject: [PATCH 097/138] Stop preview jumping when scrolling to components, and improve scrolling behaviour --- packages/client/src/components/Component.svelte | 2 +- packages/client/src/components/app/Layout.svelte | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index 31f3cc3db6..94e7587010 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -475,7 +475,7 @@ node.style.scrollMargin = "100px" node.scrollIntoView({ behavior: "smooth", - block: "start", + block: "nearest", inline: "start", }) } diff --git a/packages/client/src/components/app/Layout.svelte b/packages/client/src/components/app/Layout.svelte index b7aff4047a..5207892e42 100644 --- a/packages/client/src/components/app/Layout.svelte +++ b/packages/client/src/components/app/Layout.svelte @@ -73,18 +73,20 @@ ) $: autoCloseSidePanel = !$builderStore.inBuilder && $sidePanelStore.open - // Scroll navigation into view if selected + // Scroll navigation into view if selected. + // Memoize into a primitive to avoid spamming this whenever builder store + // changes. + $: selected = + $builderStore.inBuilder && + $builderStore.selectedComponentId === "navigation" $: { - if ( - $builderStore.inBuilder && - $builderStore.selectedComponentId === "navigation" - ) { + if (selected) { const node = document.getElementsByClassName("nav-wrapper")?.[0] if (node) { node.style.scrollMargin = "100px" node.scrollIntoView({ behavior: "smooth", - block: "start", + block: "nearest", inline: "start", }) } From 3395a5b96b0b9cccf971b63d294a45b7e41127b6 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Tue, 22 Aug 2023 19:15:47 +0100 Subject: [PATCH 098/138] Some other minor changes to fully support the per app builder from groups, making sure middlewares are properly aware. --- packages/backend-core/src/cache/user.ts | 14 ++++++++++++++ .../backend-core/src/middleware/builderOnly.ts | 11 ++++++----- .../src/middleware/builderOrAdmin.ts | 11 ++++++----- packages/backend-core/src/users/db.ts | 18 +++++++++++++++++- packages/server/src/utilities/global.ts | 3 ++- 5 files changed, 45 insertions(+), 12 deletions(-) diff --git a/packages/backend-core/src/cache/user.ts b/packages/backend-core/src/cache/user.ts index 8281bfca62..e2af78adfd 100644 --- a/packages/backend-core/src/cache/user.ts +++ b/packages/backend-core/src/cache/user.ts @@ -4,6 +4,8 @@ import * as context from "../context" import * as platform from "../platform" import env from "../environment" import * as accounts from "../accounts" +import { UserDB } from "../users" +import { sdk } from "@budibase/shared-core" const EXPIRY_SECONDS = 3600 @@ -60,6 +62,18 @@ export async function getUser( // make sure the tenant ID is always correct/set user.tenantId = tenantId } + // if has groups, could have builder permissions granted by a group + if (user.userGroups && !sdk.users.isGlobalBuilder(user)) { + await context.doInTenant(tenantId, async () => { + const appIds = await UserDB.getGroupBuilderAppIds(user) + if (appIds.length) { + const existing = user.builder?.apps || [] + user.builder = { + apps: [...new Set(existing.concat(appIds))], + } + } + }) + } return user } diff --git a/packages/backend-core/src/middleware/builderOnly.ts b/packages/backend-core/src/middleware/builderOnly.ts index 8c1c54a44c..fafcc524cc 100644 --- a/packages/backend-core/src/middleware/builderOnly.ts +++ b/packages/backend-core/src/middleware/builderOnly.ts @@ -5,11 +5,12 @@ import env from "../environment" export default async (ctx: UserCtx, next: any) => { const appId = getAppId() - const builderFn = env.isWorker() - ? hasBuilderPermissions - : env.isApps() - ? isBuilder - : undefined + const builderFn = + env.isWorker() || !appId + ? hasBuilderPermissions + : env.isApps() + ? isBuilder + : undefined if (!builderFn) { throw new Error("Service name unknown - middleware inactive.") } diff --git a/packages/backend-core/src/middleware/builderOrAdmin.ts b/packages/backend-core/src/middleware/builderOrAdmin.ts index c03e856233..4b8badec15 100644 --- a/packages/backend-core/src/middleware/builderOrAdmin.ts +++ b/packages/backend-core/src/middleware/builderOrAdmin.ts @@ -5,11 +5,12 @@ import env from "../environment" export default async (ctx: UserCtx, next: any) => { const appId = getAppId() - const builderFn = env.isWorker() - ? hasBuilderPermissions - : env.isApps() - ? isBuilder - : undefined + const builderFn = + env.isWorker() || !appId + ? hasBuilderPermissions + : env.isApps() + ? isBuilder + : undefined if (!builderFn) { throw new Error("Service name unknown - middleware inactive.") } diff --git a/packages/backend-core/src/users/db.ts b/packages/backend-core/src/users/db.ts index 14140cba81..c288540f35 100644 --- a/packages/backend-core/src/users/db.ts +++ b/packages/backend-core/src/users/db.ts @@ -20,6 +20,8 @@ import { SaveUserOpts, User, UserStatus, + UserGroup, + ContextUser, } from "@budibase/types" import { getAccountHolderFromUserIds, @@ -32,8 +34,14 @@ import { hash } from "../utils" type QuotaUpdateFn = (change: number, cb?: () => Promise) => Promise type GroupUpdateFn = (groupId: string, userIds: string[]) => Promise type FeatureFn = () => Promise +type GroupGetFn = (ids: string[]) => Promise +type GroupBuildersFn = (user: User) => Promise type QuotaFns = { addUsers: QuotaUpdateFn; removeUsers: QuotaUpdateFn } -type GroupFns = { addUsers: GroupUpdateFn } +type GroupFns = { + addUsers: GroupUpdateFn + getBulk: GroupGetFn + getGroupBuilderAppIds: GroupBuildersFn +} type FeatureFns = { isSSOEnforced: FeatureFn; isAppBuildersEnabled: FeatureFn } const bulkDeleteProcessing = async (dbUser: User) => { @@ -465,4 +473,12 @@ export class UserDB { await cache.user.invalidateUser(userId) await sessions.invalidateSessions(userId, { reason: "deletion" }) } + + static async getGroups(groupIds: string[]) { + return await this.groups.getBulk(groupIds) + } + + static async getGroupBuilderAppIds(user: User) { + return await this.groups.getGroupBuilderAppIds(user) + } } diff --git a/packages/server/src/utilities/global.ts b/packages/server/src/utilities/global.ts index 1cb7956d5e..5aa201990c 100644 --- a/packages/server/src/utilities/global.ts +++ b/packages/server/src/utilities/global.ts @@ -38,7 +38,8 @@ export async function processUser( : await groups.getBulk(user.userGroups) } // check if a group provides builder access - const builderAppIds = await groups.getGroupBuilderAppIds(user, appId, { + const builderAppIds = await groups.getGroupBuilderAppIds(user, { + appId, groups: groupList, }) if (builderAppIds.length && !users.isBuilder(user, appId)) { From a54c5b7222edc4b5cc75f6ec901f2eacd99ddcb6 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 23 Aug 2023 10:27:56 +0100 Subject: [PATCH 099/138] Add resizable screen/component sections and remove redundant /components route --- .../src/builderStore/store/frontend.js | 2 +- .../Component/ComponentInfoSection.svelte | 0 .../Component/ComponentSettingsPanel.svelte | 0 .../Component/ComponentSettingsSection.svelte | 0 .../Component/ConditionalUIDrawer.svelte | 0 .../Component/ConditionalUISection.svelte | 0 .../Component/CustomStylesSection.svelte | 0 .../Component/DesignSection.svelte | 0 .../_components/Component/StyleSection.svelte | 0 .../_components/Component/componentStyles.js | 0 .../_components/Navigation/LinksDrawer.svelte | 0 .../_components/Navigation/LinksEditor.svelte | 0 .../_components/Navigation/index.svelte | 0 .../_components/Screen/SettingsPanel.svelte | 0 .../[componentId]/_layout.svelte | 0 .../[screenId]/[componentId]/index.svelte | 1 + .../new/_components/NewComponentPanel.svelte | 2 +- .../new/_components/componentStructure.json | 0 .../[componentId]/new/index.svelte | 0 .../[screenId]/_components/AppPanel.svelte | 4 +- .../[screenId]/_components/AppPreview.svelte | 8 +- .../ComponentDropdownMenu.svelte | 0 .../ComponentList}/ComponentKeyHandler.svelte | 0 .../ComponentScrollWrapper.svelte | 0 .../ComponentList}/ComponentTree.svelte | 0 .../DNDPositionIndicator.svelte | 0 .../ScreenslotDropdownMenu.svelte | 0 .../ComponentList}/dndStore.js | 0 .../ComponentList}/index.svelte | 10 +- .../[screenId]/_components/LeftPanel.svelte | 24 ++++ .../ScreenList}/DropdownMenu.svelte | 0 .../ScreenList}/RoleIndicator.svelte | 0 .../ScreenList}/index.svelte | 106 +++++++++++++----- .../design/[screenId]/_layout.svelte | 2 +- .../_components/LeftPanel/index.svelte | 28 ----- .../components/[componentId]/index.svelte | 4 - .../design/[screenId]/components/index.svelte | 8 -- .../design/[screenId]/index.svelte | 5 +- .../app/[application]/design/index.svelte | 2 +- 39 files changed, 117 insertions(+), 89 deletions(-) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components => }/[componentId]/_components/Component/ComponentInfoSection.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components => }/[componentId]/_components/Component/ComponentSettingsPanel.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components => }/[componentId]/_components/Component/ComponentSettingsSection.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components => }/[componentId]/_components/Component/ConditionalUIDrawer.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components => }/[componentId]/_components/Component/ConditionalUISection.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components => }/[componentId]/_components/Component/CustomStylesSection.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components => }/[componentId]/_components/Component/DesignSection.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components => }/[componentId]/_components/Component/StyleSection.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components => }/[componentId]/_components/Component/componentStyles.js (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components => }/[componentId]/_components/Navigation/LinksDrawer.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components => }/[componentId]/_components/Navigation/LinksEditor.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components => }/[componentId]/_components/Navigation/index.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components => }/[componentId]/_components/Screen/SettingsPanel.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components => }/[componentId]/_layout.svelte (100%) create mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/index.svelte rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components => }/[componentId]/new/_components/NewComponentPanel.svelte (99%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components => }/[componentId]/new/_components/componentStructure.json (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components => }/[componentId]/new/index.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components/[componentId]/_components/LeftPanel/Components => _components/ComponentList}/ComponentDropdownMenu.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components/[componentId]/_components/LeftPanel/Components => _components/ComponentList}/ComponentKeyHandler.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components/[componentId]/_components/LeftPanel/Components => _components/ComponentList}/ComponentScrollWrapper.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components/[componentId]/_components/LeftPanel/Components => _components/ComponentList}/ComponentTree.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components/[componentId]/_components/LeftPanel/Components => _components/ComponentList}/DNDPositionIndicator.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components/[componentId]/_components/LeftPanel/Components => _components/ComponentList}/ScreenslotDropdownMenu.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components/[componentId]/_components/LeftPanel/Components => _components/ComponentList}/dndStore.js (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components/[componentId]/_components/LeftPanel/Components => _components/ComponentList}/index.svelte (96%) create mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/LeftPanel.svelte rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components/[componentId]/_components/LeftPanel/Screens => _components/ScreenList}/DropdownMenu.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components/[componentId]/_components/LeftPanel/Screens => _components/ScreenList}/RoleIndicator.svelte (100%) rename packages/builder/src/pages/builder/app/[application]/design/[screenId]/{components/[componentId]/_components/LeftPanel/Screens => _components/ScreenList}/index.svelte (70%) delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/index.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/index.svelte delete mode 100644 packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/index.svelte diff --git a/packages/builder/src/builderStore/store/frontend.js b/packages/builder/src/builderStore/store/frontend.js index 164fda4440..46b4bab6c0 100644 --- a/packages/builder/src/builderStore/store/frontend.js +++ b/packages/builder/src/builderStore/store/frontend.js @@ -225,7 +225,7 @@ export const getFrontendStore = () => { // Select new screen store.update(state => { state.selectedScreenId = screen._id - state.selectedComponentId = screen.props?._id + state.selectedComponentId = "screen" return state }) }, diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Component/ComponentInfoSection.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentInfoSection.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Component/ComponentInfoSection.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentInfoSection.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Component/ComponentSettingsPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsPanel.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Component/ComponentSettingsPanel.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsPanel.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Component/ComponentSettingsSection.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Component/ComponentSettingsSection.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ComponentSettingsSection.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Component/ConditionalUIDrawer.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ConditionalUIDrawer.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Component/ConditionalUIDrawer.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ConditionalUIDrawer.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Component/ConditionalUISection.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ConditionalUISection.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Component/ConditionalUISection.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/ConditionalUISection.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Component/CustomStylesSection.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/CustomStylesSection.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Component/CustomStylesSection.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/CustomStylesSection.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Component/DesignSection.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/DesignSection.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Component/DesignSection.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/DesignSection.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Component/StyleSection.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/StyleSection.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Component/StyleSection.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/StyleSection.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Component/componentStyles.js b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/componentStyles.js similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Component/componentStyles.js rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Component/componentStyles.js diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Navigation/LinksDrawer.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Navigation/LinksDrawer.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Navigation/LinksDrawer.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Navigation/LinksDrawer.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Navigation/LinksEditor.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Navigation/LinksEditor.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Navigation/LinksEditor.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Navigation/LinksEditor.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Navigation/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Navigation/index.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Navigation/index.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Navigation/index.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Screen/SettingsPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/SettingsPanel.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/Screen/SettingsPanel.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/SettingsPanel.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_layout.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_layout.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_layout.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/index.svelte new file mode 100644 index 0000000000..0ff63d1ead --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/index.svelte @@ -0,0 +1 @@ + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/new/_components/NewComponentPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/new/_components/NewComponentPanel.svelte similarity index 99% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/new/_components/NewComponentPanel.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/new/_components/NewComponentPanel.svelte index 7dca5b792b..4500723027 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/new/_components/NewComponentPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/new/_components/NewComponentPanel.svelte @@ -1,6 +1,6 @@ diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/LeftPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/LeftPanel.svelte new file mode 100644 index 0000000000..32150ef921 --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/LeftPanel.svelte @@ -0,0 +1,24 @@ + + +
+ + {#if $isActive("./:componentId")} + + {/if} +
+ + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/Screens/DropdownMenu.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/DropdownMenu.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/Screens/DropdownMenu.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/DropdownMenu.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/Screens/RoleIndicator.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/RoleIndicator.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/Screens/RoleIndicator.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/RoleIndicator.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/Screens/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte similarity index 70% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/Screens/index.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte index c11e933624..9324b2073d 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/Screens/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte @@ -9,29 +9,42 @@ let newScreen = false let search = false + let resizing = false let searchValue = "" let searchInput let screensContainer let scrolling = false + let height = "210px" + let previousHeight = null + let dragOffset $: filteredScreens = getFilteredScreens($sortedScreens, searchValue) + const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)) + const openSearch = async () => { search = true await tick() searchInput.focus() screensContainer.scroll({ top: 0, behavior: "smooth" }) + previousHeight = height + height = "calc(100% + 1px)" } - const closeSearch = () => { + const closeSearch = async () => { + if (previousHeight) { + // Restore previous height and wait for animation + height = previousHeight + previousHeight = null + await sleep(300) + } search = false searchValue = "" } const getFilteredScreens = (screens, search) => { return screens.filter(screen => { - const searchMatch = !search || screen.routing.route.includes(search) - return searchMatch + return !search || screen.routing.route.includes(search) }) } @@ -54,17 +67,33 @@ } const handleScroll = e => { - if (e.target.scrollTop === 0) { - scrolling = false - } else { - scrolling = true + scrolling = e.target.scrollTop !== 0 + } + + const startResizing = e => { + resizing = true + dragOffset = parseInt(height) - e.clientY + document.addEventListener("mousemove", resize) + document.addEventListener("mouseup", stopResizing) + } + + const resize = e => { + const newHeight = Math.max(0, e.clientY + dragOffset) + if (newHeight == null || isNaN(newHeight)) { + return } + height = `${newHeight}px` + } + + const stopResizing = () => { + resizing = false + document.removeEventListener("mousemove", resize) } -
-
+
+
{/if}
+ +
@@ -129,20 +160,24 @@ z-index: 2; background-color: var(--background); } - .newScreenVisible { display: initial; } .screens { - height: 210px; display: flex; flex-direction: column; - transition: height 300ms ease-out; + min-height: 147px; + max-height: calc(100% - 147px); + position: relative; } - - .screenSearch { - height: 100%; + .screens.search { + transition: height 300ms ease-out; + max-height: none; + } + .screens.resizing { + user-select: none; + cursor: row-resize; } .header { @@ -154,11 +189,10 @@ display: flex; align-items: center; border-bottom: 2px solid transparent; - transition: border-bottom 300ms ease-out; + transition: border-bottom 130ms ease-out; } - - .headerScrolling { - border-bottom: 2px solid var(--grey-2); + .header.scrolling { + border-bottom: var(--border-light); } .input { @@ -178,8 +212,7 @@ .input::placeholder { color: var(--spectrum-global-color-gray-600); } - - .screenSearch input { + .screens.search input { display: block; } @@ -197,6 +230,9 @@ overflow: auto; flex-grow: 1; } + .screens.resizing .content { + pointer-events: none; + } .screens :global(.nav-item) { padding-right: 8px !important; @@ -208,7 +244,6 @@ margin-right: 10px; opacity: 1; } - .searchButton:hover { color: var(--ink); } @@ -223,15 +258,14 @@ cursor: pointer; transition: transform 300ms ease-out; } + .addButton:hover { + color: var(--ink); + } .closeButton { transform: rotate(45deg); } - .addButton:hover { - color: var(--ink); - } - .icon { margin-left: 4px; margin-right: 4px; @@ -240,4 +274,24 @@ .no-results { color: var(--spectrum-global-color-gray-600); } + + .divider { + position: absolute; + bottom: 0; + transform: translateY(50%); + height: 16px; + width: 100%; + } + .divider:after { + content: ""; + position: absolute; + background: var(--spectrum-global-color-gray-200); + height: 2px; + width: 100%; + top: 50%; + transform: translateY(-50%); + } + .divider:hover { + cursor: row-resize; + } diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte index 8471cc03ed..61514270e6 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_layout.svelte @@ -4,7 +4,7 @@ import { syncURLToState } from "helpers/urlStateSync" import { store } from "builderStore" import { onDestroy } from "svelte" - import LeftPanel from "./components/[componentId]/_components/LeftPanel/index.svelte" + import LeftPanel from "./_components/LeftPanel.svelte" $: screenId = $store.selectedScreenId $: store.actions.websocket.selectResource(screenId) diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/index.svelte deleted file mode 100644 index c1fe15f625..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/_components/LeftPanel/index.svelte +++ /dev/null @@ -1,28 +0,0 @@ - - -
- -
- {#if $selectedScreen} - - {/if} -
- - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/index.svelte deleted file mode 100644 index 9b5d05fe57..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/[componentId]/index.svelte +++ /dev/null @@ -1,4 +0,0 @@ - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/index.svelte deleted file mode 100644 index 9361415cb7..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/components/index.svelte +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/index.svelte index 496467c546..c3951eab5d 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/index.svelte @@ -1,8 +1,5 @@ diff --git a/packages/builder/src/pages/builder/app/[application]/design/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/index.svelte index 470c81b88c..79d264d120 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/index.svelte @@ -4,7 +4,7 @@ $: { if ($frontendStore.screens.length > 0) { - $redirect(`./${$frontendStore.screens[0]._id}/components/screen`) + $redirect(`./${$frontendStore.screens[0]._id}/screen`) } else { $redirect("./new") } From d486a89ee786b0312de5e5031b8401f1c90632a1 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 23 Aug 2023 10:32:24 +0100 Subject: [PATCH 100/138] Clean all URLs by default in URL state sync --- packages/builder/src/helpers/urlStateSync.js | 4 ++++ .../design/[screenId]/[componentId]/_layout.svelte | 10 +++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/builder/src/helpers/urlStateSync.js b/packages/builder/src/helpers/urlStateSync.js index c4c48fb3fb..04c639b3ec 100644 --- a/packages/builder/src/helpers/urlStateSync.js +++ b/packages/builder/src/helpers/urlStateSync.js @@ -65,6 +65,10 @@ export const syncURLToState = options => { params = res.params } } + // Clean URL + if (url?.endsWith("/index")) { + url = url.replace("/index", "") + } log("Navigating to", url, "with params", params) cachedGoto(url, params) } diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_layout.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_layout.svelte index 51c3c64321..932a3d360a 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_layout.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_layout.svelte @@ -13,12 +13,8 @@ $: params = routify.params $: routeComponentId = $params.componentId - const cleanUrl = url => { - // Strip trailing slashes - if (url?.endsWith("/index")) { - url = url.replace("/index", "") - } - // Hide new component panel whenever component ID changes + // Hide new component panel whenever component ID changes + const closeNewComponentPanel = url => { if (url?.endsWith("/new")) { url = url.replace("/new", "") } @@ -40,7 +36,7 @@ fallbackUrl: "../", store, routify, - beforeNavigate: cleanUrl, + beforeNavigate: closeNewComponentPanel, }) onDestroy(stopSyncing) From f72f3f88f7a8dff5749d4e2156c900af7114b02e Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 23 Aug 2023 10:49:48 +0100 Subject: [PATCH 101/138] Improve UX when resizing screen/component lists --- packages/builder/src/builderStore/index.js | 4 +- .../_components/ScreenList/index.svelte | 49 +++++++++++++++---- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/packages/builder/src/builderStore/index.js b/packages/builder/src/builderStore/index.js index 3cd387fe95..dfb8609e65 100644 --- a/packages/builder/src/builderStore/index.js +++ b/packages/builder/src/builderStore/index.js @@ -4,7 +4,7 @@ import { getTemporalStore } from "./store/temporal" import { getThemeStore } from "./store/theme" import { getUserStore } from "./store/users" import { getDeploymentStore } from "./store/deployments" -import { derived } from "svelte/store" +import { derived, writable } from "svelte/store" import { findComponent, findComponentPath } from "./componentUtils" import { RoleUtils } from "@budibase/frontend-core" import { createHistoryStore } from "builderStore/store/history" @@ -147,3 +147,5 @@ export const userSelectedResourceMap = derived(userStore, $userStore => { export const isOnlyUser = derived(userStore, $userStore => { return $userStore.length < 2 }) + +export const screensHeight = writable("210px") diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte index 9324b2073d..0ecc9b76bf 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte @@ -1,20 +1,25 @@ -
+
-
+
screensHeight.set("210px")} + />
From 607a36e2e4822bb91f30578d61196a8a1c1a14b6 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 23 Aug 2023 11:03:00 +0100 Subject: [PATCH 102/138] Improve route handling when creating new components and screens --- .../design/NewScreen/CreateScreenModal.svelte | 3 ++- packages/builder/src/helpers/urlStateSync.js | 9 +++++---- .../[screenId]/_components/LeftPanel.svelte | 4 ++-- .../_components/ScreenList/index.svelte | 16 +++++++++++++++- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/packages/builder/src/components/design/NewScreen/CreateScreenModal.svelte b/packages/builder/src/components/design/NewScreen/CreateScreenModal.svelte index 3ca3e6b419..300906eaf6 100644 --- a/packages/builder/src/components/design/NewScreen/CreateScreenModal.svelte +++ b/packages/builder/src/components/design/NewScreen/CreateScreenModal.svelte @@ -67,7 +67,8 @@ } } - $goto(`./${screenId}`) + // Select and go to new screen + store.actions.screens.select(screenId) } catch (error) { console.log(error) notifications.error("Error creating screens") diff --git a/packages/builder/src/helpers/urlStateSync.js b/packages/builder/src/helpers/urlStateSync.js index 04c639b3ec..2408dde2f1 100644 --- a/packages/builder/src/helpers/urlStateSync.js +++ b/packages/builder/src/helpers/urlStateSync.js @@ -56,6 +56,11 @@ export const syncURLToState = options => { // Navigate to a certain URL const gotoUrl = (url, params) => { + // Clean URL + if (url?.endsWith("/index")) { + url = url.replace("/index", "") + } + // Allow custom URL handling if (beforeNavigate) { const res = beforeNavigate(url, params) if (res?.url) { @@ -65,10 +70,6 @@ export const syncURLToState = options => { params = res.params } } - // Clean URL - if (url?.endsWith("/index")) { - url = url.replace("/index", "") - } log("Navigating to", url, "with params", params) cachedGoto(url, params) } diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/LeftPanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/LeftPanel.svelte index 32150ef921..977d0ff0a9 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/LeftPanel.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/LeftPanel.svelte @@ -1,12 +1,12 @@
- {#if $isActive("./:componentId")} + {#if $selectedScreen} {/if}
diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte index 0ecc9b76bf..b4a97fbf09 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/_components/ScreenList/index.svelte @@ -11,6 +11,7 @@ import DropdownMenu from "./DropdownMenu.svelte" import NewScreen from "components/design/NewScreen/index.svelte" import { onMount, tick } from "svelte" + import { beforeUrlChange } from "@roxi/routify" let newScreen = false let search = false @@ -25,6 +26,14 @@ $: filteredScreens = getFilteredScreens($sortedScreens, searchValue) + // Close new screen when URL changes + $beforeUrlChange(() => { + if (newScreen) { + newScreen = false + } + return true + }) + const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)) const openSearch = async () => { @@ -176,7 +185,12 @@
- (newScreen = false)} /> + { + console.log("close") + newScreen = false + }} + />
diff --git a/packages/builder/src/components/design/RightPanel.svelte b/packages/builder/src/components/design/RightPanel.svelte deleted file mode 100644 index f9075600f9..0000000000 --- a/packages/builder/src/components/design/RightPanel.svelte +++ /dev/null @@ -1,112 +0,0 @@ - - -
-
-
- -
- {title} -
-
- {#each Object.entries(panes) as [id, pane]} -
- -
- {/each} -
-
- - -
- - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/theme/AppThemeSelect.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/AppThemeSelect.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/theme/AppThemeSelect.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/AppThemeSelect.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/theme/ButtonRoundnessSelect.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/ButtonRoundnessSelect.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/theme/ButtonRoundnessSelect.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/ButtonRoundnessSelect.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPane.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte similarity index 78% rename from packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPane.svelte rename to packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte index e6200272be..a08ded8eee 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPane.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/GeneralPanel.svelte @@ -1,10 +1,8 @@ - - - {#if $selectedScreen.layoutId} - - This screen uses a custom layout, which is deprecated - - {/if} - {#each screenSettings as setting (setting.key)} - setScreenSetting(setting, val)} - props={{ ...setting.props, error: errors[setting.key] }} - {bindings} - /> - {/each} - - +{#if $selectedScreen.layoutId} + + This screen uses a custom layout, which is deprecated + +{/if} +{#each screenSettings as setting (setting.key)} + setScreenSetting(setting, val)} + props={{ ...setting.props, error: errors[setting.key] }} + {bindings} + /> +{/each} diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/ThemePane.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/ThemePane.svelte deleted file mode 100644 index 20d5054648..0000000000 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/ThemePane.svelte +++ /dev/null @@ -1,98 +0,0 @@ - - - -
-
- - CHANGES WILL APPLY TO ALL SCREENS -
- - Your theme is configured for all the screens within your app. - -
- - - - - - - update("buttonBorderRadius", e.detail)} - /> - - update("primaryColor", val)} - props={{ - spectrumTheme: $store.theme, - }} - /> - update("primaryColorHover", val)} - props={{ - spectrumTheme: $store.theme, - }} - /> - -
- - - diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/ThemePanel.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/ThemePanel.svelte new file mode 100644 index 0000000000..f3f2e63cce --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/ThemePanel.svelte @@ -0,0 +1,93 @@ + + +
+
+ + CHANGES WILL APPLY TO ALL SCREENS +
+ + Your theme is configured for all the screens within your app. + +
+ + + + + + + update("buttonBorderRadius", e.detail)} + /> + + update("primaryColor", val)} + props={{ + spectrumTheme: $store.theme, + }} + /> + update("primaryColorHover", val)} + props={{ + spectrumTheme: $store.theme, + }} + /> + + + + diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/index.svelte index 554527ca4a..d9c98bda66 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Screen/index.svelte @@ -1,15 +1,51 @@ - - - - +
+
+ {#each tabs as tab} + { + activeTab = tab + }} + > + {capitalise(tab)} + + {/each} +
+
+ + {#if activeTab === "theme"} + + {:else} + + {/if} + + + + From 07e49f44366ff9e14b6794a58649b0b89b43f582 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 23 Aug 2023 16:46:32 +0100 Subject: [PATCH 129/138] Standardise info boxes between theme and navigation --- .../_components/Navigation/index.svelte | 22 ++++--------- .../_components/Screen/ThemePanel.svelte | 33 +++++-------------- .../_components/Screen/index.svelte | 4 +-- 3 files changed, 17 insertions(+), 42 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Navigation/index.svelte b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Navigation/index.svelte index 97622098cd..383026c4f8 100644 --- a/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Navigation/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/design/[screenId]/[componentId]/_components/Navigation/index.svelte @@ -64,10 +64,8 @@ Customize
-
- - These settings apply to all screens -
+ + These settings apply to all screens