General tidying and refactoring. Updated the publish button behaviour to also take into account revert and version update behaviours.
This commit is contained in:
parent
c1248eed12
commit
602ea9bc4e
13 changed files with 159 additions and 36 deletions
|
@ -55,7 +55,7 @@
|
||||||
name: "Automations",
|
name: "Automations",
|
||||||
description: "",
|
description: "",
|
||||||
icon: "Compass",
|
icon: "Compass",
|
||||||
action: () => $goto("./automate"),
|
action: () => $goto("./automation"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "Publish",
|
type: "Publish",
|
||||||
|
@ -127,7 +127,7 @@
|
||||||
type: "Automation",
|
type: "Automation",
|
||||||
name: automation.name,
|
name: automation.name,
|
||||||
icon: "ShareAndroid",
|
icon: "ShareAndroid",
|
||||||
action: () => $goto(`./automate/${automation._id}`),
|
action: () => $goto(`./automation/${automation._id}`),
|
||||||
})),
|
})),
|
||||||
...Constants.Themes.map(theme => ({
|
...Constants.Themes.map(theme => ({
|
||||||
type: "Change Builder Theme",
|
type: "Change Builder Theme",
|
||||||
|
|
|
@ -24,12 +24,18 @@
|
||||||
import { onMount } from "svelte"
|
import { onMount } from "svelte"
|
||||||
import DeployModal from "components/deploy/DeployModal.svelte"
|
import DeployModal from "components/deploy/DeployModal.svelte"
|
||||||
import { apps } from "stores/portal"
|
import { apps } from "stores/portal"
|
||||||
import { store } from "builderStore"
|
import {
|
||||||
|
store,
|
||||||
|
screenHistoryStore,
|
||||||
|
automationHistoryStore,
|
||||||
|
} from "builderStore"
|
||||||
import TourWrap from "components/portal/onboarding/TourWrap.svelte"
|
import TourWrap from "components/portal/onboarding/TourWrap.svelte"
|
||||||
import { TOUR_STEP_KEYS } from "components/portal/onboarding/tours.js"
|
import { TOUR_STEP_KEYS } from "components/portal/onboarding/tours.js"
|
||||||
import { url, goto } from "@roxi/routify"
|
import { url, goto } from "@roxi/routify"
|
||||||
|
import { isEqual, cloneDeep } from "lodash"
|
||||||
|
|
||||||
export let application
|
export let application
|
||||||
|
export let loaded
|
||||||
|
|
||||||
let unpublishModal
|
let unpublishModal
|
||||||
let updateAppModal
|
let updateAppModal
|
||||||
|
@ -40,7 +46,7 @@
|
||||||
let appActionPopoverOpen = false
|
let appActionPopoverOpen = false
|
||||||
let appActionPopoverAnchor
|
let appActionPopoverAnchor
|
||||||
|
|
||||||
let publishing
|
let publishing = false
|
||||||
|
|
||||||
$: filteredApps = $apps.filter(app => app.devId === application)
|
$: filteredApps = $apps.filter(app => app.devId === application)
|
||||||
$: selectedApp = filteredApps?.length ? filteredApps[0] : null
|
$: selectedApp = filteredApps?.length ? filteredApps[0] : null
|
||||||
|
@ -58,6 +64,81 @@
|
||||||
$store.version &&
|
$store.version &&
|
||||||
$store.upgradableVersion !== $store.version
|
$store.upgradableVersion !== $store.version
|
||||||
|
|
||||||
|
let cachedVersion = $store.version + ""
|
||||||
|
let versionAltered = false
|
||||||
|
let screensAltered = false
|
||||||
|
let automationsAltered = false
|
||||||
|
|
||||||
|
let publishRecord = {
|
||||||
|
screenHistory: null,
|
||||||
|
automationHistory: null,
|
||||||
|
}
|
||||||
|
|
||||||
|
//Meta Changes
|
||||||
|
let appMeta = {}
|
||||||
|
let appMetaUpdated = false
|
||||||
|
let appMetaInitialised = false
|
||||||
|
|
||||||
|
const unsub = store.subscribe(state => {
|
||||||
|
let { name, url: appUrl, navigation, theme, customTheme, icon } = state
|
||||||
|
const update = {
|
||||||
|
name,
|
||||||
|
url: appUrl,
|
||||||
|
navigation: { ...cloneDeep(navigation) },
|
||||||
|
theme,
|
||||||
|
customTheme,
|
||||||
|
icon,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isEqual(update, appMeta)) {
|
||||||
|
if (!appMetaInitialised) {
|
||||||
|
appMetaInitialised = true
|
||||||
|
} else {
|
||||||
|
appMetaUpdated = true
|
||||||
|
}
|
||||||
|
appMeta = {
|
||||||
|
...(appMeta || {}),
|
||||||
|
...update,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const monitorHistoryStore = (historyStore, publishedHistoryId, cb) => {
|
||||||
|
if (!historyStore.history.length || historyStore.loading) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!historyStore.canUndo) {
|
||||||
|
cb(publishedHistoryId != -1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const historyEntry = historyStore.history[historyStore.position - 1]
|
||||||
|
|
||||||
|
if (historyEntry) {
|
||||||
|
cb(publishedHistoryId != historyEntry.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$: monitorHistoryStore(
|
||||||
|
$screenHistoryStore,
|
||||||
|
publishRecord.screenHistory,
|
||||||
|
updated => {
|
||||||
|
screensAltered = updated
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
$: monitorHistoryStore(
|
||||||
|
$automationHistoryStore,
|
||||||
|
publishRecord.automationHistory,
|
||||||
|
updated => {
|
||||||
|
automationsAltered = updated
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
$: versionAltered = cachedVersion != $store.version
|
||||||
|
$: altered =
|
||||||
|
screensAltered || appMetaUpdated || automationsAltered || versionAltered
|
||||||
|
$: canPublish = (!isPublished || altered) && !publishing && loaded
|
||||||
|
|
||||||
const initialiseApp = async () => {
|
const initialiseApp = async () => {
|
||||||
const applicationPkg = await API.fetchAppPackage($store.devId)
|
const applicationPkg = await API.fetchAppPackage($store.devId)
|
||||||
await store.actions.initialise(applicationPkg)
|
await store.actions.initialise(applicationPkg)
|
||||||
|
@ -112,6 +193,27 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const resetAppHistory = (historyStore, historyKey) => {
|
||||||
|
if (historyStore.history.length) {
|
||||||
|
const historyEntryPos = historyStore.position
|
||||||
|
const historyEntry = historyStore.history[historyEntryPos - 1]
|
||||||
|
|
||||||
|
publishRecord = {
|
||||||
|
...publishRecord,
|
||||||
|
[historyKey]: historyEntry?.id || -1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetStateTracking = () => {
|
||||||
|
resetAppHistory($automationHistoryStore, "automationHistory")
|
||||||
|
resetAppHistory($screenHistoryStore, "screenHistory")
|
||||||
|
automationsAltered = false
|
||||||
|
screensAltered = false
|
||||||
|
appMetaUpdated = false
|
||||||
|
cachedVersion = $store.version + ""
|
||||||
|
}
|
||||||
|
|
||||||
async function publishApp() {
|
async function publishApp() {
|
||||||
try {
|
try {
|
||||||
publishing = true
|
publishing = true
|
||||||
|
@ -124,7 +226,9 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
await completePublish()
|
await completePublish()
|
||||||
|
resetStateTracking()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
analytics.captureException(error)
|
analytics.captureException(error)
|
||||||
notifications.error("Error publishing app")
|
notifications.error("Error publishing app")
|
||||||
}
|
}
|
||||||
|
@ -153,6 +257,7 @@
|
||||||
type: "success",
|
type: "success",
|
||||||
icon: "GlobeStrike",
|
icon: "GlobeStrike",
|
||||||
})
|
})
|
||||||
|
publishRecord = {}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
notifications.error("Error unpublishing app")
|
notifications.error("Error unpublishing app")
|
||||||
}
|
}
|
||||||
|
@ -176,7 +281,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $store.hasLock}
|
{#if $store.hasLock}
|
||||||
<div class="action-top-nav">
|
<div class="action-top-nav" class:has-lock={$store.hasLock}>
|
||||||
<div class="action-buttons">
|
<div class="action-buttons">
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
{#if updateAvailable}
|
{#if updateAvailable}
|
||||||
|
@ -317,7 +422,7 @@
|
||||||
cta
|
cta
|
||||||
on:click={publishApp}
|
on:click={publishApp}
|
||||||
id={"builder-app-publish-button"}
|
id={"builder-app-publish-button"}
|
||||||
disabled={publishing}
|
disabled={!canPublish}
|
||||||
>
|
>
|
||||||
Publish
|
Publish
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -349,8 +454,20 @@
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
<RevertModal bind:this={revertModal} />
|
<RevertModal bind:this={revertModal} onComplete={resetStateTracking} />
|
||||||
<VersionModal hideIcon bind:this={versionModal} />
|
<VersionModal
|
||||||
|
hideIcon
|
||||||
|
bind:this={versionModal}
|
||||||
|
onComplete={resetStateTracking}
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<div class="app-action-button preview-locked">
|
||||||
|
<div class="app-action">
|
||||||
|
<ActionButton quiet icon="PlayCircle" on:click={previewApp}>
|
||||||
|
Preview
|
||||||
|
</ActionButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -385,7 +502,7 @@
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.app-action-popover-content .status-text {
|
.app-action-popover-content .status-text {
|
||||||
color: #1ca872;
|
color: var(--spectrum-global-color-green-500);
|
||||||
border-right: 1px solid var(--spectrum-global-color-gray-500);
|
border-right: 1px solid var(--spectrum-global-color-gray-500);
|
||||||
padding-right: var(--spacing-m);
|
padding-right: var(--spacing-m);
|
||||||
}
|
}
|
||||||
|
@ -401,7 +518,7 @@
|
||||||
.publish-popover-status
|
.publish-popover-status
|
||||||
.unpublish-link
|
.unpublish-link
|
||||||
:global(.spectrum-Link) {
|
:global(.spectrum-Link) {
|
||||||
color: #ee4331;
|
color: var(--spectrum-global-color-red-400);
|
||||||
}
|
}
|
||||||
.publish-popover-status {
|
.publish-popover-status {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -435,6 +552,10 @@
|
||||||
gap: var(--spectrum-actionbutton-icon-gap);
|
gap: var(--spectrum-actionbutton-icon-gap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-action-button.preview-locked {
|
||||||
|
padding-right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
.app-action {
|
.app-action {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
import { store } from "builderStore"
|
import { store } from "builderStore"
|
||||||
import { API } from "api"
|
import { API } from "api"
|
||||||
|
|
||||||
export let disabled = false
|
export let onComplete = () => {}
|
||||||
|
|
||||||
let revertModal
|
let revertModal
|
||||||
let appName
|
let appName
|
||||||
|
@ -25,6 +25,7 @@
|
||||||
const applicationPkg = await API.fetchAppPackage(appId)
|
const applicationPkg = await API.fetchAppPackage(appId)
|
||||||
await store.actions.initialise(applicationPkg)
|
await store.actions.initialise(applicationPkg)
|
||||||
notifications.info("Changes reverted successfully")
|
notifications.info("Changes reverted successfully")
|
||||||
|
onComplete()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notifications.error(`Error reverting changes: ${error}`)
|
notifications.error(`Error reverting changes: ${error}`)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
updateModal.hide()
|
updateModal.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export let onComplete = () => {}
|
||||||
export let hideIcon = false
|
export let hideIcon = false
|
||||||
|
|
||||||
let updateModal
|
let updateModal
|
||||||
|
@ -47,6 +48,7 @@
|
||||||
notifications.success(
|
notifications.success(
|
||||||
`App updated successfully to version ${$store.upgradableVersion}`
|
`App updated successfully to version ${$store.upgradableVersion}`
|
||||||
)
|
)
|
||||||
|
onComplete()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
notifications.error(`Error updating app: ${err}`)
|
notifications.error(`Error updating app: ${err}`)
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,7 +143,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="root" class:blur={$store.showPreview}>
|
<div class="root" class:blur={$store.showPreview}>
|
||||||
<div class="top-nav">
|
<div class="top-nav" class:has-lock={$store.hasLock}>
|
||||||
{#if $store.initialised}
|
{#if $store.initialised}
|
||||||
<div class="topleftnav">
|
<div class="topleftnav">
|
||||||
<span class="back-to-apps">
|
<span class="back-to-apps">
|
||||||
|
@ -171,7 +171,10 @@
|
||||||
{:else}
|
{:else}
|
||||||
<div class="secondary-editor">
|
<div class="secondary-editor">
|
||||||
<Icon name="LockClosed" />
|
<Icon name="LockClosed" />
|
||||||
<div class="secondary-editor-body">
|
<div
|
||||||
|
class="secondary-editor-body"
|
||||||
|
title="Another user is currently editing your screens and automations"
|
||||||
|
>
|
||||||
Another user is currently editing your screens and automations
|
Another user is currently editing your screens and automations
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -184,7 +187,7 @@
|
||||||
<span class:nav-lock={!$store.hasLock}>
|
<span class:nav-lock={!$store.hasLock}>
|
||||||
<UserAvatars users={$userStore} />
|
<UserAvatars users={$userStore} />
|
||||||
</span>
|
</span>
|
||||||
<AppActions {application} />
|
<AppActions {application} {loaded} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
@ -239,7 +242,6 @@
|
||||||
flex: 0 0 60px;
|
flex: 0 0 60px;
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
padding: 0 var(--spacing-xl);
|
padding: 0 var(--spacing-xl);
|
||||||
padding-right: 0px;
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr auto 1fr;
|
grid-template-columns: 1fr auto 1fr;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@ -249,6 +251,10 @@
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.top-nav.has-lock {
|
||||||
|
padding-right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
.topcenternav {
|
.topcenternav {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
@ -259,16 +265,17 @@
|
||||||
|
|
||||||
.topcenternav :global(.spectrum-Heading) {
|
.topcenternav :global(.spectrum-Heading) {
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
/* width: 0; */
|
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
padding: 0px var(--spacing-m);
|
||||||
}
|
}
|
||||||
|
|
||||||
.topleftnav {
|
.topleftnav {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-bottom: -2px;
|
margin-bottom: -2px;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.topleftnav :global(.spectrum-Tabs-itemLabel) {
|
.topleftnav :global(.spectrum-Tabs-itemLabel) {
|
||||||
|
@ -291,6 +298,15 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
min-width: 0px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.secondary-editor-body {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
min-width: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.body {
|
.body {
|
||||||
|
|
|
@ -68,7 +68,7 @@
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.delete-action :global(span) {
|
.delete-action :global(span) {
|
||||||
color: #ee4331;
|
color: var(--spectrum-global-color-red-400);
|
||||||
}
|
}
|
||||||
.delete-action {
|
.delete-action {
|
||||||
display: contents;
|
display: contents;
|
||||||
|
|
|
@ -7,12 +7,6 @@
|
||||||
layout,
|
layout,
|
||||||
route,
|
route,
|
||||||
} from "@roxi/routify"
|
} from "@roxi/routify"
|
||||||
// $: console.log("isChangingPage", $isChangingPage)
|
|
||||||
// $: console.log("page ", $page)
|
|
||||||
// $: console.log("is Active ", $isActive("../settings"))
|
|
||||||
$: indexCheck = $layout.meta.index
|
|
||||||
$: console.log("Index Check ", indexCheck)
|
|
||||||
$: console.log("layout", $layout)
|
|
||||||
|
|
||||||
$redirect("../settings/automation-history")
|
$redirect("../settings/automation-history")
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -23,9 +23,6 @@
|
||||||
$: appDeployed = app?.status === AppStatus.DEPLOYED
|
$: appDeployed = app?.status === AppStatus.DEPLOYED
|
||||||
|
|
||||||
const initialiseApp = async () => {
|
const initialiseApp = async () => {
|
||||||
// In order for these changes to make it back into the app, the app package must be reinitialied
|
|
||||||
// could this have negative side affects???
|
|
||||||
console.log("Reinitialise")
|
|
||||||
const applicationPkg = await API.fetchAppPackage(app.devId)
|
const applicationPkg = await API.fetchAppPackage(app.devId)
|
||||||
await store.actions.initialise(applicationPkg)
|
await store.actions.initialise(applicationPkg)
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,6 @@
|
||||||
$goto(
|
$goto(
|
||||||
`/builder/app/${appId}/settings/automation-history?${params.toString()}`
|
`/builder/app/${appId}/settings/automation-history?${params.toString()}`
|
||||||
)
|
)
|
||||||
// $goto(`../overview/${appId}/automation-history?${params.toString()}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const errorCount = errors => {
|
const errorCount = errors => {
|
||||||
|
|
|
@ -141,7 +141,7 @@
|
||||||
customPlaceholder
|
customPlaceholder
|
||||||
allowEditRows={false}
|
allowEditRows={false}
|
||||||
customRenderers={customAppTableRenderers}
|
customRenderers={customAppTableRenderers}
|
||||||
on:click={e => $goto(`../../overview/${e.detail.devId}`)}
|
on:click={e => $goto(`/builder/app/${e.detail.devId}`)}
|
||||||
>
|
>
|
||||||
<div class="placeholder" slot="placeholder">
|
<div class="placeholder" slot="placeholder">
|
||||||
<Heading size="S">This group doesn't have access to any apps</Heading>
|
<Heading size="S">This group doesn't have access to any apps</Heading>
|
||||||
|
|
|
@ -346,7 +346,7 @@
|
||||||
customPlaceholder
|
customPlaceholder
|
||||||
allowEditRows={false}
|
allowEditRows={false}
|
||||||
customRenderers={customAppTableRenderers}
|
customRenderers={customAppTableRenderers}
|
||||||
on:click={e => $goto(`../../overview/${e.detail.devId}`)}
|
on:click={e => $goto(`/builder/app/${e.detail.devId}`)}
|
||||||
>
|
>
|
||||||
<div class="placeholder" slot="placeholder">
|
<div class="placeholder" slot="placeholder">
|
||||||
<Heading size="S">
|
<Heading size="S">
|
||||||
|
|
|
@ -10,7 +10,6 @@ export { licensing } from "./licensing"
|
||||||
export { groups } from "./groups"
|
export { groups } from "./groups"
|
||||||
export { plugins } from "./plugins"
|
export { plugins } from "./plugins"
|
||||||
export { backups } from "./backups"
|
export { backups } from "./backups"
|
||||||
export { overview } from "./overview"
|
|
||||||
export { environment } from "./environment"
|
export { environment } from "./environment"
|
||||||
export { menu } from "./menu"
|
export { menu } from "./menu"
|
||||||
export { auditLogs } from "./auditLogs"
|
export { auditLogs } from "./auditLogs"
|
||||||
|
|
|
@ -86,12 +86,6 @@ export default async function builder(ctx: UserCtx) {
|
||||||
|
|
||||||
const referer = ctx.headers["referer"]
|
const referer = ctx.headers["referer"]
|
||||||
|
|
||||||
const overviewPath = "/builder/portal/overview/"
|
|
||||||
const overviewContext = !referer ? false : referer.includes(overviewPath)
|
|
||||||
if (overviewContext) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasAppId = !referer ? false : referer.includes(appId)
|
const hasAppId = !referer ? false : referer.includes(appId)
|
||||||
const editingApp = referer ? hasAppId : false
|
const editingApp = referer ? hasAppId : false
|
||||||
// check this is a builder call and editing
|
// check this is a builder call and editing
|
||||||
|
|
Loading…
Reference in a new issue