Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add orgnaization tabs and settings tab skeleton #5458

Merged
merged 10 commits into from
Aug 20, 2024
47 changes: 47 additions & 0 deletions web-admin/src/components/nav/LeftNav.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<script lang="ts">
import { page } from "$app/stores";
import LeftNavItem from "@rilldata/web-admin/components/nav/LeftNavItem.svelte";

export let title: string;
export let basePage: string;
export let baseRoute: string;
export let navItems: {
label: string;
route: string;
}[];
</script>

<div class="nav-layout-container">
<h3>{title}</h3>
<div class="nav-container">
<div class="nav-items">
{#each navItems as { label, route } (route)}
<LeftNavItem
{label}
link={`${basePage}/${route}`}
selected={$page.route.id === `${baseRoute}/${route}`}
/>
{/each}
</div>
<div><slot /></div>
</div>
</div>

<style lang="postcss">
.nav-layout-container {
@apply px-32 py-10;
}

h3 {
@apply text-2xl font-semibold;
}

.nav-container {
@apply flex flex-row pt-6 gap-x-6;
}

.nav-items {
@apply flex flex-col gap-y-1;
@apply min-w-[150px];
}
</style>
25 changes: 25 additions & 0 deletions web-admin/src/components/nav/LeftNavItem.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<script lang="ts">
export let label: string;
export let selected: boolean;
export let link: string;
</script>

<a class:selected href={link}>
{label}
</a>

<style lang="postcss">
a {
@apply p-2 flex gap-x-1 items-center;
@apply rounded-sm text-slate-900;
@apply text-sm font-medium;
}

.selected {
@apply bg-slate-100;
}

a:hover {
@apply bg-slate-50;
}
</style>
4 changes: 3 additions & 1 deletion web-admin/src/features/navigation/TopNavigationBar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import {
isMetricsExplorerPage,
isProjectPage,
withinOrganization,
isPublicURLPage,
} from "./nav-utils";

Expand All @@ -54,6 +55,7 @@
$: onReportPage = !!report;
$: onMetricsExplorerPage = isMetricsExplorerPage($page);
$: onPublicURLPage = isPublicURLPage($page);
$: witinOrgPage = withinOrganization($page);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: witin -> within


$: loggedIn = !!$user.data?.user;
$: rillLogoHref = !loggedIn ? "https://www.rilldata.com" : "/";
Expand Down Expand Up @@ -155,7 +157,7 @@

<div
class="flex items-center w-full pr-4 pl-2 py-1"
class:border-b={!onProjectPage}
class:border-b={!onProjectPage && !witinOrgPage}
>
<!-- Left side -->
<a
Expand Down
4 changes: 4 additions & 0 deletions web-admin/src/features/navigation/nav-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ export function isOrganizationPage(page: Page): boolean {
return page.route.id === "/[organization]";
}

export function withinOrganization(page: Page): boolean {
return !!page.route?.id?.startsWith("/[organization]");
}

export function isProjectPage(page: Page): boolean {
return (
page.route.id === "/[organization]/[project]" ||
Expand Down
73 changes: 73 additions & 0 deletions web-admin/src/features/organizations/OrganizationTabs.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<script lang="ts">
import { page } from "$app/stores";
import { createAdminServiceGetOrganization } from "@rilldata/web-admin/client";

$: ({
url: { pathname },
params: { organization },
} = $page);

// Get the list of tabs to display, depending on the user's permissions
$: tabsQuery = createAdminServiceGetOrganization(organization, {
query: {
select: (data) => {
let tabs = [
{
route: `/${organization}`,
label: "Projects",
},
];

if (data.permissions.manageOrgMembers) {
// TODO: users page
}

if (data.permissions.manageOrg) {
// TODO: once settings page is filled in we add these
tabs.push({
route: `/${organization}/-/settings`,
label: "Settings",
});
}

return tabs;
},
},
});

$: tabs = $tabsQuery.data;
</script>

<!-- Hide the tabs when there is only one entry -->
{#if tabs?.length && tabs?.length > 1}
<nav>
{#each tabs as tab (tab.route)}
<a href={tab.route} class:selected={pathname === tab.route}>
{tab.label}
</a>
{/each}
</nav>
{:else}
<!-- Add a border to keep things consistent. It is cleaner to handle this here. -->
<div class="border-b"></div>
{/if}

<style lang="postcss">
a {
@apply p-2 flex gap-x-1 items-center;
@apply rounded-sm text-gray-500;
@apply text-xs font-medium justify-center;
}

.selected {
@apply text-gray-900;
}

a:hover {
@apply bg-slate-100 text-gray-700;
}

nav {
@apply flex gap-x-6 px-[17px] border-b pt-1 pb-[3px];
}
</style>
13 changes: 12 additions & 1 deletion web-admin/src/routes/+layout.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
<script lang="ts">
import { page } from "$app/stores";
import { isProjectInvitePage } from "@rilldata/web-admin/features/navigation/nav-utils";
import {
isProjectInvitePage,
withinOrganization,
withinProject,
} from "@rilldata/web-admin/features/navigation/nav-utils";
import OrganizationTabs from "@rilldata/web-admin/features/organizations/OrganizationTabs.svelte";
import { initCloudMetrics } from "@rilldata/web-admin/features/telemetry/initCloudMetrics";
import BannerCenter from "@rilldata/web-common/components/banner/BannerCenter.svelte";
import NotificationCenter from "@rilldata/web-common/components/notifications/NotificationCenter.svelte";
Expand Down Expand Up @@ -45,6 +50,8 @@
$: isEmbed = $page.url.pathname === "/-/embed";
// invite page shouldn't show the top bar because it is considered an onboard step
$: hideTopBar = isProjectInvitePage($page);

$: withinOnlyOrg = withinOrganization($page) && !withinProject($page);
</script>

<svelte:head>
Expand All @@ -60,6 +67,10 @@
createMagicAuthTokens={projectPermissions?.createMagicAuthTokens}
manageProjectMembers={projectPermissions?.manageProjectMembers}
/>

{#if withinOnlyOrg}
<OrganizationTabs />
{/if}
{/if}
<ErrorBoundary>
<slot />
Expand Down
31 changes: 31 additions & 0 deletions web-admin/src/routes/[organization]/-/settings/+layout.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<script lang="ts">
import { page } from "$app/stores";
import LeftNav from "@rilldata/web-admin/components/nav/LeftNav.svelte";

$: organization = $page.params.organization;
$: basePage = `/${organization}/-/settings`;

const navItems = [
{
label: "General",
route: "general",
},
{
label: "Billing",
route: "billing",
},
{
label: "Usage",
route: "usage",
},
];
</script>

<LeftNav
title="Settings"
{basePage}
baseRoute="/[organization]/-/settings"
{navItems}
>
<slot />
</LeftNav>
Copy link
Contributor

@ericpgreen2 ericpgreen2 Aug 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than the main page content being a child of LeftNav, I think it'd be more conventional/semantic for the main page content and LeftNav component to be siblings, like:

<div class="layout-container">
  <LeftNav {title} {basePage} {baseRoute} {navItems} />
  <slot />
</div>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this approach, it'd also make sense to pull the "Settings" header out of the LeftNav component.

2 changes: 2 additions & 0 deletions web-admin/src/routes/[organization]/-/settings/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<script lang="ts">
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Coming soon
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Coming soon
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Coming soon
Loading