From f63f9a7c51bbc82a9db2b8791033f61c483b3ef8 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 21 May 2021 10:32:16 +0100 Subject: [PATCH] Update app list screen to show unified app list with publish status --- .../src/components/start/AppCard.svelte | 70 ++++++--- .../src/components/start/AppRow.svelte | 91 ++++++----- packages/builder/src/constants/index.js | 5 +- .../src/pages/builder/portal/_layout.svelte | 2 - .../pages/builder/portal/apps/index.svelte | 146 +++++++++++++----- packages/builder/src/stores/portal/apps.js | 40 ++++- packages/server/src/db/utils.js | 4 +- 7 files changed, 249 insertions(+), 109 deletions(-) diff --git a/packages/builder/src/components/start/AppCard.svelte b/packages/builder/src/components/start/AppCard.svelte index 55f4af8b0c..6f0dcdb640 100644 --- a/packages/builder/src/components/start/AppCard.svelte +++ b/packages/builder/src/components/start/AppCard.svelte @@ -6,51 +6,65 @@ Layout, ActionMenu, MenuItem, + StatusLight, } from "@budibase/bbui" import { gradient } from "actions" import { auth } from "stores/portal" + import { AppStatus } from "constants" export let app export let exportApp - export let openApp + export let viewApp + export let editApp export let deleteApp + export let unpublishApp export let releaseLock - export let deletable
-
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 @@