Files
kandev/apps/web/lib/settings/workspace-settings-tabs.ts
2026-09-05 18:44:43 +00:00

79 lines
3.0 KiB
TypeScript

import type { ComponentType } from "react";
import {
IconArrowsShuffle,
IconApps,
IconBolt,
IconGitBranch,
IconKey,
IconLayoutGrid,
IconPlugConnected,
} from "@tabler/icons-react";
import { WORKSPACES_SETTINGS_HREF } from "@/lib/settings-discovery/catalog/workspaces";
/**
* The sections of a workspace's settings, as data.
*
* Extracted from `WorkspaceSettingsShell` so a second surface can read it
* without pulling in the shell's hooks: the settings menu's Workspaces branch
* lists exactly these tabs when the tree modes are on. Two surfaces naming the
* same sections is precisely how the menu and the page drift apart, so there is
* one table — the same reason `settings-menu-sections.ts` is data-only.
*/
export type WorkspaceSettingsTab =
| "overview"
| "repositories"
| "workflows"
| "canvases"
| "integrations"
| "automations"
| "secrets";
export function workspaceSettingsHref(workspaceId: string, tab: WorkspaceSettingsTab): string {
const base = `${WORKSPACES_SETTINGS_HREF}/${encodeURIComponent(workspaceId)}`;
return tab === "overview" ? base : `${base}/${tab}`;
}
export type WorkspaceTabSpec = {
tab: WorkspaceSettingsTab;
labelKey: string;
icon: ComponentType<{ className?: string }>;
};
/**
* `icon` is carried here rather than at the call sites that draw it, so no two
* surfaces can pick different marks for the same section. Four read this table:
* the tab strip, each tab's own page heading, the workspace list's section
* links, and the settings menu's Workspaces branch.
*/
export const WORKSPACE_SETTINGS_TABS: ReadonlyArray<WorkspaceTabSpec> = [
{ tab: "overview", labelKey: "workspaces:overview", icon: IconLayoutGrid },
{ tab: "repositories", labelKey: "sidebar:repositories", icon: IconGitBranch },
{ tab: "workflows", labelKey: "workflows:workflows", icon: IconArrowsShuffle },
{ tab: "canvases", labelKey: "canvases:canvases", icon: IconApps },
{ tab: "integrations", labelKey: "common:integrations", icon: IconPlugConnected },
{ tab: "automations", labelKey: "common:automations", icon: IconBolt },
{ tab: "secrets", labelKey: "settings:secrets", icon: IconKey },
];
/**
* The workspace settings catalog with optional canvas entries. Keeping the
* filter here means every settings surface shares the same route, label, and
* icon definitions while the disabled feature stays absent.
*/
export function getWorkspaceSettingsTabs(
canvasesEnabled: boolean,
): ReadonlyArray<WorkspaceTabSpec> {
return canvasesEnabled
? WORKSPACE_SETTINGS_TABS
: WORKSPACE_SETTINGS_TABS.filter(({ tab }) => tab !== "canvases");
}
/** The name and mark for a tab, for the surfaces that render one tab at a time. */
export function workspaceSettingsTabSpec(tab: WorkspaceSettingsTab): WorkspaceTabSpec {
// Every member of the union has a row, so the fallback is unreachable; it
// exists so a future tab cannot crash a page before its row is added.
return WORKSPACE_SETTINGS_TABS.find((entry) => entry.tab === tab) ?? WORKSPACE_SETTINGS_TABS[0];
}