|
|
|
@ -3,20 +3,17 @@ |
|
|
|
Heading, |
|
|
|
Layout, |
|
|
|
Button, |
|
|
|
Input, |
|
|
|
Select, |
|
|
|
Modal, |
|
|
|
Page, |
|
|
|
notifications, |
|
|
|
Body, |
|
|
|
Search, |
|
|
|
Helpers, |
|
|
|
} from "@budibase/bbui" |
|
|
|
import TemplateDisplay from "components/common/TemplateDisplay.svelte" |
|
|
|
import Spinner from "components/common/Spinner.svelte" |
|
|
|
import CreateAppModal from "components/start/CreateAppModal.svelte" |
|
|
|
import UpdateAppModal from "components/start/UpdateAppModal.svelte" |
|
|
|
import ChooseIconModal from "components/start/ChooseIconModal.svelte" |
|
|
|
import ExportAppModal from "components/start/ExportAppModal.svelte" |
|
|
|
|
|
|
|
import { store, automationStore } from "builderStore" |
|
|
|
@ -25,10 +22,9 @@ |
|
|
|
import { apps, auth, admin, templates } from "stores/portal" |
|
|
|
import download from "downloadjs" |
|
|
|
import { goto } from "@roxi/routify" |
|
|
|
import ConfirmDialog from "components/common/ConfirmDialog.svelte" |
|
|
|
import AppRow from "components/start/AppRow.svelte" |
|
|
|
import { AppStatus } from "constants" |
|
|
|
import analytics, { Events, EventSource } from "analytics" |
|
|
|
import analytics, { Events } from "analytics" |
|
|
|
import Logo from "assets/bb-space-man.svg" |
|
|
|
|
|
|
|
let sortBy = "name" |
|
|
|
@ -36,15 +32,11 @@ |
|
|
|
let selectedApp |
|
|
|
let creationModal |
|
|
|
let updatingModal |
|
|
|
let deletionModal |
|
|
|
let unpublishModal |
|
|
|
let exportModal |
|
|
|
let iconModal |
|
|
|
let creatingApp = false |
|
|
|
let loaded = $apps?.length || $templates?.length |
|
|
|
let searchTerm = "" |
|
|
|
let cloud = $admin.cloud |
|
|
|
let appName = "" |
|
|
|
let creatingFromTemplate = false |
|
|
|
|
|
|
|
const resolveWelcomeMessage = (auth, apps) => { |
|
|
|
@ -170,18 +162,6 @@ |
|
|
|
creatingApp = false |
|
|
|
} |
|
|
|
|
|
|
|
const viewApp = app => { |
|
|
|
analytics.captureEvent(Events.APP.VIEW_PUBLISHED, { |
|
|
|
appId: app.appId, |
|
|
|
eventSource: EventSource.PORTAL, |
|
|
|
}) |
|
|
|
if (app.url) { |
|
|
|
window.open(`/app${app.url}`) |
|
|
|
} else { |
|
|
|
window.open(`/${app.prodId}`) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const appOverview = app => { |
|
|
|
$goto(`../overview/${app.devId}`) |
|
|
|
} |
|
|
|
@ -196,79 +176,6 @@ |
|
|
|
$goto(`../../app/${app.devId}`) |
|
|
|
} |
|
|
|
|
|
|
|
const editIcon = app => { |
|
|
|
selectedApp = app |
|
|
|
iconModal.show() |
|
|
|
} |
|
|
|
|
|
|
|
const exportApp = app => { |
|
|
|
exportModal.show() |
|
|
|
selectedApp = app |
|
|
|
} |
|
|
|
|
|
|
|
const unpublishApp = app => { |
|
|
|
selectedApp = app |
|
|
|
unpublishModal.show() |
|
|
|
} |
|
|
|
|
|
|
|
const confirmUnpublishApp = async () => { |
|
|
|
if (!selectedApp) { |
|
|
|
return |
|
|
|
} |
|
|
|
try { |
|
|
|
analytics.captureEvent(Events.APP.UNPUBLISHED, { |
|
|
|
appId: selectedApp.appId, |
|
|
|
}) |
|
|
|
await API.unpublishApp(selectedApp.prodId) |
|
|
|
await apps.load() |
|
|
|
notifications.success("App unpublished successfully") |
|
|
|
} catch (err) { |
|
|
|
notifications.error("Error unpublishing app") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const deleteApp = app => { |
|
|
|
selectedApp = app |
|
|
|
deletionModal.show() |
|
|
|
} |
|
|
|
|
|
|
|
const confirmDeleteApp = async () => { |
|
|
|
if (!selectedApp) { |
|
|
|
return |
|
|
|
} |
|
|
|
try { |
|
|
|
await API.deleteApp(selectedApp?.devId) |
|
|
|
await apps.load() |
|
|
|
// Get checklist, just in case that was the last app |
|
|
|
await admin.init() |
|
|
|
notifications.success("App deleted successfully") |
|
|
|
} catch (err) { |
|
|
|
notifications.error("Error deleting app") |
|
|
|
} |
|
|
|
selectedApp = null |
|
|
|
appName = null |
|
|
|
} |
|
|
|
|
|
|
|
const updateApp = async app => { |
|
|
|
selectedApp = app |
|
|
|
updatingModal.show() |
|
|
|
} |
|
|
|
|
|
|
|
const releaseLock = async app => { |
|
|
|
try { |
|
|
|
await API.releaseAppLock(app.devId) |
|
|
|
await apps.load() |
|
|
|
notifications.success("Lock released successfully") |
|
|
|
} catch (err) { |
|
|
|
notifications.error("Error releasing lock") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const copyAppId = async app => { |
|
|
|
await Helpers.copyToClipboard(app.prodId) |
|
|
|
notifications.success("App ID copied to clipboard.") |
|
|
|
} |
|
|
|
|
|
|
|
function createAppFromTemplateUrl(templateKey) { |
|
|
|
// validate the template key just to make sure |
|
|
|
const templateParts = templateKey.split("/") |
|
|
|
@ -416,19 +323,7 @@ |
|
|
|
|
|
|
|
<div class="appTable" class:unlocked> |
|
|
|
{#each filteredApps as app (app.appId)} |
|
|
|
<AppRow |
|
|
|
{copyAppId} |
|
|
|
{releaseLock} |
|
|
|
{editIcon} |
|
|
|
{app} |
|
|
|
{unpublishApp} |
|
|
|
{viewApp} |
|
|
|
{editApp} |
|
|
|
{exportApp} |
|
|
|
{deleteApp} |
|
|
|
{updateApp} |
|
|
|
{appOverview} |
|
|
|
/> |
|
|
|
<AppRow {app} {editApp} {appOverview} /> |
|
|
|
{/each} |
|
|
|
</div> |
|
|
|
</Layout> |
|
|
|
@ -462,35 +357,6 @@ |
|
|
|
<ExportAppModal app={selectedApp} /> |
|
|
|
</Modal> |
|
|
|
|
|
|
|
<ConfirmDialog |
|
|
|
bind:this={deletionModal} |
|
|
|
title="Confirm deletion" |
|
|
|
okText="Delete app" |
|
|
|
onOk={confirmDeleteApp} |
|
|
|
onCancel={() => (appName = null)} |
|
|
|
disabled={appName !== selectedApp?.name} |
|
|
|
> |
|
|
|
Are you sure you want to delete the app <b>{selectedApp?.name}</b>? |
|
|
|
|
|
|
|
<p>Please enter the app name below to confirm.</p> |
|
|
|
<Input |
|
|
|
bind:value={appName} |
|
|
|
data-cy="delete-app-confirmation" |
|
|
|
placeholder={selectedApp?.name} |
|
|
|
/> |
|
|
|
</ConfirmDialog> |
|
|
|
<ConfirmDialog |
|
|
|
bind:this={unpublishModal} |
|
|
|
title="Confirm unpublish" |
|
|
|
okText="Unpublish app" |
|
|
|
onOk={confirmUnpublishApp} |
|
|
|
dataCy={"unpublish-modal"} |
|
|
|
> |
|
|
|
Are you sure you want to unpublish the app <b>{selectedApp?.name}</b>? |
|
|
|
</ConfirmDialog> |
|
|
|
|
|
|
|
<ChooseIconModal app={selectedApp} bind:this={iconModal} /> |
|
|
|
|
|
|
|
<style> |
|
|
|
.appTable { |
|
|
|
border-top: var(--border-light); |
|
|
|
@ -547,12 +413,9 @@ |
|
|
|
height: 70px; |
|
|
|
display: grid; |
|
|
|
align-items: center; |
|
|
|
grid-gap: var(--spacing-xl); |
|
|
|
grid-template-columns: auto 1fr; |
|
|
|
white-space: nowrap; |
|
|
|
overflow: hidden; |
|
|
|
text-overflow: ellipsis; |
|
|
|
padding: 0 var(--spacing-s); |
|
|
|
} |
|
|
|
.appTable :global(> div) { |
|
|
|
border-bottom: var(--border-light); |
|
|
|
|