From 6cb13807703f8c359ae7c43f30529cd7b92fbe7e Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Wed, 19 May 2021 20:58:59 +0100 Subject: [PATCH 1/9] postgres connection pooling --- packages/bbui/src/Typography/Body.svelte | 2 +- packages/bbui/src/Typography/Heading.svelte | 2 +- .../src/components/login/ForgotForm.svelte | 8 ++++-- .../src/components/login/ResetForm.svelte | 5 ++-- packages/server/src/integrations/postgres.js | 28 +++++++++++++------ 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/packages/bbui/src/Typography/Body.svelte b/packages/bbui/src/Typography/Body.svelte index ec32e54140..13e83434e4 100644 --- a/packages/bbui/src/Typography/Body.svelte +++ b/packages/bbui/src/Typography/Body.svelte @@ -8,7 +8,7 @@

diff --git a/packages/builder/src/components/login/ForgotForm.svelte b/packages/builder/src/components/login/ForgotForm.svelte index afadf9f4cf..25d72228ef 100644 --- a/packages/builder/src/components/login/ForgotForm.svelte +++ b/packages/builder/src/components/login/ForgotForm.svelte @@ -30,12 +30,14 @@ Forgotten your password? - No problem! Just enter your account's email address and we'll send - you a link to reset it. + No problem! Just enter your account's email address and we'll send you + a link to reset it. - + diff --git a/packages/builder/src/components/login/ResetForm.svelte b/packages/builder/src/components/login/ResetForm.svelte index 4ae19b1ab1..83e9ab7a6e 100644 --- a/packages/builder/src/components/login/ResetForm.svelte +++ b/packages/builder/src/components/login/ResetForm.svelte @@ -16,7 +16,6 @@ } catch (err) { notifications.error("Unable to reset password") } - } @@ -33,7 +32,9 @@ - + diff --git a/packages/server/src/integrations/postgres.js b/packages/server/src/integrations/postgres.js index c6a24577b3..d567db7ba0 100644 --- a/packages/server/src/integrations/postgres.js +++ b/packages/server/src/integrations/postgres.js @@ -1,4 +1,6 @@ -const { Client } = require("pg") +const { Pool } = require("pg") + +let pool const SCHEMA = { docs: "https://node-postgres.com", @@ -51,31 +53,39 @@ const SCHEMA = { class PostgresIntegration { constructor(config) { this.config = config - this.client = new Client(config) - this.connect() + if (!pool) { + pool = new Pool(this.config) + } } - async connect() { - return this.client.connect() + async query(sql) { + try { + this.client = await pool.connect() + return await this.client.query(sql) + } catch (err) { + throw new Error(err) + } finally { + this.client.release() + } } async create({ sql }) { - const response = await this.client.query(sql) + const response = await this.query(sql) return response.rows.length ? response.rows : [{ created: true }] } async read({ sql }) { - const response = await this.client.query(sql) + const response = await this.query(sql) return response.rows } async update({ sql }) { - const response = await this.client.query(sql) + const response = await this.query(sql) return response.rows.length ? response.rows : [{ updated: true }] } async delete({ sql }) { - const response = await this.client.query(sql) + const response = await this.query(sql) return response.rows.length ? response.rows : [{ deleted: true }] } } From d30a9ef494b7e8ebd4ea84ee4ba0b3c1211f1808 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 21 May 2021 10:31:45 +0100 Subject: [PATCH 2/9] Add StatusLight and Badge components to BBUI --- packages/bbui/package.json | 3 +- packages/bbui/src/Badge/Badge.svelte | 27 ++++++++++++ .../bbui/src/StatusLight/StatusLight.svelte | 41 +++++++++++++++++++ packages/bbui/src/Tags/Tag.svelte | 9 ++++ packages/bbui/src/index.js | 2 + packages/bbui/yarn.lock | 7 +++- 6 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 packages/bbui/src/Badge/Badge.svelte create mode 100644 packages/bbui/src/StatusLight/StatusLight.svelte diff --git a/packages/bbui/package.json b/packages/bbui/package.json index c4c7e14b4b..3449931d12 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -52,7 +52,7 @@ "@spectrum-css/icon": "^3.0.1", "@spectrum-css/illustratedmessage": "^3.0.2", "@spectrum-css/inputgroup": "^3.0.2", - "@spectrum-css/label": "^2.0.9", + "@spectrum-css/label": "^2.0.10", "@spectrum-css/link": "^3.1.1", "@spectrum-css/menu": "^3.0.1", "@spectrum-css/modal": "^3.0.1", @@ -64,6 +64,7 @@ "@spectrum-css/radio": "^3.0.2", "@spectrum-css/search": "^3.0.2", "@spectrum-css/sidenav": "^3.0.2", + "@spectrum-css/statuslight": "^3.0.2", "@spectrum-css/switch": "^1.0.2", "@spectrum-css/table": "^3.0.1", "@spectrum-css/tabs": "^3.0.1", diff --git a/packages/bbui/src/Badge/Badge.svelte b/packages/bbui/src/Badge/Badge.svelte new file mode 100644 index 0000000000..737d4133d8 --- /dev/null +++ b/packages/bbui/src/Badge/Badge.svelte @@ -0,0 +1,27 @@ + + + + + diff --git a/packages/bbui/src/StatusLight/StatusLight.svelte b/packages/bbui/src/StatusLight/StatusLight.svelte new file mode 100644 index 0000000000..f56fee0c2a --- /dev/null +++ b/packages/bbui/src/StatusLight/StatusLight.svelte @@ -0,0 +1,41 @@ + + +
+ +
diff --git a/packages/bbui/src/Tags/Tag.svelte b/packages/bbui/src/Tags/Tag.svelte index 906065cc71..f7089decdb 100644 --- a/packages/bbui/src/Tags/Tag.svelte +++ b/packages/bbui/src/Tags/Tag.svelte @@ -1,6 +1,8 @@
-
openApp(app)}> + {#if app.lockedBy} + + {/if} +
editApp(app)}> {app.name}
- exportApp(app)} icon="Download"> - Export - - {#if deletable} + {#if app.deployed} + viewApp(app)} icon="GlobeOutline"> + View published app + + unpublishApp(app)} icon="GlobeRemove"> + Unpublish + + {/if} + {#if app.lockedBy && app.lockedBy?.email === $auth.user?.email} + releaseLock(app)} icon="LockOpen"> + Release lock + + {/if} + {#if !app.deployed} deleteApp(app)} icon="Delete"> Delete {/if} - {#if app.lockedBy && app.lockedBy?.email === $auth.user?.email} - releaseLock(app.appId)} icon="LockOpen"> - Release Lock - - {/if} + exportApp(app)} icon="Download"> + Export +
- Edited {Math.floor(1 + Math.random() * 10)} months ago + Updated {Math.floor(1 + Math.random() * 10)} months ago - {#if app.lockedBy} - - {/if} + + {#if app.deployed}Published{:else}Unpublished{/if} +
@@ -59,13 +73,17 @@ .wrapper { overflow: hidden; } + .wrapper :global(.spectrum-StatusLight) { + padding: 0; + min-height: 0; + } + .preview { height: 135px; border-radius: var(--border-radius-s); - margin-bottom: var(--spacing-s); + margin-bottom: var(--spacing-m); } - .title, .status { display: flex; flex-direction: row; @@ -74,12 +92,18 @@ } .name { - text-decoration: none; flex: 1 1 auto; - width: 0; - overflow: hidden; - text-overflow: ellipsis; - margin-right: var(--spacing-m); + } + + .title { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: flex-start; + gap: var(--spacing-m); + } + .title :global(.spectrum-Icon) { + flex: 0 0 auto; } .title :global(h1) { overflow: hidden; diff --git a/packages/builder/src/components/start/AppRow.svelte b/packages/builder/src/components/start/AppRow.svelte index bace5766d0..e5eaac98ba 100644 --- a/packages/builder/src/components/start/AppRow.svelte +++ b/packages/builder/src/components/start/AppRow.svelte @@ -1,55 +1,82 @@
-
openApp(app)}> +
editApp(app)}> {app.name}
- Edited {Math.round(Math.random() * 10 + 1)} months ago + Updated {Math.round(Math.random() * 10 + 1)} months ago
- {#if app.lockedBy} - {#if app.lockedBy.email === $auth.user.email} -
+ + {#if app.lockedYou} Locked by you - {:else} -
+ {:else if app.lockedOther} Locked by {app.lockedBy.email} + {:else} + Open {/if} - {:else} -
- Open - {/if} +
- + + {#if app.deployed}Published{:else}Unpublished{/if} + +
+
+ - exportApp(app)} icon="Download">Export - {#if deletable} - deleteApp(app)} icon="Delete">Delete - {/if} - {#if app.lockedBy && app.lockedBy?.email === $auth.user?.email} - releaseLock(app.appId)} icon="LockOpen"> - Release Lock + {#if app.deployed} + viewApp(app)} icon="GlobeOutline"> + View published app + + unpublishApp(app)} icon="GlobeRemove"> + Unpublish {/if} + {#if app.lockedBy && app.lockedBy?.email === $auth.user?.email} + releaseLock(app)} icon="LockOpen"> + Release lock + + {/if} + {#if !app.deployed} + deleteApp(app)} icon="Delete">Delete + {/if} + exportApp(app)} icon="Download">Export
@@ -61,24 +88,16 @@ } .name { text-decoration: none; + overflow: hidden; + } + .name :global(.spectrum-Heading) { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; } .title :global(h1:hover) { color: var(--spectrum-global-color-blue-600); cursor: pointer; transition: color 130ms ease; } - .status { - height: 10px; - width: 10px; - border-radius: 50%; - } - .status--locked-you { - background-color: var(--spectrum-global-color-orange-600); - } - .status--locked-other { - background-color: var(--spectrum-global-color-red-600); - } - .status--open { - background-color: var(--spectrum-global-color-green-600); - } diff --git a/packages/builder/src/constants/index.js b/packages/builder/src/constants/index.js index aa1ccd729b..8a0e8fd60e 100644 --- a/packages/builder/src/constants/index.js +++ b/packages/builder/src/constants/index.js @@ -10,8 +10,9 @@ export const FrontendTypes = { } export const AppStatus = { - DEV: "dev", - PUBLISHED: "published", + ALL: "all", + DEV: "development", + DEPLOYED: "published", } // fields on the user table that cannot be edited diff --git a/packages/builder/src/pages/builder/portal/_layout.svelte b/packages/builder/src/pages/builder/portal/_layout.svelte index b6bc1b07bf..bfb0e9606c 100644 --- a/packages/builder/src/pages/builder/portal/_layout.svelte +++ b/packages/builder/src/pages/builder/portal/_layout.svelte @@ -21,9 +21,7 @@ const menu = [ { title: "Apps", href: "/builder/portal/apps" }, - { title: "Drafts", href: "/builder/portal/drafts" }, { title: "Users", href: "/builder/portal/manage/users", heading: "Manage" }, - { title: "Groups", href: "/builder/portal/manage/groups" }, { title: "Auth", href: "/builder/portal/manage/auth" }, { title: "Email", href: "/builder/portal/manage/email" }, { diff --git a/packages/builder/src/pages/builder/portal/apps/index.svelte b/packages/builder/src/pages/builder/portal/apps/index.svelte index b8463730ec..13282f6d64 100644 --- a/packages/builder/src/pages/builder/portal/apps/index.svelte +++ b/packages/builder/src/pages/builder/portal/apps/index.svelte @@ -26,15 +26,39 @@ import { AppStatus } from "constants" let layout = "grid" - let appStatus = AppStatus.PUBLISHED + let sortBy = "name" let template - let appToDelete + let selectedApp let creationModal let deletionModal + let unpublishModal let creatingApp = false let loaded = false - $: appStatus && apps.load(appStatus) + $: enrichedApps = enrichApps($apps, $auth.user, sortBy) + + const enrichApps = (apps, user, sortBy) => { + const enrichedApps = apps.map(app => ({ + ...app, + deployed: app.status === AppStatus.DEPLOYED, + lockedYou: app.lockedBy?.email === user.email, + lockedOther: app.lockedBy && app.lockedBy.email !== user.email, + })) + if (sortBy === "status") { + return enrichedApps.sort((a, b) => { + if (a.status === b.status) { + return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1 + } + return a.status === AppStatus.DEPLOYED ? -1 : 1 + }) + } else if (sortBy === "name") { + return enrichedApps.sort((a, b) => { + return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1 + }) + } else { + return enrichedApps + } + } const checkKeys = async () => { const response = await api.get(`/api/keys/`) @@ -60,19 +84,19 @@ creatingApp = false } - const openApp = app => { - if (app.lockedBy && app.lockedBy?.email !== $auth.user?.email) { + const viewApp = app => { + const id = app.deployed ? app.prodId : app.devId + window.open(`/${id}`, "_blank") + } + + const editApp = app => { + if (app.lockedOther) { notifications.error( `App locked by ${app.lockedBy.email}. Please allow lock to expire or have them unlock this app.` ) return } - - if (appStatus === AppStatus.DEV) { - $goto(`../../app/${app.appId}`) - } else { - window.open(`/${app.appId}`, "_blank") - } + $goto(`../../app/${app.devId}`) } const exportApp = app => { @@ -82,36 +106,66 @@ app.name )}` ) - notifications.success("App export complete") + notifications.success("App exported successfully") } catch (err) { - console.error(err) - notifications.error("App export failed") + notifications.error(`Error exporting app: ${err}`) + } + } + + const unpublishApp = app => { + selectedApp = app + unpublishModal.show() + } + + const confirmUnpublishApp = async () => { + if (!selectedApp) { + return + } + try { + const response = await del(`/api/applications/${selectedApp.prodId}`) + if (response.status !== 200) { + const json = await response.json() + throw json.message + } + await apps.load() + notifications.success("App unpublished successfully") + } catch (err) { + notifications.error(`Error unpublishing app: ${err}`) } } const deleteApp = app => { - appToDelete = app + selectedApp = app deletionModal.show() } const confirmDeleteApp = async () => { - if (!appToDelete) { + if (!selectedApp) { return } - await del(`/api/applications/${appToDelete?.appId}`) - await apps.load() - appToDelete = null - notifications.success("App deleted successfully.") + try { + const response = await del(`/api/applications/${selectedApp?.devId}`) + if (response.status !== 200) { + const json = await response.json() + throw json.message + } + await apps.load() + notifications.success("App deleted successfully") + } catch (err) { + notifications.error(`Error deleting app: ${err}`) + } + selectedApp = null } - const releaseLock = async appId => { + const releaseLock = async app => { try { - const response = await del(`/api/dev/${appId}/lock`) - const json = await response.json() - if (response.status !== 200) throw json.message - - notifications.success("Lock released") - await apps.load(appStatus) + const response = await del(`/api/dev/${app.devId}/lock`) + if (response.status !== 200) { + const json = await response.json() + throw json.message + } + await apps.load() + notifications.success("Lock released successfully") } catch (err) { notifications.error(`Error releasing lock: ${err}`) } @@ -119,7 +173,7 @@ onMount(async () => { checkKeys() - await apps.load(appStatus) + await apps.load() loaded = true }) @@ -136,10 +190,12 @@
+ {#if loaded && enrichedApps.length} + +
+ Apps + + + + +
+
+
+ diff --git a/packages/builder/src/components/settings/ThemeEditorDropdown.svelte b/packages/builder/src/components/settings/ThemeEditorDropdown.svelte deleted file mode 100644 index 8e1a9a4601..0000000000 --- a/packages/builder/src/components/settings/ThemeEditorDropdown.svelte +++ /dev/null @@ -1,35 +0,0 @@ - - -
- -
- - - - - - - diff --git a/packages/builder/src/pages/builder/apps/_components/UpdateUserInfoModal.svelte b/packages/builder/src/components/settings/UpdateUserInfoModal.svelte similarity index 100% rename from packages/builder/src/pages/builder/apps/_components/UpdateUserInfoModal.svelte rename to packages/builder/src/components/settings/UpdateUserInfoModal.svelte diff --git a/packages/builder/src/components/start/BuilderSettingsModal.svelte b/packages/builder/src/components/start/BuilderSettingsModal.svelte deleted file mode 100644 index 3026dc62cc..0000000000 --- a/packages/builder/src/components/start/BuilderSettingsModal.svelte +++ /dev/null @@ -1,42 +0,0 @@ - - - - Theme - - - Analytics - - If you would like to send analytics that help us make budibase better, - please let us know below. - - - diff --git a/packages/builder/src/pages/builder/apps/index.svelte b/packages/builder/src/pages/builder/apps/index.svelte index cc10fc6e4a..c5a1218a63 100644 --- a/packages/builder/src/pages/builder/apps/index.svelte +++ b/packages/builder/src/pages/builder/apps/index.svelte @@ -17,8 +17,8 @@ import { goto } from "@roxi/routify" import { AppStatus } from "constants" import { gradient } from "actions" - import UpdateUserInfoModal from "./_components/UpdateUserInfoModal.svelte" - import ChangePasswordModal from "./_components/ChangePasswordModal.svelte" + import UpdateUserInfoModal from "components/settings/UpdateUserInfoModal.svelte" + import ChangePasswordModal from "components/settings/ChangePasswordModal.svelte" let loaded = false let userInfoModal @@ -31,10 +31,11 @@ }) -{#if loaded} +{#if $auth.user && loaded}
+ asdas
diff --git a/packages/builder/src/pages/builder/portal/_layout.svelte b/packages/builder/src/pages/builder/portal/_layout.svelte index bfb0e9606c..d1c9414f7f 100644 --- a/packages/builder/src/pages/builder/portal/_layout.svelte +++ b/packages/builder/src/pages/builder/portal/_layout.svelte @@ -13,11 +13,13 @@ } from "@budibase/bbui" import ConfigChecklist from "components/common/ConfigChecklist.svelte" import { organisation, auth } from "stores/portal" - import BuilderSettingsModal from "components/start/BuilderSettingsModal.svelte" import { onMount } from "svelte" + import UpdateUserInfoModal from "components/settings/UpdateUserInfoModal.svelte" + import ChangePasswordModal from "components/settings/ChangePasswordModal.svelte" - let oldSettingsModal let loaded = false + let userInfoModal + let changePasswordModal const menu = [ { title: "Apps", href: "/builder/portal/apps" }, @@ -25,12 +27,11 @@ { title: "Auth", href: "/builder/portal/manage/auth" }, { title: "Email", href: "/builder/portal/manage/email" }, { - title: "General", - href: "/builder/portal/settings/general", + title: "Organisation", + href: "/builder/portal/settings/organisation", heading: "Settings", }, - { title: "Theming", href: "/builder/portal/theming" }, - { title: "Account", href: "/builder/portal/account" }, + { title: "Theming", href: "/builder/portal/settings/theming" }, ] onMount(async () => { @@ -44,7 +45,7 @@ }) -{#if loaded} +{#if $auth.user && loaded}
- - Old settings + userInfoModal.show()}> + Update user information + + changePasswordModal.show()} + > + Update password $goto("../apps")}> Close developer mode @@ -91,8 +98,11 @@
- - + + + + + {/if} diff --git a/packages/builder/src/pages/builder/portal/settings/general.svelte b/packages/builder/src/pages/builder/portal/settings/organisation.svelte similarity index 94% rename from packages/builder/src/pages/builder/portal/settings/general.svelte rename to packages/builder/src/pages/builder/portal/settings/organisation.svelte index bfd6c57b8d..ec278fa0e4 100644 --- a/packages/builder/src/pages/builder/portal/settings/general.svelte +++ b/packages/builder/src/pages/builder/portal/settings/organisation.svelte @@ -66,10 +66,11 @@ - General + Organisation - General is the place where you edit your organisation name, logo. You can - also configure your platform URL as well as turn on or off analytics. + Organisation settings is where you can edit your organisation name and + logo. You can also configure your platform URL and enable or disable + analytics. diff --git a/packages/builder/src/pages/builder/portal/settings/theming.svelte b/packages/builder/src/pages/builder/portal/settings/theming.svelte new file mode 100644 index 0000000000..17b811b1fd --- /dev/null +++ b/packages/builder/src/pages/builder/portal/settings/theming.svelte @@ -0,0 +1,36 @@ + + + + + Theming + Customize how Budibase looks and feels. + + +
+
+ +