Update apps list page and app rows to match new styles and behaviours

This commit is contained in:
Andrew Kingston 2022-06-10 12:16:28 +01:00
parent 4219b2251a
commit 3a33f5b376
3 changed files with 20 additions and 180 deletions

View File

@ -87,7 +87,7 @@
{#if lockedByYou && getExpiryDuration(app) > 0} {#if lockedByYou && getExpiryDuration(app) > 0}
<span class="lock-expiry-body"> <span class="lock-expiry-body">
{processStringSync( {processStringSync(
"This lock will expire in {{ duration time 'millisecond' }} from now", "This lock will expire in {{ duration time 'millisecond' }} from now.",
{ {
time: getExpiryDuration(app), time: getExpiryDuration(app),
} }
@ -141,4 +141,8 @@
gap: var(--spacing-s); gap: var(--spacing-s);
max-width: 175px; max-width: 175px;
} }
.lock-status-text {
font-weight: 400;
color: var(--spectrum-global-color-gray-800);
}
</style> </style>

View File

@ -1,18 +1,11 @@
<script> <script>
import { Heading, Button, Icon, ActionMenu, MenuItem } from "@budibase/bbui" import { Heading, Button, Icon } from "@budibase/bbui"
import AppLockModal from "../common/AppLockModal.svelte" import AppLockModal from "../common/AppLockModal.svelte"
import { processStringSync } from "@budibase/string-templates" import { processStringSync } from "@budibase/string-templates"
export let app export let app
export let exportApp
export let editApp export let editApp
export let updateApp
export let deleteApp
export let unpublishApp
export let appOverview export let appOverview
export let releaseLock
export let editIcon
export let copyAppId
</script> </script>
<div class="title" data-cy={`${app.devId}`}> <div class="title" data-cy={`${app.devId}`}>
@ -20,7 +13,7 @@
<div class="app-icon" style="color: {app.icon?.color || ''}"> <div class="app-icon" style="color: {app.icon?.color || ''}">
<Icon size="XL" name={app.icon?.name || "Apps"} /> <Icon size="XL" name={app.icon?.name || "Apps"} />
</div> </div>
<div class="name" data-cy="app-name-link" on:click={() => appOverview(app)}> <div class="name" data-cy="app-name-link" on:click={() => editApp(app)}>
<Heading size="XS"> <Heading size="XS">
{app.name} {app.name}
</Heading> </Heading>
@ -37,7 +30,7 @@
{/if} {/if}
</div> </div>
<div class="desktop"> <div class="desktop">
<AppLockModal {app} buttonSize="S" /> <AppLockModal {app} buttonSize="M" />
</div> </div>
<div class="desktop"> <div class="desktop">
<div class="app-status"> <div class="app-status">
@ -52,47 +45,27 @@
</div> </div>
<div data-cy={`row_actions_${app.appId}`}> <div data-cy={`row_actions_${app.appId}`}>
<div class="app-row-actions"> <div class="app-row-actions">
<Button size="S" secondary newStyles on:click={() => appOverview(app)}>
Manage
</Button>
<Button <Button
size="S" size="S"
secondary primary
quiet newStyles
disabled={app.lockedOther} disabled={app.lockedOther}
on:click={() => editApp(app)} on:click={() => editApp(app)}
>Edit >
Edit
</Button> </Button>
<Button size="S" cta on:click={() => appOverview(app)}>View</Button>
</div> </div>
<ActionMenu align="right" dataCy="app-row-actions-menu-popover">
<span slot="control" class="app-row-actions-icon">
<Icon hoverable name="More" />
</span>
{#if app.lockedYou}
<MenuItem on:click={() => releaseLock(app)} icon="LockOpen">
Release lock
</MenuItem>
{/if}
<MenuItem on:click={() => exportApp(app)} icon="Download">Export</MenuItem>
{#if app.deployed}
<MenuItem on:click={() => unpublishApp(app)} icon="GlobeRemove">
Unpublish
</MenuItem>
<MenuItem on:click={() => copyAppId(app)} icon="Copy">
Copy App ID
</MenuItem>
{/if}
{#if !app.deployed}
<MenuItem on:click={() => updateApp(app)} icon="Edit">Edit</MenuItem>
<MenuItem on:click={() => deleteApp(app)} icon="Delete">Delete</MenuItem>
{/if}
<MenuItem on:click={() => editIcon(app)} icon="Brush">Edit icon</MenuItem>
</ActionMenu>
</div> </div>
<style> <style>
.app-row-actions { .app-row-actions {
grid-gap: var(--spacing-s); grid-gap: var(--spacing-s);
display: grid; display: flex;
grid-template-columns: 75px 75px; flex-direction: row;
justify-content: flex-end;
} }
.app-status { .app-status {
display: grid; display: grid;

View File

@ -3,20 +3,17 @@
Heading, Heading,
Layout, Layout,
Button, Button,
Input,
Select, Select,
Modal, Modal,
Page, Page,
notifications, notifications,
Body, Body,
Search, Search,
Helpers,
} from "@budibase/bbui" } from "@budibase/bbui"
import TemplateDisplay from "components/common/TemplateDisplay.svelte" import TemplateDisplay from "components/common/TemplateDisplay.svelte"
import Spinner from "components/common/Spinner.svelte" import Spinner from "components/common/Spinner.svelte"
import CreateAppModal from "components/start/CreateAppModal.svelte" import CreateAppModal from "components/start/CreateAppModal.svelte"
import UpdateAppModal from "components/start/UpdateAppModal.svelte" import UpdateAppModal from "components/start/UpdateAppModal.svelte"
import ChooseIconModal from "components/start/ChooseIconModal.svelte"
import ExportAppModal from "components/start/ExportAppModal.svelte" import ExportAppModal from "components/start/ExportAppModal.svelte"
import { store, automationStore } from "builderStore" import { store, automationStore } from "builderStore"
@ -25,10 +22,9 @@
import { apps, auth, admin, templates } from "stores/portal" import { apps, auth, admin, templates } from "stores/portal"
import download from "downloadjs" import download from "downloadjs"
import { goto } from "@roxi/routify" import { goto } from "@roxi/routify"
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import AppRow from "components/start/AppRow.svelte" import AppRow from "components/start/AppRow.svelte"
import { AppStatus } from "constants" import { AppStatus } from "constants"
import analytics, { Events, EventSource } from "analytics" import analytics, { Events } from "analytics"
import Logo from "assets/bb-space-man.svg" import Logo from "assets/bb-space-man.svg"
let sortBy = "name" let sortBy = "name"
@ -36,15 +32,11 @@
let selectedApp let selectedApp
let creationModal let creationModal
let updatingModal let updatingModal
let deletionModal
let unpublishModal
let exportModal let exportModal
let iconModal
let creatingApp = false let creatingApp = false
let loaded = $apps?.length || $templates?.length let loaded = $apps?.length || $templates?.length
let searchTerm = "" let searchTerm = ""
let cloud = $admin.cloud let cloud = $admin.cloud
let appName = ""
let creatingFromTemplate = false let creatingFromTemplate = false
const resolveWelcomeMessage = (auth, apps) => { const resolveWelcomeMessage = (auth, apps) => {
@ -170,18 +162,6 @@
creatingApp = false 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 => { const appOverview = app => {
$goto(`../overview/${app.devId}`) $goto(`../overview/${app.devId}`)
} }
@ -196,79 +176,6 @@
$goto(`../../app/${app.devId}`) $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) { function createAppFromTemplateUrl(templateKey) {
// validate the template key just to make sure // validate the template key just to make sure
const templateParts = templateKey.split("/") const templateParts = templateKey.split("/")
@ -416,19 +323,7 @@
<div class="appTable" class:unlocked> <div class="appTable" class:unlocked>
{#each filteredApps as app (app.appId)} {#each filteredApps as app (app.appId)}
<AppRow <AppRow {app} {editApp} {appOverview} />
{copyAppId}
{releaseLock}
{editIcon}
{app}
{unpublishApp}
{viewApp}
{editApp}
{exportApp}
{deleteApp}
{updateApp}
{appOverview}
/>
{/each} {/each}
</div> </div>
</Layout> </Layout>
@ -462,35 +357,6 @@
<ExportAppModal app={selectedApp} /> <ExportAppModal app={selectedApp} />
</Modal> </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> <style>
.appTable { .appTable {
border-top: var(--border-light); border-top: var(--border-light);
@ -547,12 +413,9 @@
height: 70px; height: 70px;
display: grid; display: grid;
align-items: center; align-items: center;
grid-gap: var(--spacing-xl);
grid-template-columns: auto 1fr;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
padding: 0 var(--spacing-s);
} }
.appTable :global(> div) { .appTable :global(> div) {
border-bottom: var(--border-light); border-bottom: var(--border-light);