-
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}
+
- openApp(app)} size="S" secondary>Open
+
+ {#if app.deployed}Published{:else}Unpublished{/if}
+
+
+
+
editApp(app)}
+ size="S"
+ secondary>Open
- 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 && $apps.length}
+ {#if loaded && enrichedApps.length}
- {#each $apps as app, idx (app.appId)}
+ {#each enrichedApps as app, idx (app.appId)}
{/each}
{/if}
- {#if !$apps.length && !creatingApp && loaded}
+ {#if !enrichedApps.length && !creatingApp && loaded}
- Are you sure you want to delete the app {appToDelete?.name} ?
+ Are you sure you want to delete the app {selectedApp?.name} ?
+
+
+ Are you sure you want to unpublish the app {selectedApp?.name} ?