Update top bar when not the primary builder and prevent flashing during loading states
This commit is contained in:
parent
7f96fbf741
commit
5f81584a14
|
@ -39,6 +39,7 @@ import { makePropSafe as safe } from "@budibase/string-templates"
|
||||||
import { getComponentFieldOptions } from "helpers/formFields"
|
import { getComponentFieldOptions } from "helpers/formFields"
|
||||||
|
|
||||||
const INITIAL_FRONTEND_STATE = {
|
const INITIAL_FRONTEND_STATE = {
|
||||||
|
initialised: false,
|
||||||
apps: [],
|
apps: [],
|
||||||
name: "",
|
name: "",
|
||||||
url: "",
|
url: "",
|
||||||
|
@ -70,6 +71,7 @@ const INITIAL_FRONTEND_STATE = {
|
||||||
previewDevice: "desktop",
|
previewDevice: "desktop",
|
||||||
highlightedSettingKey: null,
|
highlightedSettingKey: null,
|
||||||
builderSidePanel: false,
|
builderSidePanel: false,
|
||||||
|
hasLock: true,
|
||||||
|
|
||||||
// URL params
|
// URL params
|
||||||
selectedScreenId: null,
|
selectedScreenId: null,
|
||||||
|
@ -112,7 +114,7 @@ export const getFrontendStore = () => {
|
||||||
store.set({ ...INITIAL_FRONTEND_STATE })
|
store.set({ ...INITIAL_FRONTEND_STATE })
|
||||||
},
|
},
|
||||||
initialise: async pkg => {
|
initialise: async pkg => {
|
||||||
const { layouts, screens, application, clientLibPath } = pkg
|
const { layouts, screens, application, clientLibPath, hasLock } = pkg
|
||||||
|
|
||||||
await store.actions.components.refreshDefinitions(application.appId)
|
await store.actions.components.refreshDefinitions(application.appId)
|
||||||
|
|
||||||
|
@ -137,6 +139,8 @@ export const getFrontendStore = () => {
|
||||||
upgradableVersion: application.upgradableVersion,
|
upgradableVersion: application.upgradableVersion,
|
||||||
navigation: application.navigation || {},
|
navigation: application.navigation || {},
|
||||||
usedPlugins: application.usedPlugins || [],
|
usedPlugins: application.usedPlugins || [],
|
||||||
|
hasLock,
|
||||||
|
initialised: true,
|
||||||
}))
|
}))
|
||||||
screenHistoryStore.reset()
|
screenHistoryStore.reset()
|
||||||
automationHistoryStore.reset()
|
automationHistoryStore.reset()
|
||||||
|
|
|
@ -113,109 +113,113 @@
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="action-top-nav">
|
{#if $store.hasLock}
|
||||||
<div class="action-buttons">
|
<div class="action-top-nav">
|
||||||
<div class="version">
|
<div class="action-buttons">
|
||||||
<VersionModal />
|
<div class="version">
|
||||||
</div>
|
<VersionModal />
|
||||||
<RevertModal />
|
|
||||||
|
|
||||||
{#if isPublished}
|
|
||||||
<div class="publish-popover">
|
|
||||||
<div bind:this={publishPopoverAnchor}>
|
|
||||||
<ActionButton
|
|
||||||
quiet
|
|
||||||
icon="Globe"
|
|
||||||
size="M"
|
|
||||||
tooltip="Your published app"
|
|
||||||
on:click={publishPopover.show()}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Popover
|
|
||||||
bind:this={publishPopover}
|
|
||||||
align="right"
|
|
||||||
disabled={!isPublished}
|
|
||||||
anchor={publishPopoverAnchor}
|
|
||||||
offset={10}
|
|
||||||
>
|
|
||||||
<div class="popover-content">
|
|
||||||
<Layout noPadding gap="M">
|
|
||||||
<Heading size="XS">Your published app</Heading>
|
|
||||||
<Body size="S">
|
|
||||||
<span class="publish-popover-message">
|
|
||||||
{processStringSync(
|
|
||||||
"Last published {{ duration time 'millisecond' }} ago",
|
|
||||||
{
|
|
||||||
time:
|
|
||||||
new Date().getTime() -
|
|
||||||
new Date(latestDeployments[0].updatedAt).getTime(),
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</Body>
|
|
||||||
<div class="buttons">
|
|
||||||
<Button
|
|
||||||
warning={true}
|
|
||||||
icon="GlobeStrike"
|
|
||||||
disabled={!isPublished}
|
|
||||||
on:click={unpublishApp}
|
|
||||||
>
|
|
||||||
Unpublish
|
|
||||||
</Button>
|
|
||||||
<Button cta on:click={viewApp}>View app</Button>
|
|
||||||
</div>
|
|
||||||
</Layout>
|
|
||||||
</div>
|
|
||||||
</Popover>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
<RevertModal />
|
||||||
|
|
||||||
{#if !isPublished}
|
{#if isPublished}
|
||||||
<ActionButton
|
<div class="publish-popover">
|
||||||
quiet
|
<div bind:this={publishPopoverAnchor}>
|
||||||
icon="GlobeStrike"
|
<ActionButton
|
||||||
size="M"
|
quiet
|
||||||
tooltip="Your app has not been published yet"
|
icon="Globe"
|
||||||
disabled
|
size="M"
|
||||||
/>
|
tooltip="Your published app"
|
||||||
{/if}
|
on:click={publishPopover.show()}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Popover
|
||||||
|
bind:this={publishPopover}
|
||||||
|
align="right"
|
||||||
|
disabled={!isPublished}
|
||||||
|
anchor={publishPopoverAnchor}
|
||||||
|
offset={10}
|
||||||
|
>
|
||||||
|
<div class="popover-content">
|
||||||
|
<Layout noPadding gap="M">
|
||||||
|
<Heading size="XS">Your published app</Heading>
|
||||||
|
<Body size="S">
|
||||||
|
<span class="publish-popover-message">
|
||||||
|
{processStringSync(
|
||||||
|
"Last published {{ duration time 'millisecond' }} ago",
|
||||||
|
{
|
||||||
|
time:
|
||||||
|
new Date().getTime() -
|
||||||
|
new Date(latestDeployments[0].updatedAt).getTime(),
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</Body>
|
||||||
|
<div class="buttons">
|
||||||
|
<Button
|
||||||
|
warning={true}
|
||||||
|
icon="GlobeStrike"
|
||||||
|
disabled={!isPublished}
|
||||||
|
on:click={unpublishApp}
|
||||||
|
>
|
||||||
|
Unpublish
|
||||||
|
</Button>
|
||||||
|
<Button cta on:click={viewApp}>View app</Button>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
</div>
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<TourWrap
|
{#if !isPublished}
|
||||||
tourStepKey={$store.onboarding
|
|
||||||
? TOUR_STEP_KEYS.BUILDER_USER_MANAGEMENT
|
|
||||||
: TOUR_STEP_KEYS.FEATURE_USER_MANAGEMENT}
|
|
||||||
>
|
|
||||||
<span id="builder-app-users-button">
|
|
||||||
<ActionButton
|
<ActionButton
|
||||||
quiet
|
quiet
|
||||||
icon="UserGroup"
|
icon="GlobeStrike"
|
||||||
size="M"
|
size="M"
|
||||||
on:click={() => {
|
tooltip="Your app has not been published yet"
|
||||||
store.update(state => {
|
disabled
|
||||||
state.builderSidePanel = true
|
/>
|
||||||
return state
|
{/if}
|
||||||
})
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Users
|
|
||||||
</ActionButton>
|
|
||||||
</span>
|
|
||||||
</TourWrap>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ConfirmDialog
|
<TourWrap
|
||||||
bind:this={unpublishModal}
|
tourStepKey={$store.onboarding
|
||||||
title="Confirm unpublish"
|
? TOUR_STEP_KEYS.BUILDER_USER_MANAGEMENT
|
||||||
okText="Unpublish app"
|
: TOUR_STEP_KEYS.FEATURE_USER_MANAGEMENT}
|
||||||
onOk={confirmUnpublishApp}
|
>
|
||||||
>
|
<span id="builder-app-users-button">
|
||||||
Are you sure you want to unpublish the app <b>{selectedApp?.name}</b>?
|
<ActionButton
|
||||||
</ConfirmDialog>
|
quiet
|
||||||
|
icon="UserGroup"
|
||||||
|
size="M"
|
||||||
|
on:click={() => {
|
||||||
|
store.update(state => {
|
||||||
|
state.builderSidePanel = true
|
||||||
|
return state
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Users
|
||||||
|
</ActionButton>
|
||||||
|
</span>
|
||||||
|
</TourWrap>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ConfirmDialog
|
||||||
|
bind:this={unpublishModal}
|
||||||
|
title="Confirm unpublish"
|
||||||
|
okText="Unpublish app"
|
||||||
|
onOk={confirmUnpublishApp}
|
||||||
|
>
|
||||||
|
Are you sure you want to unpublish the app <b>{selectedApp?.name}</b>?
|
||||||
|
</ConfirmDialog>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<Button on:click={previewApp} secondary>Preview</Button>
|
<Button on:click={previewApp} secondary>Preview</Button>
|
||||||
<DeployModal onOk={completePublish} />
|
{#if $store.hasLock}
|
||||||
|
<DeployModal onOk={completePublish} />
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
@ -134,68 +134,80 @@
|
||||||
|
|
||||||
<div class="root">
|
<div class="root">
|
||||||
<div class="top-nav">
|
<div class="top-nav">
|
||||||
<div class="topleftnav">
|
{#if $store.initialised}
|
||||||
<ActionMenu>
|
<div class="topleftnav">
|
||||||
<div slot="control">
|
<ActionMenu>
|
||||||
<Icon size="M" hoverable name="ShowMenu" />
|
<div slot="control">
|
||||||
</div>
|
<Icon size="M" hoverable name="ShowMenu" />
|
||||||
<MenuItem on:click={() => $goto("../../portal/apps")}>
|
</div>
|
||||||
Exit to portal
|
<MenuItem on:click={() => $goto("../../portal/apps")}>
|
||||||
</MenuItem>
|
Exit to portal
|
||||||
<MenuItem
|
</MenuItem>
|
||||||
on:click={() => $goto(`../../portal/overview/${application}`)}
|
<MenuItem
|
||||||
>
|
on:click={() => $goto(`../../portal/overview/${application}`)}
|
||||||
Overview
|
>
|
||||||
</MenuItem>
|
Overview
|
||||||
<MenuItem
|
</MenuItem>
|
||||||
on:click={() => $goto(`../../portal/overview/${application}/access`)}
|
<MenuItem
|
||||||
>
|
on:click={() =>
|
||||||
Access
|
$goto(`../../portal/overview/${application}/access`)}
|
||||||
</MenuItem>
|
>
|
||||||
<MenuItem
|
Access
|
||||||
on:click={() =>
|
</MenuItem>
|
||||||
$goto(`../../portal/overview/${application}/automation-history`)}
|
<MenuItem
|
||||||
>
|
on:click={() =>
|
||||||
Automation history
|
$goto(`../../portal/overview/${application}/automation-history`)}
|
||||||
</MenuItem>
|
>
|
||||||
<MenuItem
|
Automation history
|
||||||
on:click={() => $goto(`../../portal/overview/${application}/backups`)}
|
</MenuItem>
|
||||||
>
|
<MenuItem
|
||||||
Backups
|
on:click={() =>
|
||||||
</MenuItem>
|
$goto(`../../portal/overview/${application}/backups`)}
|
||||||
|
>
|
||||||
|
Backups
|
||||||
|
</MenuItem>
|
||||||
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
on:click={() =>
|
on:click={() =>
|
||||||
$goto(`../../portal/overview/${application}/name-and-url`)}
|
$goto(`../../portal/overview/${application}/name-and-url`)}
|
||||||
>
|
>
|
||||||
Name and URL
|
Name and URL
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
on:click={() => $goto(`../../portal/overview/${application}/version`)}
|
on:click={() =>
|
||||||
>
|
$goto(`../../portal/overview/${application}/version`)}
|
||||||
Version
|
>
|
||||||
</MenuItem>
|
Version
|
||||||
</ActionMenu>
|
</MenuItem>
|
||||||
<Heading size="XS">{$store.name}</Heading>
|
</ActionMenu>
|
||||||
</div>
|
<Heading size="XS">{$store.name}</Heading>
|
||||||
<div class="topcenternav">
|
</div>
|
||||||
<Tabs {selected} size="M">
|
<div class="topcenternav">
|
||||||
{#each $layout.children as { path, title }}
|
{#if $store.hasLock}
|
||||||
<TourWrap tourStepKey={`builder-${title}-section`}>
|
<Tabs {selected} size="M">
|
||||||
<Tab
|
{#each $layout.children as { path, title }}
|
||||||
quiet
|
<TourWrap tourStepKey={`builder-${title}-section`}>
|
||||||
selected={$isActive(path)}
|
<Tab
|
||||||
on:click={topItemNavigate(path)}
|
quiet
|
||||||
title={capitalise(title)}
|
selected={$isActive(path)}
|
||||||
id={`builder-${title}-tab`}
|
on:click={topItemNavigate(path)}
|
||||||
/>
|
title={capitalise(title)}
|
||||||
</TourWrap>
|
id={`builder-${title}-tab`}
|
||||||
{/each}
|
/>
|
||||||
</Tabs>
|
</TourWrap>
|
||||||
</div>
|
{/each}
|
||||||
<div class="toprightnav">
|
</Tabs>
|
||||||
<AppActions {application} />
|
{:else}
|
||||||
</div>
|
<div class="secondary-editor">
|
||||||
|
<Icon name="LockClosed" />
|
||||||
|
Another user is currently editing your screens and automations
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div class="toprightnav">
|
||||||
|
<AppActions {application} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{#await promise}
|
{#await promise}
|
||||||
<!-- This should probably be some kind of loading state? -->
|
<!-- This should probably be some kind of loading state? -->
|
||||||
|
@ -270,4 +282,11 @@
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--spacing-l);
|
gap: var(--spacing-l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.secondary-editor {
|
||||||
|
align-self: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in New Issue