Merge pull request #3263 from Fredkiss3/feat/command-bar

feat: Command Palette for searching accross the dashboard
This commit is contained in:
Milo Schwartz
2026-07-07 21:17:39 -04:00
committed by GitHub
22 changed files with 1565 additions and 125 deletions
+4 -1
View File
@@ -12,7 +12,7 @@ import UserProvider from "@app/providers/UserProvider";
import { Layout } from "@app/components/Layout";
import { getTranslations } from "next-intl/server";
import { pullEnv } from "@app/lib/pullEnv";
import { orgNavSections } from "@app/app/navigation";
import { commandBarNavSections, orgNavSections } from "@app/app/navigation";
import { getCachedOrgUser } from "@app/lib/api/getCachedOrgUser";
export const dynamic = "force-dynamic";
@@ -82,6 +82,9 @@ export default async function SettingsLayout(props: SettingsLayoutProps) {
navItems={orgNavSections(env, {
isPrimaryOrg: primaryOrg
})}
commandNavItems={commandBarNavSections(env, {
isPrimaryOrg: primaryOrg
})}
>
{children}
</Layout>
@@ -1,18 +1,15 @@
import PrivateResourcesBanner from "@app/components/PrivateResourcesBanner";
import type { InternalResourceRow } from "@app/components/PrivateResourcesTable";
import PrivateResourcesTable from "@app/components/PrivateResourcesTable";
import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
import PrivateResourcesBanner from "@app/components/PrivateResourcesBanner";
import { internal } from "@app/lib/api";
import { authCookieHeader } from "@app/lib/api/cookies";
import { getCachedOrg } from "@app/lib/api/getCachedOrg";
import OrgProvider from "@app/providers/OrgProvider";
import type { ListResourcesResponse } from "@server/routers/resource";
import { GetSiteResponse } from "@server/routers/site/getSite";
import type { ListAllSiteResourcesByOrgResponse } from "@server/routers/siteResource";
import type ResponseT from "@server/types/Response";
import type { AxiosResponse } from "axios";
import { getTranslations } from "next-intl/server";
import type { Metadata } from "next";
import { getTranslations } from "next-intl/server";
import { redirect } from "next/navigation";
export const metadata: Metadata = {
@@ -24,13 +21,6 @@ export interface ClientResourcesPageProps {
searchParams: Promise<Record<string, string>>;
}
function parsePositiveInt(s: string | undefined): number | undefined {
if (!s) return undefined;
const n = Number(s);
if (!Number.isInteger(n) || n <= 0) return undefined;
return n;
}
export default async function ClientResourcesPage(
props: ClientResourcesPageProps
) {
@@ -39,7 +29,7 @@ export default async function ClientResourcesPage(
const searchParams = new URLSearchParams(await props.searchParams);
let siteResources: ListAllSiteResourcesByOrgResponse["siteResources"] = [];
let pagination: ListResourcesResponse["pagination"] = {
let pagination: ListAllSiteResourcesByOrgResponse["pagination"] = {
total: 0,
page: 1,
pageSize: 20
@@ -56,34 +46,6 @@ export default async function ClientResourcesPage(
pagination = responseData.pagination;
} catch (e) {}
const siteIdParam = parsePositiveInt(
searchParams.get("siteId") ?? undefined
);
let initialFilterSite: {
siteId: number;
name: string;
type: string;
} | null = null;
if (siteIdParam) {
try {
const siteRes = await internal.get(
`/site/${siteIdParam}`,
await authCookieHeader()
);
const s = (siteRes.data as ResponseT<GetSiteResponse>).data;
if (s && s.orgId === params.orgId) {
initialFilterSite = {
siteId: s.siteId,
name: s.name,
type: s.type
};
}
} catch {
// leave null
}
}
let org = null;
try {
const res = await getCachedOrg(params.orgId);
@@ -154,7 +116,6 @@ export default async function ClientResourcesPage(
pageIndex: pagination.page - 1,
pageSize: pagination.pageSize
}}
initialFilterSite={initialFilterSite}
/>
</OrgProvider>
</>
+232
View File
@@ -341,3 +341,235 @@ export const adminNavSections = (env?: Env): SidebarNavSection[] => [
]
}
];
export type CommandBarNavSection = {
// Added from 'dev' branch
heading: string;
items: CommandBarNavItem[];
};
export type CommandBarNavItem = {
href?: string;
title: string;
icon?: React.ReactNode;
showEE?: boolean;
isBeta?: boolean;
};
export const commandBarNavSections = (
env?: Env,
options?: OrgNavSectionsOptions
): CommandBarNavSection[] => [
{
heading: "network",
items: [
{
title: "commandSites",
href: "/{orgId}/settings/sites",
icon: <Plug className="size-4 flex-none" />
},
{
title: "commandProxyResources",
href: "/{orgId}/settings/resources/public",
icon: <Globe className="size-4 flex-none" />
},
{
title: "commandClientResources",
href: "/{orgId}/settings/resources/private",
icon: <GlobeLock className="size-4 flex-none" />
},
{
href: "/{orgId}/settings/clients/user",
title: "commandUserDevices",
icon: <Laptop className="size-4 flex-none" />
},
{
href: "/{orgId}/settings/clients/machine",
title: "commandMachineClients",
icon: <Server className="size-4 flex-none" />
},
...(build === "saas"
? [
{
title: "commandRemoteExitNodes",
href: "/{orgId}/settings/remote-exit-nodes",
icon: <Server className="size-4 flex-none" />
}
]
: [])
]
},
{
heading: "commandTeam",
items: [
{
title: "commandUsers",
href: "/{orgId}/settings/access/users",
icon: <User className="size-4 flex-none" />
},
{
title: "commandRoles",
href: "/{orgId}/settings/access/roles",
icon: <Users className="size-4 flex-none" />
},
{
title: "commandInvitations",
href: "/{orgId}/settings/access/invitations",
icon: <TicketCheck className="size-4 flex-none" />
}
]
},
{
heading: "accessControl",
items: [
...(!env?.flags.disableEnterpriseFeatures
? [
{
title: "commandResourcePolicies",
href: "/{orgId}/settings/policies/resources/public",
icon: <ShieldIcon className="size-4 flex-none" />
}
]
: []),
// PaidFeaturesAlert
...((build === "oss" && !env?.flags.disableEnterpriseFeatures) ||
build === "saas" ||
env?.app.identityProviderMode === "org" ||
(env?.app.identityProviderMode === undefined && build !== "oss")
? [
{
title: "commandIdentityProviders",
href: "/{orgId}/settings/idp",
icon: <Fingerprint className="size-4 flex-none" />
}
]
: []),
...(!env?.flags.disableEnterpriseFeatures
? [
{
title: "commandApprovals",
href: "/{orgId}/settings/access/approvals",
icon: <UserCog className="size-4 flex-none" />
}
]
: []),
{
title: "commandShareableLinks",
href: "/{orgId}/settings/share-links",
icon: <LinkIcon className="size-4 flex-none" />
}
]
},
{
heading: "commandLogsAndAnalytics",
items: [
{
title: "commandLogsAnalytics",
href: "/{orgId}/settings/logs/analytics",
icon: <ChartLine className="size-4 flex-none" />
},
{
title: "commandLogsRequest",
href: "/{orgId}/settings/logs/request",
icon: <SquareMousePointer className="size-4 flex-none" />
},
...(!env?.flags.disableEnterpriseFeatures
? [
{
title: "commandLogsAccess",
href: "/{orgId}/settings/logs/access",
icon: <ScanEye className="size-4 flex-none" />
},
{
title: "commandLogsAction",
href: "/{orgId}/settings/logs/action",
icon: <Logs className="size-4 flex-none" />
},
{
title: "commandLogsConnection",
href: "/{orgId}/settings/logs/connection",
icon: <Cable className="size-4 flex-none" />
},
{
title: "commandLogsStreaming",
href: "/{orgId}/settings/logs/streaming",
icon: <Unplug className="size-4 flex-none" />
}
]
: [])
]
},
{
heading: "commandManagement",
items: [
...(!env?.flags.disableEnterpriseFeatures
? [
{
title: "commandAlerting",
href: "/{orgId}/settings/alerting",
icon: <BellRing className="size-4 flex-none" />
},
{
title: "commandProvisioning",
href: "/{orgId}/settings/provisioning",
icon: <Boxes className="size-4 flex-none" />
}
]
: []),
{
title: "commandBluePrints",
href: "/{orgId}/settings/blueprints",
icon: <ReceiptText className="size-4 flex-none" />
},
{
title: "commandApiKeys",
href: "/{orgId}/settings/api-keys",
icon: <KeyRound className="size-4 flex-none" />
},
...(!env?.flags.disableEnterpriseFeatures
? [
{
title: "labels",
href: "/{orgId}/settings/labels",
icon: <TagIcon className="size-4 flex-none" />
}
]
: [])
]
},
{
heading: "commandOrganization",
items: [
{
title: "commandSettings",
href: "/{orgId}/settings/general",
icon: <Settings className="size-4 flex-none" />
},
{
title: "commandDomains",
href: "/{orgId}/settings/domains",
icon: <Globe className="size-4 flex-none" />
}
]
},
...(build === "saas" && options?.isPrimaryOrg
? [
{
heading: "commandBillingAndLicenses",
items: [
{
title: "commandBilling",
href: "/{orgId}/settings/billing",
icon: <CreditCard className="size-4 flex-none" />
},
{
title: "commandEnterpriseLicenses",
href: "/{orgId}/settings/license",
icon: <TicketCheck className="size-4 flex-none" />
}
]
}
]
: [])
];
+3 -1
View File
@@ -21,9 +21,11 @@ export default async function Page(props: {
searchParams: Promise<{
redirect: string | undefined;
t: string | undefined;
orgs?: string | undefined;
}>;
}) {
const params = await props.searchParams; // this is needed to prevent static optimization
const showOrgPicker = params.orgs === "1";
const env = pullEnv();
@@ -106,7 +108,7 @@ export default async function Page(props: {
}
}
if (targetOrgId) {
if (targetOrgId && !showOrgPicker) {
const targetOrg = orgs.find((org) => org.orgId === targetOrgId);
return (
<RedirectToOrg