More WIP portal redesign!
This commit is contained in:
parent
16bfe97015
commit
98ce87e8f7
28 changed files with 295 additions and 243 deletions
|
@ -25,7 +25,7 @@
|
|||
}
|
||||
|
||||
.narrow {
|
||||
max-width: 800px;
|
||||
max-width: 840px;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
dummy.select()
|
||||
document.execCommand("copy")
|
||||
document.body.removeChild(dummy)
|
||||
notifications.success(`URL copied to clipboard`)
|
||||
notifications.success(`Copied to clipboard`)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
gap: 4px;
|
||||
}
|
||||
.title {
|
||||
margin-left: var(--spacing-m);
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
<script>
|
||||
import { ModalContent, Body, notifications } from "@budibase/bbui"
|
||||
import { auth } from "stores/portal"
|
||||
import { onMount } from "svelte"
|
||||
import CopyInput from "components/common/inputs/CopyInput.svelte"
|
||||
|
||||
let apiKey = null
|
||||
|
||||
async function generateAPIKey() {
|
||||
try {
|
||||
apiKey = await auth.generateAPIKey()
|
||||
notifications.success("New API key generated")
|
||||
} catch (err) {
|
||||
notifications.error("Unable to generate new API key")
|
||||
}
|
||||
// need to return false to keep modal open
|
||||
return false
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
try {
|
||||
apiKey = await auth.fetchAPIKey()
|
||||
} catch (err) {
|
||||
notifications.error("Unable to fetch API key")
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<ModalContent
|
||||
title="Developer information"
|
||||
showConfirmButton={false}
|
||||
showSecondaryButton={true}
|
||||
secondaryButtonText="Re-generate key"
|
||||
secondaryAction={generateAPIKey}
|
||||
>
|
||||
<Body size="S">
|
||||
You can find information about your developer account here, such as the API
|
||||
key used to access the Budibase API.
|
||||
</Body>
|
||||
<CopyInput bind:value={apiKey} label="API key" />
|
||||
</ModalContent>
|
|
@ -11,8 +11,12 @@
|
|||
<div class="app-row">
|
||||
<div class="header">
|
||||
<div class="title" data-cy={`${app.devId}`}>
|
||||
<div class="app-icon" style="color: {app.icon?.color || ''}">
|
||||
<Icon size="L" name={app.icon?.name || "Apps"} />
|
||||
<div class="app-icon">
|
||||
<Icon
|
||||
size="L"
|
||||
name={app.icon?.name || "Apps"}
|
||||
color={app.icon?.color}
|
||||
/>
|
||||
</div>
|
||||
<div class="name" data-cy="app-name-link" on:click={() => editApp(app)}>
|
||||
<Heading size="S">
|
||||
|
@ -96,7 +100,7 @@
|
|||
|
||||
.app-status:not(.deployed) :global(.spectrum-Icon),
|
||||
.app-status:not(.deployed) :global(.spectrum-Body) {
|
||||
color: var(--spectrum-global-color-gray-700);
|
||||
color: var(--spectrum-global-color-gray-600);
|
||||
}
|
||||
|
||||
.app-row-actions {
|
||||
|
|
|
@ -89,7 +89,7 @@
|
|||
|
||||
{#if $auth.user && loaded}
|
||||
<div class="container">
|
||||
<Page>
|
||||
<Page narrow>
|
||||
<div class="content">
|
||||
<Layout noPadding>
|
||||
<div class="header">
|
||||
|
@ -196,6 +196,11 @@
|
|||
.container {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
padding: 80px;
|
||||
}
|
||||
.content {
|
||||
width: 100%;
|
||||
|
|
|
@ -15,14 +15,12 @@
|
|||
import { onMount } from "svelte"
|
||||
import UpdateUserInfoModal from "components/settings/UpdateUserInfoModal.svelte"
|
||||
import ChangePasswordModal from "components/settings/ChangePasswordModal.svelte"
|
||||
import UpdateAPIKeyModal from "components/settings/UpdateAPIKeyModal.svelte"
|
||||
import Logo from "assets/bb-emblem.svg"
|
||||
import { isEnabled, TENANT_FEATURE_FLAGS } from "helpers/featureFlags"
|
||||
|
||||
let loaded = false
|
||||
let userInfoModal
|
||||
let changePasswordModal
|
||||
let apiKeyModal
|
||||
let mobileMenuVisible = false
|
||||
let activeTab = "Apps"
|
||||
|
||||
|
@ -42,92 +40,79 @@
|
|||
title: "Users",
|
||||
href: "/builder/portal/users/users",
|
||||
},
|
||||
{ title: "Auth", href: "/builder/portal/manage/auth" },
|
||||
{ title: "Email", href: "/builder/portal/manage/email" },
|
||||
{
|
||||
title: "Plugins",
|
||||
href: "/builder/portal/manage/plugins",
|
||||
href: "/builder/portal/plugins",
|
||||
badge: "New",
|
||||
},
|
||||
|
||||
{
|
||||
title: "Organisation",
|
||||
href: "/builder/portal/settings/organisation",
|
||||
heading: "Settings",
|
||||
title: "Usage",
|
||||
href: "/builder/portal/usage",
|
||||
},
|
||||
{
|
||||
title: "Theming",
|
||||
href: "/builder/portal/settings/theming",
|
||||
},
|
||||
])
|
||||
|
||||
if (!$adminStore.cloud) {
|
||||
menu = menu.concat([
|
||||
{
|
||||
title: "Update",
|
||||
href: "/builder/portal/settings/update",
|
||||
},
|
||||
])
|
||||
}
|
||||
} else {
|
||||
menu = menu.concat([
|
||||
{
|
||||
title: "Theming",
|
||||
href: "/builder/portal/settings/theming",
|
||||
heading: "Settings",
|
||||
title: "Settings",
|
||||
href: "/builder/portal/settings",
|
||||
},
|
||||
])
|
||||
// if (!$adminStore.cloud) {
|
||||
// menu = menu.concat([
|
||||
// {
|
||||
// title: "Update",
|
||||
// href: "/builder/portal/settings/update",
|
||||
// },
|
||||
// ])
|
||||
// }
|
||||
}
|
||||
|
||||
// add link to account portal if the user has access
|
||||
let accountSectionAdded = false
|
||||
|
||||
// link out to account-portal if account holder in cloud or always in self-host
|
||||
if ($auth?.user?.accountPortalAccess || (!$adminStore.cloud && admin)) {
|
||||
accountSectionAdded = true
|
||||
menu = menu.concat([
|
||||
{
|
||||
title: "Account",
|
||||
href: $adminStore.accountPortalUrl,
|
||||
heading: "Account",
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
if (isEnabled(TENANT_FEATURE_FLAGS.LICENSING)) {
|
||||
// always show usage in self-host or cloud if licensing enabled
|
||||
menu = menu.concat([
|
||||
{
|
||||
title: "Usage",
|
||||
href: "/builder/portal/settings/usage",
|
||||
heading: accountSectionAdded ? "" : "Account",
|
||||
},
|
||||
])
|
||||
|
||||
// show the relevant hosting upgrade page
|
||||
if ($adminStore.cloud && $auth?.user?.accountPortalAccess) {
|
||||
menu = menu.concat([
|
||||
{
|
||||
title: "Upgrade",
|
||||
href: $adminStore.accountPortalUrl + "/portal/upgrade",
|
||||
badge: "New",
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
// show the billing page to licensed account holders in cloud
|
||||
if (
|
||||
$auth?.user?.accountPortalAccess &&
|
||||
$auth.user.account.stripeCustomerId
|
||||
) {
|
||||
menu = menu.concat([
|
||||
{
|
||||
title: "Billing",
|
||||
href: $adminStore.accountPortalUrl + "/portal/billing",
|
||||
},
|
||||
])
|
||||
}
|
||||
}
|
||||
// if ($auth?.user?.accountPortalAccess || (!$adminStore.cloud && admin)) {
|
||||
// accountSectionAdded = true
|
||||
// menu = menu.concat([
|
||||
// {
|
||||
// title: "Account",
|
||||
// href: $adminStore.accountPortalUrl,
|
||||
// heading: "Account",
|
||||
// },
|
||||
// ])
|
||||
// }
|
||||
//
|
||||
// if (isEnabled(TENANT_FEATURE_FLAGS.LICENSING)) {
|
||||
// // always show usage in self-host or cloud if licensing enabled
|
||||
// menu = menu.concat([
|
||||
// {
|
||||
// title: "Usage",
|
||||
// href: "/builder/portal/settings/usage",
|
||||
// heading: accountSectionAdded ? "" : "Account",
|
||||
// },
|
||||
// ])
|
||||
//
|
||||
// // show the relevant hosting upgrade page
|
||||
// if ($adminStore.cloud && $auth?.user?.accountPortalAccess) {
|
||||
// menu = menu.concat([
|
||||
// {
|
||||
// title: "Upgrade",
|
||||
// href: $adminStore.accountPortalUrl + "/portal/upgrade",
|
||||
// badge: "New",
|
||||
// },
|
||||
// ])
|
||||
// }
|
||||
//
|
||||
// // show the billing page to licensed account holders in cloud
|
||||
// if (
|
||||
// $auth?.user?.accountPortalAccess &&
|
||||
// $auth.user.account.stripeCustomerId
|
||||
// ) {
|
||||
// menu = menu.concat([
|
||||
// {
|
||||
// title: "Billing",
|
||||
// href: $adminStore.accountPortalUrl + "/portal/billing",
|
||||
// },
|
||||
// ])
|
||||
// }
|
||||
// }
|
||||
|
||||
menu = menu.filter(item => !!item)
|
||||
return menu
|
||||
|
@ -216,11 +201,6 @@
|
|||
>
|
||||
Update user information
|
||||
</MenuItem>
|
||||
{#if $auth.isBuilder}
|
||||
<MenuItem icon="Key" on:click={() => apiKeyModal.show()}>
|
||||
View API key
|
||||
</MenuItem>
|
||||
{/if}
|
||||
<MenuItem
|
||||
icon="LockClosed"
|
||||
on:click={() => changePasswordModal.show()}
|
||||
|
@ -247,9 +227,6 @@
|
|||
<Modal bind:this={changePasswordModal}>
|
||||
<ChangePasswordModal />
|
||||
</Modal>
|
||||
<Modal bind:this={apiKeyModal}>
|
||||
<UpdateAPIKeyModal />
|
||||
</Modal>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
let automationErrors
|
||||
let accessFilterList = null
|
||||
|
||||
$: welcomeHeader = `Welcome ${auth?.user?.firstName || "back"}`
|
||||
$: welcomeHeader = `Welcome ${$auth?.user?.firstName || "back"}`
|
||||
$: enrichedApps = enrichApps($apps, $auth.user, sortBy)
|
||||
$: filteredApps = enrichedApps.filter(
|
||||
app =>
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
<script>
|
||||
import { Page } from "@budibase/bbui"
|
||||
import { auth } from "stores/portal"
|
||||
import { page, redirect } from "@roxi/routify"
|
||||
|
||||
// Only admins allowed here
|
||||
$: {
|
||||
if (!$auth.isAdmin) {
|
||||
$redirect("../")
|
||||
}
|
||||
}
|
||||
|
||||
$: wide = $page.path.includes("email/:template")
|
||||
</script>
|
||||
|
||||
{#if $auth.isAdmin}
|
||||
<Page maxWidth="90ch" {wide}>
|
||||
<slot />
|
||||
</Page>
|
||||
{/if}
|
|
@ -8,6 +8,7 @@
|
|||
Divider,
|
||||
Modal,
|
||||
Search,
|
||||
Page,
|
||||
} from "@budibase/bbui"
|
||||
import { onMount } from "svelte"
|
||||
import { plugins, admin } from "stores/portal"
|
||||
|
@ -42,43 +43,42 @@
|
|||
})
|
||||
</script>
|
||||
|
||||
<Layout noPadding>
|
||||
<Layout gap="XS" noPadding>
|
||||
<Heading size="M">Plugins</Heading>
|
||||
<Body>Add your own custom datasources and components.</Body>
|
||||
</Layout>
|
||||
<Divider size="S" />
|
||||
<Page narrow>
|
||||
<Layout noPadding>
|
||||
<div class="controls">
|
||||
<div>
|
||||
<Button on:click={modal.show} newStyles cta icon={"Add"}>
|
||||
Add plugin
|
||||
</Button>
|
||||
</div>
|
||||
{#if $plugins?.length}
|
||||
<div class="filters">
|
||||
<div class="select">
|
||||
<Select
|
||||
bind:value={filter}
|
||||
placeholder={null}
|
||||
options={filterOptions}
|
||||
autoWidth
|
||||
quiet
|
||||
/>
|
||||
</div>
|
||||
<Search bind:value={searchTerm} placeholder="Search plugins" />
|
||||
<Layout gap="XS" noPadding>
|
||||
<Heading size="M">Plugins</Heading>
|
||||
<Body>Add your own custom datasources and components.</Body>
|
||||
</Layout>
|
||||
<Divider />
|
||||
<Layout noPadding>
|
||||
<div class="controls">
|
||||
<div>
|
||||
<Button on:click={modal.show} newStyles cta>Add plugin</Button>
|
||||
</div>
|
||||
{#if $plugins?.length}
|
||||
<div class="filters">
|
||||
<div class="select">
|
||||
<Select
|
||||
bind:value={filter}
|
||||
placeholder={null}
|
||||
options={filterOptions}
|
||||
autoWidth
|
||||
/>
|
||||
</div>
|
||||
<Search bind:value={searchTerm} placeholder="Search plugins" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{#if filteredPlugins?.length}
|
||||
<Layout noPadding gap="S">
|
||||
{#each filteredPlugins as plugin (plugin._id)}
|
||||
<PluginRow {plugin} />
|
||||
{/each}
|
||||
</Layout>
|
||||
{/if}
|
||||
</div>
|
||||
{#if filteredPlugins?.length}
|
||||
<Layout noPadding gap="S">
|
||||
{#each filteredPlugins as plugin (plugin._id)}
|
||||
<PluginRow {plugin} />
|
||||
{/each}
|
||||
</Layout>
|
||||
{/if}
|
||||
</Layout>
|
||||
</Layout>
|
||||
</Layout>
|
||||
</Page>
|
||||
|
||||
<Modal bind:this={modal}>
|
||||
<AddPluginModal />
|
|
@ -1,7 +1,60 @@
|
|||
<script>
|
||||
import { url, isActive } from "@roxi/routify"
|
||||
import { Page } from "@budibase/bbui"
|
||||
import { Content, SideNav, SideNavItem } from "components/portal/page"
|
||||
</script>
|
||||
|
||||
<Page maxWidth="90ch">
|
||||
<slot />
|
||||
<Page narrow>
|
||||
<Content>
|
||||
<div slot="side-nav">
|
||||
<SideNav title="Settings">
|
||||
<SideNavItem
|
||||
text="API Key"
|
||||
url={$url("./api")}
|
||||
active={$isActive("./api")}
|
||||
/>
|
||||
<SideNavItem
|
||||
text="Auth"
|
||||
url={$url("./auth")}
|
||||
active={$isActive("./auth")}
|
||||
/>
|
||||
<SideNavItem
|
||||
text="Email"
|
||||
url={$url("./email")}
|
||||
active={$isActive("./email")}
|
||||
/>
|
||||
<SideNavItem
|
||||
text="Organisation"
|
||||
url={$url("./organisation")}
|
||||
active={$isActive("./organisation")}
|
||||
/>
|
||||
<SideNavItem
|
||||
text="Version"
|
||||
url={$url("./version")}
|
||||
active={$isActive("./version")}
|
||||
/>
|
||||
<SideNavItem
|
||||
text="Theme"
|
||||
url={$url("./theme")}
|
||||
active={$isActive("./theme")}
|
||||
/>
|
||||
<SideNavItem
|
||||
text="Upgrade"
|
||||
url={$url("./upgrade")}
|
||||
active={$isActive("./upgrade")}
|
||||
/>
|
||||
<SideNavItem
|
||||
text="Secrets"
|
||||
url={$url("./secrets")}
|
||||
active={$isActive("./secrets")}
|
||||
/>
|
||||
<SideNavItem
|
||||
text="Scheduled Backups"
|
||||
url={$url("./backups")}
|
||||
active={$isActive("./backups")}
|
||||
/>
|
||||
</SideNav>
|
||||
</div>
|
||||
<slot />
|
||||
</Content>
|
||||
</Page>
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
<script>
|
||||
import {
|
||||
Layout,
|
||||
Heading,
|
||||
Body,
|
||||
Divider,
|
||||
Button,
|
||||
Label,
|
||||
notifications,
|
||||
} from "@budibase/bbui"
|
||||
import { auth } from "stores/portal"
|
||||
import { onMount } from "svelte"
|
||||
import CopyInput from "components/common/inputs/CopyInput.svelte"
|
||||
|
||||
let apiKey = null
|
||||
|
||||
async function generateAPIKey() {
|
||||
try {
|
||||
apiKey = await auth.generateAPIKey()
|
||||
notifications.success("New API key generated")
|
||||
} catch (err) {
|
||||
notifications.error("Unable to generate new API key")
|
||||
}
|
||||
// need to return false to keep modal open
|
||||
return false
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
try {
|
||||
apiKey = await auth.fetchAPIKey()
|
||||
} catch (err) {
|
||||
notifications.error("Unable to fetch API key")
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<Layout noPadding>
|
||||
<Layout gap="XS" noPadding>
|
||||
<Heading size="M">API Key</Heading>
|
||||
<Body>You API key to access the Budibase public API</Body>
|
||||
</Layout>
|
||||
<Divider />
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
<Label size="L">API key</Label>
|
||||
<CopyInput bind:value={apiKey} />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Button newStyles secondary on:click={generateAPIKey}>Regenerate key</Button
|
||||
>
|
||||
</div>
|
||||
</Layout>
|
||||
|
||||
<style>
|
||||
.fields {
|
||||
display: grid;
|
||||
grid-gap: var(--spacing-m);
|
||||
}
|
||||
.field {
|
||||
display: grid;
|
||||
grid-template-columns: 120px 1fr;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 319 B After Width: | Height: | Size: 319 B |
|
@ -1,4 +1,4 @@
|
|||
<script>
|
||||
import { goto } from "@roxi/routify"
|
||||
$goto("./organisation")
|
||||
$goto("./api")
|
||||
</script>
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
|
||||
<Layout noPadding>
|
||||
<Layout gap="XS" noPadding>
|
||||
<Heading size="M">Theming</Heading>
|
||||
<Heading size="M">Theme</Heading>
|
||||
<Body>Customize how Budibase looks and feels.</Body>
|
||||
</Layout>
|
||||
<Divider />
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
<Label size="L">Builder theme</Label>
|
||||
<Label size="L">Theme</Label>
|
||||
<Select
|
||||
options={Constants.Themes}
|
||||
bind:value={$themeStore.theme}
|
|
@ -8,6 +8,7 @@
|
|||
Detail,
|
||||
Link,
|
||||
TooltipWrapper,
|
||||
Page,
|
||||
} from "@budibase/bbui"
|
||||
import { onMount } from "svelte"
|
||||
import { admin, auth, licensing } from "../../../../stores/portal"
|
||||
|
@ -176,32 +177,32 @@
|
|||
</script>
|
||||
|
||||
{#if loaded}
|
||||
<Layout noPadding>
|
||||
<Layout noPadding gap="XS">
|
||||
<Heading>Usage</Heading>
|
||||
<Body>
|
||||
Get information about your current usage within Budibase.
|
||||
{#if accountPortalAccess}
|
||||
To upgrade your plan and usage limits visit your <Link
|
||||
on:click={goToAccountPortal}
|
||||
size="L">Account</Link
|
||||
>
|
||||
{:else}
|
||||
To upgrade your plan and usage limits contact your account holder.
|
||||
{/if}
|
||||
</Body>
|
||||
</Layout>
|
||||
<Divider />
|
||||
<DashCard
|
||||
description="YOUR CURRENT PLAN"
|
||||
title={planTitle()}
|
||||
{primaryActionText}
|
||||
primaryAction={accountPortalAccess ? goToAccountPortal : undefined}
|
||||
{textRows}
|
||||
>
|
||||
<Layout gap="S" noPadding>
|
||||
<Layout gap="S">
|
||||
<div class="usages">
|
||||
<Page narrow>
|
||||
<Layout noPadding>
|
||||
<Layout noPadding gap="XS">
|
||||
<Heading>Usage</Heading>
|
||||
<Body>
|
||||
<div>Get information about your current usage within Budibase.</div>
|
||||
{#if accountPortalAccess}
|
||||
<div>
|
||||
To upgrade your plan and usage limits visit your <Link
|
||||
on:click={goToAccountPortal}
|
||||
size="L">Account</Link
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
</Body>
|
||||
</Layout>
|
||||
<Divider />
|
||||
<DashCard
|
||||
description="YOUR CURRENT PLAN"
|
||||
title={planTitle()}
|
||||
{primaryActionText}
|
||||
primaryAction={accountPortalAccess ? goToAccountPortal : undefined}
|
||||
{textRows}
|
||||
>
|
||||
<div class="content">
|
||||
<div class="column">
|
||||
<Layout noPadding>
|
||||
{#each staticUsage as usage}
|
||||
<div class="usage">
|
||||
|
@ -213,44 +214,51 @@
|
|||
{/each}
|
||||
</Layout>
|
||||
</div>
|
||||
</Layout>
|
||||
{#if monthlyUsage.length}
|
||||
<div class="monthly-container">
|
||||
<Layout gap="S">
|
||||
<Heading size="S" weight="light">Monthly</Heading>
|
||||
<div class="detail">
|
||||
<TooltipWrapper tooltip={new Date(quotaReset)}>
|
||||
<Detail size="M">Resets in {daysRemainingInMonth} days</Detail
|
||||
>
|
||||
</TooltipWrapper>
|
||||
</div>
|
||||
<div class="usages">
|
||||
<Layout noPadding>
|
||||
|
||||
{#if monthlyUsage.length}
|
||||
<div class="column">
|
||||
<Layout noPadding gap="M">
|
||||
<Layout gap="XS" noPadding>
|
||||
<Heading size="S">Monthly limits</Heading>
|
||||
<div class="detail">
|
||||
<TooltipWrapper tooltip={new Date(quotaReset)}>
|
||||
<Detail size="M">
|
||||
Resets in {daysRemainingInMonth} days
|
||||
</Detail>
|
||||
</TooltipWrapper>
|
||||
</div>
|
||||
</Layout>
|
||||
<Layout noPadding gap="M">
|
||||
{#each monthlyUsage as usage}
|
||||
<div class="usage">
|
||||
<Usage
|
||||
{usage}
|
||||
warnWhenFull={WARN_USAGE.includes(usage.name)}
|
||||
/>
|
||||
</div>
|
||||
<Usage
|
||||
{usage}
|
||||
warnWhenFull={WARN_USAGE.includes(usage.name)}
|
||||
/>
|
||||
{/each}
|
||||
</Layout>
|
||||
</div>
|
||||
</Layout>
|
||||
</div>
|
||||
{/if}
|
||||
</Layout>
|
||||
</DashCard>
|
||||
</Layout>
|
||||
</Layout>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</DashCard>
|
||||
</Layout>
|
||||
</Page>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.usages {
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
gap: 40px;
|
||||
}
|
||||
.column {
|
||||
flex: 1 1 0;
|
||||
}
|
||||
.detail :global(.spectrum-Detail) {
|
||||
color: var(--spectrum-global-color-gray-700);
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.detail :global(.icon) {
|
||||
margin-bottom: 0;
|
|
@ -104,7 +104,7 @@
|
|||
</script>
|
||||
|
||||
{#if loaded}
|
||||
<Layout noPadding gap="XL">
|
||||
<Layout noPadding gap="L">
|
||||
<Breadcrumbs>
|
||||
<Breadcrumb url={$url("./")} text="Groups" />
|
||||
<Breadcrumb text={group?.name} />
|
||||
|
|
|
@ -189,7 +189,7 @@
|
|||
</script>
|
||||
|
||||
{#if loaded}
|
||||
<Layout gap="XL" noPadding>
|
||||
<Layout gap="L" noPadding>
|
||||
<Breadcrumbs>
|
||||
<Breadcrumb url={$url("./")} text="Users" />
|
||||
<Breadcrumb text={user?.email} />
|
||||
|
|
Loading…
Reference in a new issue