Centralise menu logic and show full menu on mobile

This commit is contained in:
Andrew Kingston 2023-01-12 16:50:43 +00:00
parent abd84118d9
commit 5d24fe0a13
8 changed files with 179 additions and 130 deletions

View File

@ -6,9 +6,9 @@
import UpgradeButton from "./UpgradeButton.svelte" import UpgradeButton from "./UpgradeButton.svelte"
import { fade } from "svelte/transition" import { fade } from "svelte/transition"
import Logo from "./Logo.svelte" import Logo from "./Logo.svelte"
import { menu } from "stores/portal"
export let visible = false export let visible = false
export let menu
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
@ -28,13 +28,28 @@
<Logo /> <Logo />
</div> </div>
<SideNav> <SideNav>
{#each menu as { title, href }} {#each $menu as { title, href, subPages }}
<SideNavItem {#if !subPages?.length}
text={title} <SideNavItem
url={href} text={title}
active={$isActive(href)} url={href}
on:click={close} active={$isActive(href)}
/> on:click={close}
/>
{/if}
{/each}
{#each $menu as { title, href, subPages }}
{#if subPages?.length}
<div class="category">{title}</div>
{#each subPages as { title, href }}
<SideNavItem
text={title}
url={href}
active={$isActive(href)}
on:click={close}
/>
{/each}
{/if}
{/each} {/each}
</SideNav> </SideNav>
<div> <div>
@ -47,6 +62,13 @@
.mobile-nav { .mobile-nav {
display: none; display: none;
} }
.category {
color: var(--spectrum-global-color-gray-600);
font-size: var(--font-size-s);
margin-left: var(--spacing-m);
margin-top: 24px;
margin-bottom: 4px;
}
@media (max-width: 640px) { @media (max-width: 640px) {
.mobile-nav-underlay { .mobile-nav-underlay {

View File

@ -1,9 +1,8 @@
<script> <script>
import { isActive, redirect, goto, url } from "@roxi/routify" import { isActive, redirect, goto, url } from "@roxi/routify"
import { Icon, notifications, Tabs, Tab } from "@budibase/bbui" import { Icon, notifications, Tabs, Tab } from "@budibase/bbui"
import { organisation, auth, admin as adminStore } from "stores/portal" import { organisation, auth, menu } from "stores/portal"
import { onMount } from "svelte" import { onMount } from "svelte"
import { isEnabled, TENANT_FEATURE_FLAGS } from "helpers/featureFlags"
import UpgradeButton from "./_components/UpgradeButton.svelte" import UpgradeButton from "./_components/UpgradeButton.svelte"
import MobileMenu from "./_components/MobileMenu.svelte" import MobileMenu from "./_components/MobileMenu.svelte"
import Logo from "./_components/Logo.svelte" import Logo from "./_components/Logo.svelte"
@ -13,10 +12,9 @@
let mobileMenuVisible = false let mobileMenuVisible = false
let activeTab = "Apps" let activeTab = "Apps"
$: menu = buildMenu($auth.isAdmin) $: $url(), updateActiveTab($menu)
$: $url(), updateActiveTab()
const updateActiveTab = () => { const updateActiveTab = menu => {
for (let entry of menu) { for (let entry of menu) {
if ($isActive(entry.href)) { if ($isActive(entry.href)) {
if (activeTab !== entry.title) { if (activeTab !== entry.title) {
@ -27,55 +25,6 @@
} }
} }
const buildMenu = admin => {
// Standard user and developer pages
let menu = [
{
title: "Apps",
href: "/builder/portal/apps",
},
{
title: "Plugins",
href: "/builder/portal/plugins",
},
]
// Admin only pages
if (admin) {
menu = [
{
title: "Apps",
href: "/builder/portal/apps",
},
{
title: "Users",
href: "/builder/portal/users/users",
},
{
title: "Plugins",
href: "/builder/portal/plugins",
},
{
title: "Settings",
href: "/builder/portal/settings",
},
]
}
// Check if allowed access to account section
if (
isEnabled(TENANT_FEATURE_FLAGS.LICENSING) &&
($auth?.user?.accountPortalAccess || (!$adminStore.cloud && admin))
) {
menu.push({
title: "Account",
href: "/builder/portal/account",
})
}
return menu
}
const showMobileMenu = () => (mobileMenuVisible = true) const showMobileMenu = () => (mobileMenuVisible = true)
const hideMobileMenu = () => (mobileMenuVisible = false) const hideMobileMenu = () => (mobileMenuVisible = false)
@ -104,7 +53,7 @@
</div> </div>
<div class="desktop"> <div class="desktop">
<Tabs selected={activeTab}> <Tabs selected={activeTab}>
{#each menu as { title, href }} {#each $menu as { title, href }}
<Tab {title} on:click={() => $goto(href)} /> <Tab {title} on:click={() => $goto(href)} />
{/each} {/each}
</Tabs> </Tabs>
@ -122,7 +71,7 @@
<div class="main"> <div class="main">
<slot /> <slot />
</div> </div>
<MobileMenu visible={mobileMenuVisible} {menu} on:close={hideMobileMenu} /> <MobileMenu visible={mobileMenuVisible} on:close={hideMobileMenu} />
</div> </div>
{/if} {/if}

View File

@ -1,40 +1,19 @@
<script> <script>
import { url, isActive } from "@roxi/routify" import { isActive } from "@roxi/routify"
import { Page } from "@budibase/bbui" import { Page } from "@budibase/bbui"
import { Content, SideNav, SideNavItem } from "components/portal/page" import { Content, SideNav, SideNavItem } from "components/portal/page"
import { admin, auth } from "stores/portal" import { menu } from "stores/portal"
$: pages = $menu.find(x => x.title === "Account").subPages
</script> </script>
<Page narrow> <Page narrow>
<Content> <Content>
<div slot="side-nav"> <div slot="side-nav">
<SideNav> <SideNav>
<!-- Always show usage in self-host or cloud if licensing enabled--> {#each pages as { title, href }}
<SideNavItem <SideNavItem text={title} url={href} active={$isActive(href)} />
text="Usage" {/each}
url={$url("./usage")}
active={$isActive("./usage")}
/>
<!-- Show the relevant hosting upgrade page-->
{#if $admin.cloud && $auth?.user?.accountPortalAccess}
<SideNavItem
text="Upgrade"
url={$admin.accountPortalUrl + "/portal/upgrade"}
/>
{:else if !$admin.cloud && admin}
<SideNavItem
text="Upgrade"
url={$url("./upgrade")}
active={$isActive("./upgrade")}
/>
{/if}
<!-- Show the billing page to licensed account holders in cloud -->
{#if $auth?.user?.accountPortalAccess && $auth.user.account.stripeCustomerId}
<SideNavItem
text="Billing"
url={$admin.accountPortalUrl + "/portal/billing"}
/>
{/if}
</SideNav> </SideNav>
</div> </div>
<slot /> <slot />

View File

@ -1,38 +1,20 @@
<script> <script>
import { url, isActive } from "@roxi/routify" import { isActive } from "@roxi/routify"
import { Page } from "@budibase/bbui" import { Page } from "@budibase/bbui"
import { Content, SideNav, SideNavItem } from "components/portal/page" import { Content, SideNav, SideNavItem } from "components/portal/page"
import { admin } from "stores/portal" import { menu } from "stores/portal"
$: wide = $isActive("./email/:template") $: wide = $isActive("./email/:template")
$: pages = $menu.find(x => x.title === "Settings").subPages
</script> </script>
<Page> <Page>
<Content narrow={!wide}> <Content narrow={!wide}>
<div slot="side-nav"> <div slot="side-nav">
<SideNav> <SideNav>
<SideNavItem {#each pages as { title, href }}
text="Auth" <SideNavItem text={title} url={href} active={$isActive(href)} />
url={$url("./auth")} {/each}
active={$isActive("./auth")}
/>
<SideNavItem
text="Email"
url={$url("./email")}
active={$isActive("./email")}
/>
<SideNavItem
text="Organisation"
url={$url("./organisation")}
active={$isActive("./organisation")}
/>
{#if !$admin.cloud}
<SideNavItem
text="Version"
url={$url("./version")}
active={$isActive("./version")}
/>
{/if}
</SideNav> </SideNav>
</div> </div>
<slot /> <slot />

View File

@ -1,28 +1,20 @@
<script> <script>
import { Page } from "@budibase/bbui" import { Page } from "@budibase/bbui"
import { SideNav, SideNavItem, Content } from "components/portal/page" import { SideNav, SideNavItem, Content } from "components/portal/page"
import { isActive, url } from "@roxi/routify" import { isActive } from "@roxi/routify"
import { isEnabled, TENANT_FEATURE_FLAGS } from "helpers/featureFlags" import { menu } from "stores/portal"
$: wide = $isActive("./users/index") || $isActive("./groups/index") $: wide = $isActive("./users/index") || $isActive("./groups/index")
$: pages = $menu.find(x => x.title === "Users").subPages
</script> </script>
<Page> <Page>
<Content narrow={!wide}> <Content narrow={!wide}>
<div slot="side-nav"> <div slot="side-nav">
<SideNav> <SideNav>
<SideNavItem {#each pages as { title, href }}
text="Users" <SideNavItem text={title} url={href} active={$isActive(href)} />
url={$url("./users")} {/each}
active={$isActive("./users")}
/>
{#if isEnabled(TENANT_FEATURE_FLAGS.USER_GROUPS)}
<SideNavItem
text="Groups"
url={$url("./groups")}
active={$isActive("./groups")}
/>
{/if}
</SideNav> </SideNav>
</div> </div>
<slot /> <slot />

View File

@ -0,0 +1,4 @@
<script>
import { redirect } from "@roxi/routify"
$redirect("./users")
</script>

View File

@ -11,3 +11,4 @@ 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 { overview } from "./overview"
export { menu } from "./menu"

View File

@ -0,0 +1,120 @@
import { derived } from "svelte/store"
import { isEnabled, TENANT_FEATURE_FLAGS } from "helpers/featureFlags"
import { admin } from "./admin"
import { auth } from "./auth"
export const menu = derived([admin, auth], ([$admin, $auth]) => {
// Standard user and developer pages
let menu = [
{
title: "Apps",
href: "/builder/portal/apps",
},
{
title: "Plugins",
href: "/builder/portal/plugins",
},
]
// Admin only pages
if ($auth.isAdmin) {
// Determine user sub pages
let userSubPages = [
{
title: "Users",
href: "/builder/portal/users/users",
},
]
if (isEnabled(TENANT_FEATURE_FLAGS.USER_GROUPS)) {
userSubPages.push({
title: "Groups",
href: "/builder/portal/users/groups",
})
}
// Determine settings sub pages
let settingsSubPages = [
{
title: "Auth",
href: "/builder/portal/settings/auth",
},
{
title: "Email",
href: "/builder/portal/settings/email",
},
{
title: "Organisation",
href: "/builder/portal/settings/organisation",
},
]
if (!$admin.cloud) {
settingsSubPages.push({
title: "Version",
href: "/builder/portal/settings/version",
})
}
menu = [
{
title: "Apps",
href: "/builder/portal/apps",
},
{
title: "Users",
href: "/builder/portal/users",
subPages: userSubPages,
},
{
title: "Plugins",
href: "/builder/portal/plugins",
},
{
title: "Settings",
href: "/builder/portal/settings",
subPages: settingsSubPages,
},
]
}
// Check if allowed access to account section
if (
isEnabled(TENANT_FEATURE_FLAGS.LICENSING) &&
($auth?.user?.accountPortalAccess || (!$admin.cloud && $auth.isAdmin))
) {
// Determine account sub pages
let accountSubPages = [
{
title: "Usage",
href: "/builder/portal/account/usage",
},
]
if ($admin.cloud && $auth?.user?.accountPortalAccess) {
accountSubPages.push({
title: "Upgrade",
href: $admin.accountPortalUrl + "/portal/upgrade",
})
} else if (!$admin.cloud && admin) {
accountSubPages.push({
title: "Upgrade",
href: "/builder/portal/account/upgrade",
})
}
if (
$auth?.user?.accountPortalAccess &&
$auth.user.account.stripeCustomerId
) {
accountSubPages.push({
title: "Billing",
href: $admin.accountPortalUrl + "/portal/billing",
})
}
menu.push({
title: "Account",
href: "/builder/portal/account",
subPages: accountSubPages,
})
}
return menu
})