@cellarnode/ui 0.194.0 → 0.195.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/certification-upload-card.d.ts.map +1 -1
- package/dist/components/certification-upload-card.js +5 -2
- package/dist/components/certification-upload-card.js.map +1 -1
- package/dist/components/confirmation-dialog.d.ts +3 -1
- package/dist/components/confirmation-dialog.d.ts.map +1 -1
- package/dist/components/confirmation-dialog.js +20 -2
- package/dist/components/confirmation-dialog.js.map +1 -1
- package/dist/components/copy-button.d.ts +23 -0
- package/dist/components/copy-button.d.ts.map +1 -0
- package/dist/components/copy-button.js +53 -0
- package/dist/components/copy-button.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/profile/api-keys/_story-fixtures.d.ts +3 -0
- package/dist/profile/api-keys/_story-fixtures.d.ts.map +1 -0
- package/dist/profile/api-keys/_story-fixtures.js +3 -0
- package/dist/profile/api-keys/_story-fixtures.js.map +1 -0
- package/dist/profile/api-keys/api-key-secret-reveal.d.ts +42 -0
- package/dist/profile/api-keys/api-key-secret-reveal.d.ts.map +1 -0
- package/dist/profile/api-keys/api-key-secret-reveal.js +56 -0
- package/dist/profile/api-keys/api-key-secret-reveal.js.map +1 -0
- package/dist/profile/api-keys/api-keys-card.d.ts +56 -0
- package/dist/profile/api-keys/api-keys-card.d.ts.map +1 -0
- package/dist/profile/api-keys/api-keys-card.js +77 -0
- package/dist/profile/api-keys/api-keys-card.js.map +1 -0
- package/dist/profile/api-keys/client-snippets.d.ts +20 -0
- package/dist/profile/api-keys/client-snippets.d.ts.map +1 -0
- package/dist/profile/api-keys/client-snippets.js +79 -0
- package/dist/profile/api-keys/client-snippets.js.map +1 -0
- package/dist/profile/api-keys/connected-apps-card.d.ts +39 -0
- package/dist/profile/api-keys/connected-apps-card.d.ts.map +1 -0
- package/dist/profile/api-keys/connected-apps-card.js +54 -0
- package/dist/profile/api-keys/connected-apps-card.js.map +1 -0
- package/dist/profile/api-keys/create-api-key-dialog.d.ts +51 -0
- package/dist/profile/api-keys/create-api-key-dialog.d.ts.map +1 -0
- package/dist/profile/api-keys/create-api-key-dialog.js +114 -0
- package/dist/profile/api-keys/create-api-key-dialog.js.map +1 -0
- package/dist/profile/api-keys/format.d.ts +20 -0
- package/dist/profile/api-keys/format.d.ts.map +1 -0
- package/dist/profile/api-keys/format.js +58 -0
- package/dist/profile/api-keys/format.js.map +1 -0
- package/dist/profile/api-keys/index.d.ts +19 -0
- package/dist/profile/api-keys/index.d.ts.map +1 -0
- package/dist/profile/api-keys/index.js +10 -0
- package/dist/profile/api-keys/index.js.map +1 -0
- package/dist/profile/api-keys/mock-client.d.ts +23 -0
- package/dist/profile/api-keys/mock-client.d.ts.map +1 -0
- package/dist/profile/api-keys/mock-client.js +167 -0
- package/dist/profile/api-keys/mock-client.js.map +1 -0
- package/dist/profile/api-keys/profile-keys-section.d.ts +36 -0
- package/dist/profile/api-keys/profile-keys-section.d.ts.map +1 -0
- package/dist/profile/api-keys/profile-keys-section.js +97 -0
- package/dist/profile/api-keys/profile-keys-section.js.map +1 -0
- package/dist/profile/api-keys/revoke-confirm.d.ts +26 -0
- package/dist/profile/api-keys/revoke-confirm.d.ts.map +1 -0
- package/dist/profile/api-keys/revoke-confirm.js +26 -0
- package/dist/profile/api-keys/revoke-confirm.js.map +1 -0
- package/dist/profile/api-keys/scope-list.d.ts +36 -0
- package/dist/profile/api-keys/scope-list.d.ts.map +1 -0
- package/dist/profile/api-keys/scope-list.js +29 -0
- package/dist/profile/api-keys/scope-list.js.map +1 -0
- package/dist/profile/api-keys/types.d.ts +111 -0
- package/dist/profile/api-keys/types.d.ts.map +1 -0
- package/dist/profile/api-keys/types.js +147 -0
- package/dist/profile/api-keys/types.js.map +1 -0
- package/dist/profile/index.d.ts +1 -0
- package/dist/profile/index.d.ts.map +1 -1
- package/dist/profile/index.js +2 -0
- package/dist/profile/index.js.map +1 -1
- package/dist/profile/profile.d.ts +3 -1
- package/dist/profile/profile.d.ts.map +1 -1
- package/dist/profile/profile.js +2 -2
- package/dist/profile/profile.js.map +1 -1
- package/package.json +1 -1
- package/src/theme/tokens.css +5 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { ChevronDownIcon, KeyRoundIcon, PlusIcon, RefreshCwIcon } from "lucide-react";
|
|
4
|
+
import { Badge } from "../../components/badge.js";
|
|
5
|
+
import { Button } from "../../components/button.js";
|
|
6
|
+
import { EmptyState } from "../../components/empty-state.js";
|
|
7
|
+
import { Skeleton } from "../../components/skeleton.js";
|
|
8
|
+
import { ProfileCard } from "../profile.js";
|
|
9
|
+
import { fmt, formatDate, formatRelative, maskedKey } from "./format.js";
|
|
10
|
+
import { ScopeList, SurfaceBadge } from "./scope-list.js";
|
|
11
|
+
import { API_KEY_LIMITS } from "./types.js";
|
|
12
|
+
const DEFAULTS = {
|
|
13
|
+
title: "API keys",
|
|
14
|
+
description: "Use a personal key to connect AI tools that cannot sign in with a browser. Keys act as you, in this organisation only.",
|
|
15
|
+
create: "Create key",
|
|
16
|
+
slotsLeft: "{left} of {max} key slots left",
|
|
17
|
+
atCap: "You have reached the limit of {max} active keys. Revoke one to create another.",
|
|
18
|
+
emptyTitle: "No API keys yet",
|
|
19
|
+
emptyDescription: "Create a key to connect a tool such as Claude Code, Cursor or Codex.",
|
|
20
|
+
emptyAction: "Create your first key",
|
|
21
|
+
lastUsed: "Last used {when}",
|
|
22
|
+
neverUsed: "Never used",
|
|
23
|
+
expires: "Expires {when}",
|
|
24
|
+
expiredOn: "Expired {when}",
|
|
25
|
+
created: "Created {when}",
|
|
26
|
+
revoke: "Revoke",
|
|
27
|
+
revokeNamed: "Revoke key {name}",
|
|
28
|
+
maskedKeyLabel: "Key starting {prefix}, ending {hint}",
|
|
29
|
+
inactive: "Inactive keys ({count})",
|
|
30
|
+
statusExpired: "Expired",
|
|
31
|
+
statusRevoked: "Revoked",
|
|
32
|
+
loadFailed: "Your API keys could not be loaded.",
|
|
33
|
+
retry: "Try again",
|
|
34
|
+
loading: "Loading API keys",
|
|
35
|
+
};
|
|
36
|
+
export function ApiKeysCard({ keys, isLoading = false, isError = false, onRetry, onCreate, onRevoke, maxKeys = API_KEY_LIMITS.maxKeys, locale, now, labels, className, headingId, }) {
|
|
37
|
+
const l = { ...DEFAULTS, ...labels };
|
|
38
|
+
const [mountedAt] = React.useState(() => Date.now());
|
|
39
|
+
const clock = now ?? mountedAt;
|
|
40
|
+
const capId = React.useId();
|
|
41
|
+
const rows = keys ?? [];
|
|
42
|
+
const activeRows = rows.filter((k) => k.status === "active");
|
|
43
|
+
const inactiveRows = rows.filter((k) => k.status !== "active");
|
|
44
|
+
const atCap = activeRows.length >= maxKeys;
|
|
45
|
+
const renderRow = (key) => {
|
|
46
|
+
const inactive = key.status !== "active";
|
|
47
|
+
const meta = [
|
|
48
|
+
key.lastUsedAt
|
|
49
|
+
? fmt(l.lastUsed, { when: formatRelative(key.lastUsedAt, clock, locale) })
|
|
50
|
+
: l.neverUsed,
|
|
51
|
+
key.status === "active"
|
|
52
|
+
? fmt(l.expires, { when: formatDate(key.expiresAt, locale) })
|
|
53
|
+
: key.status === "expired"
|
|
54
|
+
? fmt(l.expiredOn, { when: formatDate(key.expiresAt, locale) })
|
|
55
|
+
: null,
|
|
56
|
+
].filter((x) => x !== null);
|
|
57
|
+
return (_jsxs("li", { className: "flex flex-col gap-2 py-4 first:pt-0 last:pb-0", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "min-w-0 break-words text-sm/6 font-medium text-foreground", children: key.name }), _jsx(SurfaceBadge, { surface: key.surface, labels: labels }), key.status === "expired" ? _jsx(Badge, { color: "warning", children: l.statusExpired }) : null, key.status === "revoked" ? _jsx(Badge, { color: "neutral", children: l.statusRevoked }) : null] }), _jsx("p", { className: "mt-1 font-mono text-sm/5 text-muted-foreground", "aria-label": fmt(l.maskedKeyLabel, { prefix: key.prefix, hint: key.hint }), children: maskedKey(key.prefix, key.hint) })] }), !inactive ? (_jsx(Button, { plain: true, className: "min-h-11 shrink-0", "aria-label": fmt(l.revokeNamed, { name: key.name }), onClick: () => onRevoke(key), children: l.revoke })) : null] }), _jsx("p", { className: "text-sm/6 text-muted-foreground", children: meta.join(" · ") }), _jsx(ScopeList, { surface: key.surface, scopes: key.scopes, labels: labels, children: _jsx("p", { children: fmt(l.created, { when: formatDate(key.createdAt, locale) }) }) })] }, key.id));
|
|
58
|
+
};
|
|
59
|
+
let body;
|
|
60
|
+
if (isLoading) {
|
|
61
|
+
body = (_jsxs("div", { role: "status", "aria-busy": "true", className: "flex flex-col gap-4", children: [_jsx("span", { className: "sr-only", children: l.loading }), _jsx(Skeleton, { className: "h-24 w-full" }), _jsx(Skeleton, { className: "h-24 w-full" })] }));
|
|
62
|
+
}
|
|
63
|
+
else if (isError) {
|
|
64
|
+
body = (_jsxs("div", { role: "alert", className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx("p", { className: "text-sm/6 text-foreground", children: l.loadFailed }), onRetry ? (_jsxs(Button, { outline: true, className: "min-h-11", onClick: onRetry, children: [_jsx(RefreshCwIcon, { "data-slot": "icon", "aria-hidden": "true" }), l.retry] })) : null] }));
|
|
65
|
+
}
|
|
66
|
+
else if (rows.length === 0) {
|
|
67
|
+
body = (_jsx(EmptyState, { icon: _jsx(KeyRoundIcon, { className: "size-5" }), headline: l.emptyTitle, description: l.emptyDescription, entranceMotion: false, actions: _jsxs(Button, { color: "brand", className: "min-h-11", onClick: onCreate, children: [_jsx(PlusIcon, { "data-slot": "icon", "aria-hidden": "true" }), l.emptyAction] }) }));
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
body = (_jsxs("div", { className: "flex flex-col gap-4", children: [activeRows.length > 0 ? (_jsx("ul", { className: "divide-y divide-border/60", children: activeRows.map(renderRow) })) : null, inactiveRows.length > 0 ? (_jsxs("details", { className: "group border-t border-border/60 pt-3", children: [_jsxs("summary", { className: "inline-flex min-h-11 cursor-pointer items-center rounded-sm text-sm/6 font-medium text-foreground focus-visible:outline-2 focus-visible:outline-ring sm:min-h-8", children: [_jsx(ChevronDownIcon, { "aria-hidden": "true", className: "mr-1.5 size-4 transition-transform group-open:rotate-180 motion-reduce:transition-none" }), fmt(l.inactive, { count: inactiveRows.length })] }), _jsx("ul", { className: "mt-2 divide-y divide-border/60", children: inactiveRows.map(renderRow) })] })) : null] }));
|
|
71
|
+
}
|
|
72
|
+
const showFooter = !isLoading && !isError && rows.length > 0;
|
|
73
|
+
return (_jsx(ProfileCard, { title: l.title, description: l.description, headingId: headingId, ...(className !== undefined ? { className } : {}), footer: showFooter ? (_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx("p", { id: capId, className: `text-sm/6 ${atCap ? "font-medium text-foreground" : "text-muted-foreground"}`, children: atCap
|
|
74
|
+
? fmt(l.atCap, { max: maxKeys })
|
|
75
|
+
: fmt(l.slotsLeft, { left: maxKeys - activeRows.length, max: maxKeys }) }), _jsxs(Button, { color: "brand", className: "min-h-11", disabled: atCap, "aria-describedby": capId, onClick: onCreate, children: [_jsx(PlusIcon, { "data-slot": "icon", "aria-hidden": "true" }), l.create] })] })) : undefined, children: body }));
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=api-keys-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-keys-card.js","sourceRoot":"","sources":["../../../src/profile/api-keys/api-keys-card.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type SurfaceId } from "./types.js";
|
|
2
|
+
export type ClientSnippetId = "claude-code" | "cursor" | "codex" | "xai" | "openclaw";
|
|
3
|
+
export interface ClientSnippet {
|
|
4
|
+
id: ClientSnippetId;
|
|
5
|
+
label: string;
|
|
6
|
+
/** Where the snippet goes, one line. */
|
|
7
|
+
where: string;
|
|
8
|
+
language: string;
|
|
9
|
+
code: string;
|
|
10
|
+
/** Extra guidance for this client, when it has a catch. */
|
|
11
|
+
note?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Clients that can read the key from the environment never get the raw key in their snippet (it would
|
|
15
|
+
* land in shell history, a dotfile, or a repo). The xAI request body and OpenClaw keep it inline:
|
|
16
|
+
* the xAI snippet is an API payload, and OpenClaw's env support is not documented, so its note says
|
|
17
|
+
* the file now holds a secret.
|
|
18
|
+
*/
|
|
19
|
+
export declare function buildClientSnippets(surface: SurfaceId, key: string, base?: string): ClientSnippet[];
|
|
20
|
+
//# sourceMappingURL=client-snippets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-snippets.d.ts","sourceRoot":"","sources":["../../../src/profile/api-keys/client-snippets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAEjD,MAAM,MAAM,eAAe,GAAG,aAAa,GAAG,QAAQ,GAAG,OAAO,GAAG,KAAK,GAAG,UAAU,CAAC;AAEtF,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,eAAe,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAUD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,SAAS,EAClB,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,MAAM,GACZ,aAAa,EAAE,CAoEjB"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { mcpUrl } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Copy-paste setup for the clients that take a static header (spec (e) "Which clients use PATs").
|
|
4
|
+
* The raw key is interpolated: these only ever render inside the one-time reveal.
|
|
5
|
+
*/
|
|
6
|
+
/** Env references the clients expand themselves at start (verified in their MCP docs). */
|
|
7
|
+
const ENV_REF_CLAUDE = "${CELLARNODE_MCP_KEY}";
|
|
8
|
+
const ENV_REF_CURSOR = "${env:CELLARNODE_MCP_KEY}";
|
|
9
|
+
/**
|
|
10
|
+
* Clients that can read the key from the environment never get the raw key in their snippet (it would
|
|
11
|
+
* land in shell history, a dotfile, or a repo). The xAI request body and OpenClaw keep it inline:
|
|
12
|
+
* the xAI snippet is an API payload, and OpenClaw's env support is not documented, so its note says
|
|
13
|
+
* the file now holds a secret.
|
|
14
|
+
*/
|
|
15
|
+
export function buildClientSnippets(surface, key, base) {
|
|
16
|
+
const url = mcpUrl(surface, base);
|
|
17
|
+
const json = (value) => JSON.stringify(value, null, 2);
|
|
18
|
+
return [
|
|
19
|
+
{
|
|
20
|
+
id: "claude-code",
|
|
21
|
+
label: "Claude Code",
|
|
22
|
+
where: "Paste the key when asked (nothing is shown or saved to shell history), save the JSON as .mcp.json in your project, then start Claude Code from this same terminal.",
|
|
23
|
+
language: "bash",
|
|
24
|
+
code: `read -rs CELLARNODE_MCP_KEY && export CELLARNODE_MCP_KEY\n\n# .mcp.json\n${json({
|
|
25
|
+
mcpServers: {
|
|
26
|
+
cellarnode: {
|
|
27
|
+
type: "http",
|
|
28
|
+
url,
|
|
29
|
+
headers: { Authorization: `Bearer ${ENV_REF_CLAUDE}` },
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
})}`,
|
|
33
|
+
note: "Claude Code reads ${CELLARNODE_MCP_KEY} from your environment each time it starts, so the key is never written to .mcp.json or to your shell history.",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: "cursor",
|
|
37
|
+
label: "Cursor",
|
|
38
|
+
where: "Paste the key when asked, add the JSON to ~/.cursor/mcp.json, then start Cursor from this same terminal (for example `cursor .`).",
|
|
39
|
+
language: "bash",
|
|
40
|
+
code: `read -rs CELLARNODE_MCP_KEY && export CELLARNODE_MCP_KEY\n\n# ~/.cursor/mcp.json\n${json({
|
|
41
|
+
mcpServers: {
|
|
42
|
+
cellarnode: { url, headers: { Authorization: `Bearer ${ENV_REF_CURSOR}` } },
|
|
43
|
+
},
|
|
44
|
+
})}`,
|
|
45
|
+
note: "Cursor only sees the variable when it is started from a shell that has it, or when it is set in your operating system environment.",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: "codex",
|
|
49
|
+
label: "Codex",
|
|
50
|
+
where: "Paste the key when asked, add the config to ~/.codex/config.toml, then start Codex from this same terminal.",
|
|
51
|
+
language: "bash",
|
|
52
|
+
code: `read -rs CELLARNODE_MCP_KEY && export CELLARNODE_MCP_KEY\n\n# ~/.codex/config.toml\n[mcp_servers.cellarnode]\nurl = "${url}"\nbearer_token_env_var = "CELLARNODE_MCP_KEY"`,
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: "xai",
|
|
56
|
+
label: "xAI API",
|
|
57
|
+
where: "Add to the tools array of a Responses API request.",
|
|
58
|
+
language: "json",
|
|
59
|
+
code: json({
|
|
60
|
+
type: "mcp",
|
|
61
|
+
server_label: "cellarnode",
|
|
62
|
+
server_url: url,
|
|
63
|
+
headers: { Authorization: `Bearer ${key}` },
|
|
64
|
+
}),
|
|
65
|
+
note: "Use a Read-only key here: this client has no step that asks you before a tool changes data.",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: "openclaw",
|
|
69
|
+
label: "OpenClaw",
|
|
70
|
+
where: "Add to your mcporter server list.",
|
|
71
|
+
language: "json",
|
|
72
|
+
code: json({
|
|
73
|
+
mcpServers: { cellarnode: { url, headers: { Authorization: `Bearer ${key}` } } },
|
|
74
|
+
}),
|
|
75
|
+
note: 'This file now holds your key: keep it private (`chmod 600`) and out of version control. OpenClaw ignores custom headers while a server is set to auth: "oauth", so leave that unset for this server.',
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=client-snippets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-snippets.js","sourceRoot":"","sources":["../../../src/profile/api-keys/client-snippets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAkB,MAAM,SAAS,CAAC;AAejD;;;GAGG;AACH,0FAA0F;AAC1F,MAAM,cAAc,GAAG,uBAAuB,CAAC;AAC/C,MAAM,cAAc,GAAG,2BAA2B,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAAkB,EAClB,GAAW,EACX,IAAa;IAEb,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,CAAC,KAAc,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAChE,OAAO;QACL;YACE,EAAE,EAAE,aAAa;YACjB,KAAK,EAAE,aAAa;YACpB,KAAK,EACH,oKAAoK;YACtK,QAAQ,EAAE,MAAM;YAChB,IAAI,EAAE,4EAA4E,IAAI,CAAC;gBACrF,UAAU,EAAE;oBACV,UAAU,EAAE;wBACV,IAAI,EAAE,MAAM;wBACZ,GAAG;wBACH,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,cAAc,EAAE,EAAE;qBACvD;iBACF;aACF,CAAC,EAAE;YACJ,IAAI,EAAE,uJAAuJ;SAC9J;QACD;YACE,EAAE,EAAE,QAAQ;YACZ,KAAK,EAAE,QAAQ;YACf,KAAK,EACH,mIAAmI;YACrI,QAAQ,EAAE,MAAM;YAChB,IAAI,EAAE,qFAAqF,IAAI,CAC7F;gBACE,UAAU,EAAE;oBACV,UAAU,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,cAAc,EAAE,EAAE,EAAE;iBAC5E;aACF,CACF,EAAE;YACH,IAAI,EAAE,oIAAoI;SAC3I;QACD;YACE,EAAE,EAAE,OAAO;YACX,KAAK,EAAE,OAAO;YACd,KAAK,EACH,6GAA6G;YAC/G,QAAQ,EAAE,MAAM;YAChB,IAAI,EAAE,wHAAwH,GAAG,gDAAgD;SAClL;QACD;YACE,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,oDAAoD;YAC3D,QAAQ,EAAE,MAAM;YAChB,IAAI,EAAE,IAAI,CAAC;gBACT,IAAI,EAAE,KAAK;gBACX,YAAY,EAAE,YAAY;gBAC1B,UAAU,EAAE,GAAG;gBACf,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,GAAG,EAAE,EAAE;aAC5C,CAAC;YACF,IAAI,EAAE,6FAA6F;SACpG;QACD;YACE,EAAE,EAAE,UAAU;YACd,KAAK,EAAE,UAAU;YACjB,KAAK,EAAE,mCAAmC;YAC1C,QAAQ,EAAE,MAAM;YAChB,IAAI,EAAE,IAAI,CAAC;gBACT,UAAU,EAAE,EAAE,UAAU,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,GAAG,EAAE,EAAE,EAAE,EAAE;aACjF,CAAC;YACF,IAAI,EAAE,sMAAsM;SAC7M;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type ScopeListLabels } from "./scope-list.js";
|
|
2
|
+
import type { OAuthGrantRow } from "./types.js";
|
|
3
|
+
export interface ConnectedAppsCardLabels extends ScopeListLabels {
|
|
4
|
+
title?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
emptyTitle?: string;
|
|
7
|
+
emptyDescription?: string;
|
|
8
|
+
unverified?: string;
|
|
9
|
+
/** Calm explanation under an unverified app. */
|
|
10
|
+
unverifiedHint?: string;
|
|
11
|
+
/** "{host}" placeholder. */
|
|
12
|
+
host?: string;
|
|
13
|
+
/** "{when}" placeholder. */
|
|
14
|
+
lastUsed?: string;
|
|
15
|
+
neverUsed?: string;
|
|
16
|
+
/** "{when}" placeholder. */
|
|
17
|
+
connected?: string;
|
|
18
|
+
revoke?: string;
|
|
19
|
+
/** "{name}" placeholder. */
|
|
20
|
+
revokeNamed?: string;
|
|
21
|
+
loadFailed?: string;
|
|
22
|
+
retry?: string;
|
|
23
|
+
loading?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface ConnectedAppsCardProps {
|
|
26
|
+
grants?: readonly OAuthGrantRow[] | undefined;
|
|
27
|
+
isLoading?: boolean;
|
|
28
|
+
isError?: boolean;
|
|
29
|
+
onRetry?: (() => void) | undefined;
|
|
30
|
+
onRevoke: (grant: OAuthGrantRow) => void;
|
|
31
|
+
locale?: string | undefined;
|
|
32
|
+
now?: number | undefined;
|
|
33
|
+
labels?: ConnectedAppsCardLabels | undefined;
|
|
34
|
+
className?: string | undefined;
|
|
35
|
+
headingId?: string | undefined;
|
|
36
|
+
}
|
|
37
|
+
/** OAuth grants (spec (f)): who may act as you, with an unmistakable treatment for unverified apps. */
|
|
38
|
+
export declare function ConnectedAppsCard({ grants, isLoading, isError, onRetry, onRevoke, locale, now, labels, className, headingId, }: ConnectedAppsCardProps): import("react/jsx-runtime").JSX.Element;
|
|
39
|
+
//# sourceMappingURL=connected-apps-card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connected-apps-card.d.ts","sourceRoot":"","sources":["../../../src/profile/api-keys/connected-apps-card.tsx"],"names":[],"mappings":"AAQA,OAAO,EAA2B,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAC7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,MAAM,WAAW,uBAAwB,SAAQ,eAAe;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4BAA4B;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAqBD,MAAM,WAAW,sBAAsB;IACrC,MAAM,CAAC,EAAE,SAAS,aAAa,EAAE,GAAG,SAAS,CAAC;IAC9C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IACnC,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,MAAM,CAAC,EAAE,uBAAuB,GAAG,SAAS,CAAC;IAC7C,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,uGAAuG;AACvG,wBAAgB,iBAAiB,CAAC,EAChC,MAAM,EACN,SAAiB,EACjB,OAAe,EACf,OAAO,EACP,QAAQ,EACR,MAAM,EACN,GAAG,EACH,MAAM,EACN,SAAS,EACT,SAAS,GACV,EAAE,sBAAsB,2CAuGxB"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { PlugZapIcon, RefreshCwIcon, TriangleAlertIcon } from "lucide-react";
|
|
4
|
+
import { Badge } from "../../components/badge.js";
|
|
5
|
+
import { Button } from "../../components/button.js";
|
|
6
|
+
import { EmptyState } from "../../components/empty-state.js";
|
|
7
|
+
import { Skeleton } from "../../components/skeleton.js";
|
|
8
|
+
import { ProfileCard } from "../profile.js";
|
|
9
|
+
import { fmt, formatDate, formatRelative } from "./format.js";
|
|
10
|
+
import { ScopeList, SurfaceBadge } from "./scope-list.js";
|
|
11
|
+
const DEFAULTS = {
|
|
12
|
+
title: "Connected apps",
|
|
13
|
+
description: "Apps you signed in to CellarNode with. Disconnect any you no longer use.",
|
|
14
|
+
emptyTitle: "No connected apps",
|
|
15
|
+
emptyDescription: "Apps appear here after you approve them, for example from ChatGPT or Claude.",
|
|
16
|
+
unverified: "Unverified app",
|
|
17
|
+
unverifiedHint: "CellarNode hasn't verified who runs this app. Disconnect it if you don't recognise it.",
|
|
18
|
+
host: "Sends you back to {host}",
|
|
19
|
+
lastUsed: "Last used {when}",
|
|
20
|
+
neverUsed: "Never used",
|
|
21
|
+
connected: "Connected {when}",
|
|
22
|
+
revoke: "Disconnect",
|
|
23
|
+
revokeNamed: "Disconnect {name}",
|
|
24
|
+
loadFailed: "Your connected apps could not be loaded.",
|
|
25
|
+
retry: "Try again",
|
|
26
|
+
loading: "Loading connected apps",
|
|
27
|
+
};
|
|
28
|
+
/** OAuth grants (spec (f)): who may act as you, with an unmistakable treatment for unverified apps. */
|
|
29
|
+
export function ConnectedAppsCard({ grants, isLoading = false, isError = false, onRetry, onRevoke, locale, now, labels, className, headingId, }) {
|
|
30
|
+
const l = { ...DEFAULTS, ...labels };
|
|
31
|
+
const [mountedAt] = React.useState(() => Date.now());
|
|
32
|
+
const clock = now ?? mountedAt;
|
|
33
|
+
const rows = grants ?? [];
|
|
34
|
+
let body;
|
|
35
|
+
if (isLoading) {
|
|
36
|
+
body = (_jsxs("div", { role: "status", "aria-busy": "true", className: "flex flex-col gap-4", children: [_jsx("span", { className: "sr-only", children: l.loading }), _jsx(Skeleton, { className: "h-24 w-full" })] }));
|
|
37
|
+
}
|
|
38
|
+
else if (isError) {
|
|
39
|
+
body = (_jsxs("div", { role: "alert", className: "flex flex-wrap items-center justify-between gap-3", children: [_jsx("p", { className: "text-sm/6 text-foreground", children: l.loadFailed }), onRetry ? (_jsxs(Button, { outline: true, className: "min-h-11", onClick: onRetry, children: [_jsx(RefreshCwIcon, { "data-slot": "icon", "aria-hidden": "true" }), l.retry] })) : null] }));
|
|
40
|
+
}
|
|
41
|
+
else if (rows.length === 0) {
|
|
42
|
+
body = (_jsx(EmptyState, { icon: _jsx(PlugZapIcon, { className: "size-5" }), headline: l.emptyTitle, description: l.emptyDescription, entranceMotion: false }));
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
body = (_jsx("ul", { className: "divide-y divide-border/60", children: rows.map((grant) => (_jsxs("li", { className: "flex flex-col gap-2 py-4 first:pt-0 last:pb-0", children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsx("div", { className: "min-w-0 flex-1", children: _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [grant.unverified ? (_jsxs(Badge, { color: "warning", children: [_jsx(TriangleAlertIcon, { className: "mr-1 size-3.5", "aria-hidden": "true" }), l.unverified] })) : null, _jsx("span", { className: "min-w-0 break-words text-sm/6 font-medium text-foreground", children: grant.clientName }), _jsx(SurfaceBadge, { surface: grant.surface, labels: labels })] }) }), _jsx(Button, { plain: true, className: "min-h-11 shrink-0", "aria-label": fmt(l.revokeNamed, { name: grant.clientName }), onClick: () => onRevoke(grant), children: l.revoke })] }), grant.unverified ? (_jsxs("div", { children: [_jsx("p", { className: "text-sm/6 text-foreground", children: l.unverifiedHint }), grant.clientHost ? (_jsx("p", { className: "mt-1.5 break-all rounded-lg bg-(--tone-warning-soft) px-3 py-2 text-sm/6 font-medium text-(--tone-warning-fg)", children: fmt(l.host, { host: grant.clientHost }) })) : null] })) : grant.clientHost ? (_jsx("p", { className: "break-all text-sm/6 text-muted-foreground", children: fmt(l.host, { host: grant.clientHost }) })) : null, _jsx("p", { className: "text-sm/6 text-muted-foreground", children: [
|
|
46
|
+
grant.lastUsedAt
|
|
47
|
+
? fmt(l.lastUsed, { when: formatRelative(grant.lastUsedAt, clock, locale) })
|
|
48
|
+
: l.neverUsed,
|
|
49
|
+
fmt(l.connected, { when: formatDate(grant.createdAt, locale) }),
|
|
50
|
+
].join(" · ") }), _jsx(ScopeList, { surface: grant.surface, scopes: grant.scopes, labels: labels })] }, grant.id))) }));
|
|
51
|
+
}
|
|
52
|
+
return (_jsx(ProfileCard, { title: l.title, description: l.description, headingId: headingId, ...(className !== undefined ? { className } : {}), children: body }));
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=connected-apps-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connected-apps-card.js","sourceRoot":"","sources":["../../../src/profile/api-keys/connected-apps-card.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type ApiKeySurface, type CreateApiKeyInput } from "./types.js";
|
|
2
|
+
export interface CreateApiKeyDialogLabels {
|
|
3
|
+
title?: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
namePlaceholder?: string;
|
|
7
|
+
nameRequired?: string;
|
|
8
|
+
surface?: string;
|
|
9
|
+
access?: string;
|
|
10
|
+
accessRead?: string;
|
|
11
|
+
accessReadHint?: string;
|
|
12
|
+
accessWrite?: string;
|
|
13
|
+
accessWriteHint?: string;
|
|
14
|
+
customise?: string;
|
|
15
|
+
/** "{count}" placeholder. */
|
|
16
|
+
accessCustom?: string;
|
|
17
|
+
/** Shown instead of the access choice when the area has no write permissions at all (read-only). */
|
|
18
|
+
accessReadOnlyArea?: string;
|
|
19
|
+
customiseHint?: string;
|
|
20
|
+
expiry?: string;
|
|
21
|
+
/** "{days}" placeholder. */
|
|
22
|
+
expiryDays?: string;
|
|
23
|
+
expiryCustom?: string;
|
|
24
|
+
expiryDate?: string;
|
|
25
|
+
/** "{max}" placeholder. */
|
|
26
|
+
expiryDateHint?: string;
|
|
27
|
+
expiryDateInvalid?: string;
|
|
28
|
+
scopesRequired?: string;
|
|
29
|
+
submit?: string;
|
|
30
|
+
submitting?: string;
|
|
31
|
+
cancel?: string;
|
|
32
|
+
createFailed?: string;
|
|
33
|
+
/** Overrides the surface option labels / descriptions. */
|
|
34
|
+
surfaces?: Partial<Record<ApiKeySurface, {
|
|
35
|
+
label?: string;
|
|
36
|
+
description?: string;
|
|
37
|
+
}>>;
|
|
38
|
+
}
|
|
39
|
+
export interface CreateApiKeyDialogProps {
|
|
40
|
+
open: boolean;
|
|
41
|
+
onClose: () => void;
|
|
42
|
+
/** Creates the key. Resolve to close the form; reject to show an error and keep it open. */
|
|
43
|
+
onSubmit: (input: CreateApiKeyInput) => Promise<void>;
|
|
44
|
+
/** Surfaces this org may offer (producer org: producer, readonly, elabel if entitled; importer org: importer, readonly). Default all four. Never `admin`. */
|
|
45
|
+
surfaces?: readonly ApiKeySurface[] | undefined;
|
|
46
|
+
labels?: CreateApiKeyDialogLabels | undefined;
|
|
47
|
+
/** Clock for the custom-date bounds. */
|
|
48
|
+
now?: number | undefined;
|
|
49
|
+
}
|
|
50
|
+
export declare function CreateApiKeyDialog(props: CreateApiKeyDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
51
|
+
//# sourceMappingURL=create-api-key-dialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-api-key-dialog.d.ts","sourceRoot":"","sources":["../../../src/profile/api-keys/create-api-key-dialog.tsx"],"names":[],"mappings":"AAgBA,OAAO,EAQL,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACvB,MAAM,SAAS,CAAC;AAEjB,MAAM,WAAW,wBAAwB;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6BAA6B;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oGAAoG;IACpG,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2BAA2B;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;CACrF;AAgCD,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,4FAA4F;IAC5F,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,6JAA6J;IAC7J,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,GAAG,SAAS,CAAC;IAChD,MAAM,CAAC,EAAE,wBAAwB,GAAG,SAAS,CAAC;IAC9C,wCAAwC;IACxC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,2CAOhE"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ChevronDownIcon } from "lucide-react";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Button } from "../../components/button.js";
|
|
5
|
+
import { Checkbox, CheckboxField, CheckboxGroup } from "../../components/checkbox.js";
|
|
6
|
+
import { Dialog, DialogActions, DialogBody, DialogDescription, DialogTitle, } from "../../components/dialog.js";
|
|
7
|
+
import { ErrorMessage, Description, Field, Label } from "../../components/fieldset.js";
|
|
8
|
+
import { Input } from "../../components/input.js";
|
|
9
|
+
import { Radio, RadioField, RadioGroup } from "../../components/radio.js";
|
|
10
|
+
import { Select } from "../../components/select.js";
|
|
11
|
+
import { endOfLocalDayIso, expiryBounds, fmt } from "./format.js";
|
|
12
|
+
import { allScopes, API_KEY_LIMITS, API_KEY_SURFACES, readScopes, SURFACE_CATALOG, summarizeScopes, surfaceAllowsChanges, } from "./types.js";
|
|
13
|
+
const DEFAULTS = {
|
|
14
|
+
title: "Create API key",
|
|
15
|
+
description: "The key acts as you, in this organisation only. You will see it once, right after you create it.",
|
|
16
|
+
name: "Name",
|
|
17
|
+
namePlaceholder: "For example, Claude Code on my laptop",
|
|
18
|
+
nameRequired: "Give the key a name so you can recognise it later.",
|
|
19
|
+
surface: "What can the key reach?",
|
|
20
|
+
access: "Access",
|
|
21
|
+
accessRead: "Read only",
|
|
22
|
+
accessReadHint: "Look at data. Cannot change anything.",
|
|
23
|
+
accessWrite: "Read and change",
|
|
24
|
+
accessWriteHint: "Everything this area offers, including changes.",
|
|
25
|
+
customise: "Customise permissions",
|
|
26
|
+
accessCustom: "Custom ({count} permissions)",
|
|
27
|
+
accessReadOnlyArea: "This area is read only: a key here can look but never change anything.",
|
|
28
|
+
customiseHint: "Pick exactly what this key may do.",
|
|
29
|
+
expiry: "Expires after",
|
|
30
|
+
expiryDays: "{days} days",
|
|
31
|
+
expiryCustom: "Pick a date",
|
|
32
|
+
expiryDate: "Expiry date",
|
|
33
|
+
expiryDateHint: "Up to {max} days from today.",
|
|
34
|
+
expiryDateInvalid: "Choose a date between tomorrow and {max} days from today.",
|
|
35
|
+
scopesRequired: "Choose at least one permission.",
|
|
36
|
+
submit: "Create key",
|
|
37
|
+
submitting: "Creating",
|
|
38
|
+
cancel: "Cancel",
|
|
39
|
+
createFailed: "The key could not be created. Try again.",
|
|
40
|
+
};
|
|
41
|
+
export function CreateApiKeyDialog(props) {
|
|
42
|
+
// Remount the form on every open so state never leaks between creations.
|
|
43
|
+
return (_jsx(Dialog, { open: props.open, onClose: props.onClose, size: "lg", children: props.open ? _jsx(Form, { ...props }) : null }));
|
|
44
|
+
}
|
|
45
|
+
function Form({ onClose, onSubmit, surfaces, labels, now }) {
|
|
46
|
+
const l = { ...DEFAULTS, ...labels };
|
|
47
|
+
const offered = (surfaces ?? API_KEY_SURFACES).filter((s) => API_KEY_SURFACES.includes(s));
|
|
48
|
+
// Safest default first: Read-only when this org may use it.
|
|
49
|
+
const first = offered.includes("readonly") ? "readonly" : (offered[0] ?? "readonly");
|
|
50
|
+
const [mountedAt] = React.useState(() => Date.now());
|
|
51
|
+
const clock = now ?? mountedAt;
|
|
52
|
+
const bounds = expiryBounds(clock, API_KEY_LIMITS.maxExpiryDays);
|
|
53
|
+
const ids = React.useId();
|
|
54
|
+
const accessId = `${ids}-access`;
|
|
55
|
+
const scopesId = `${ids}-scopes`;
|
|
56
|
+
const [name, setName] = React.useState("");
|
|
57
|
+
const [surface, setSurface] = React.useState(first);
|
|
58
|
+
const [scopes, setScopes] = React.useState(() => readScopes(first));
|
|
59
|
+
const [manualOpen, setManualOpen] = React.useState(false);
|
|
60
|
+
const [days, setDays] = React.useState(String(API_KEY_LIMITS.defaultExpiryDays));
|
|
61
|
+
const [date, setDate] = React.useState("");
|
|
62
|
+
const [submitted, setSubmitted] = React.useState(false);
|
|
63
|
+
const [pending, setPending] = React.useState(false);
|
|
64
|
+
const [failure, setFailure] = React.useState(null);
|
|
65
|
+
const info = SURFACE_CATALOG[surface];
|
|
66
|
+
const changesAllowed = surfaceAllowsChanges(surface);
|
|
67
|
+
const kind = summarizeScopes(surface, scopes);
|
|
68
|
+
const custom = days === "custom";
|
|
69
|
+
// A custom selection (or an empty one) always shows the list it is made of.
|
|
70
|
+
const showCustom = manualOpen || kind === "custom";
|
|
71
|
+
const trimmed = name.trim();
|
|
72
|
+
const nameError = trimmed.length === 0 ? l.nameRequired : null;
|
|
73
|
+
const scopesError = scopes.length === 0 ? l.scopesRequired : null;
|
|
74
|
+
const dateError = custom && (date === "" || date < bounds.min || date > bounds.max)
|
|
75
|
+
? fmt(l.expiryDateInvalid, { max: API_KEY_LIMITS.maxExpiryDays })
|
|
76
|
+
: null;
|
|
77
|
+
const invalid = nameError !== null || scopesError !== null || dateError !== null;
|
|
78
|
+
const pickSurface = (next) => {
|
|
79
|
+
setSurface(next);
|
|
80
|
+
setScopes(readScopes(next));
|
|
81
|
+
};
|
|
82
|
+
const toggle = (id, on) => setScopes((current) => (on ? [...new Set([...current, id])] : current.filter((x) => x !== id)));
|
|
83
|
+
const submit = async (event) => {
|
|
84
|
+
event.preventDefault();
|
|
85
|
+
setSubmitted(true);
|
|
86
|
+
if (invalid || pending)
|
|
87
|
+
return;
|
|
88
|
+
setPending(true);
|
|
89
|
+
setFailure(null);
|
|
90
|
+
try {
|
|
91
|
+
await onSubmit({
|
|
92
|
+
name: trimmed,
|
|
93
|
+
surface,
|
|
94
|
+
scopes,
|
|
95
|
+
...(custom
|
|
96
|
+
? { expiresAt: endOfLocalDayIso(date, clock, API_KEY_LIMITS.maxExpiryDays) }
|
|
97
|
+
: { expiresInDays: Number(days) }),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
setFailure(error instanceof Error && error.message ? error.message : l.createFailed);
|
|
102
|
+
setPending(false);
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
const surfaceLabel = (id) => labels?.surfaces?.[id]?.label ?? SURFACE_CATALOG[id].label;
|
|
106
|
+
const surfaceHint = labels?.surfaces?.[surface]?.description ?? info.description;
|
|
107
|
+
return (_jsxs("form", { onSubmit: (e) => void submit(e), noValidate: true, children: [_jsx(DialogTitle, { children: l.title }), _jsx(DialogDescription, { children: l.description }), _jsxs(DialogBody, { children: [_jsxs("div", { className: "flex flex-col gap-6", children: [_jsxs(Field, { children: [_jsx(Label, { children: l.name }), _jsx(Input, { name: "name", autoFocus: true, value: name, maxLength: API_KEY_LIMITS.maxNameLength, placeholder: l.namePlaceholder, autoComplete: "off", invalid: submitted && nameError !== null, onChange: (e) => setName(e.target.value) }), submitted && nameError ? _jsx(ErrorMessage, { children: nameError }) : null] }), _jsxs(Field, { children: [_jsx(Label, { children: l.surface }), _jsx(Select, { name: "surface", "aria-label": l.surface, value: surface, onChange: (e) => pickSurface(e.target.value), children: offered.map((id) => (_jsx("option", { value: id, children: surfaceLabel(id) }, id))) }), _jsx(Description, { children: surfaceHint })] }), _jsxs("div", { className: "flex flex-col gap-3", children: [_jsx("p", { className: "text-sm/6 font-medium text-foreground", id: accessId, children: l.access }), changesAllowed ? (_jsxs(RadioGroup, { "aria-labelledby": accessId, value: kind === "custom" ? "custom" : kind, onChange: (value) => {
|
|
108
|
+
if (value === "read")
|
|
109
|
+
setScopes(readScopes(surface));
|
|
110
|
+
if (value === "write")
|
|
111
|
+
setScopes(allScopes(surface));
|
|
112
|
+
}, children: [_jsxs(RadioField, { children: [_jsx(Radio, { value: "read" }), _jsx(Label, { children: l.accessRead }), _jsx(Description, { children: l.accessReadHint })] }), _jsxs(RadioField, { children: [_jsx(Radio, { value: "write" }), _jsx(Label, { children: l.accessWrite }), _jsx(Description, { children: l.accessWriteHint })] }), kind === "custom" ? (_jsxs(RadioField, { children: [_jsx(Radio, { value: "custom" }), _jsx(Label, { children: fmt(l.accessCustom, { count: scopes.length }) })] })) : null] })) : (_jsx("p", { className: "text-sm/6 text-muted-foreground", children: l.accessReadOnlyArea })), _jsxs("div", { children: [kind === "custom" ? (_jsx("p", { className: "text-sm/6 font-medium text-foreground", children: l.customise })) : (_jsxs("button", { type: "button", "aria-expanded": showCustom, "aria-controls": scopesId, onClick: () => setManualOpen((v) => !v), className: "inline-flex min-h-11 items-center gap-1.5 rounded-sm text-sm/6 font-medium text-foreground focus-visible:outline-2 focus-visible:outline-ring sm:min-h-8", children: [_jsx(ChevronDownIcon, { "aria-hidden": "true", className: `size-4 transition-transform motion-reduce:transition-none ${showCustom ? "rotate-180" : ""}` }), l.customise] })), _jsxs("div", { id: scopesId, hidden: !showCustom, className: "mt-2", children: [_jsx("p", { className: "mb-2 text-sm/6 text-muted-foreground", children: l.customiseHint }), _jsx(CheckboxGroup, { children: info.scopes.map((scope) => (_jsxs(CheckboxField, { children: [_jsx(Checkbox, { name: "scopes", value: scope.id, checked: scopes.includes(scope.id), onChange: (on) => toggle(scope.id, on) }), _jsx(Label, { children: scope.label })] }, scope.id))) })] }), scopesError ? (_jsx("p", { role: "alert", className: "mt-2 text-sm/6 text-(--tone-danger-fg)", children: scopesError })) : null] })] }), _jsxs(Field, { children: [_jsx(Label, { children: l.expiry }), _jsxs(Select, { name: "expiry", "aria-label": l.expiry, value: days, onChange: (e) => setDays(e.target.value), children: [API_KEY_LIMITS.expiryPresetDays.map((d) => (_jsx("option", { value: String(d), children: fmt(l.expiryDays, { days: d }) }, d))), _jsx("option", { value: "custom", children: l.expiryCustom })] })] }), custom ? (_jsxs(Field, { children: [_jsx(Label, { children: l.expiryDate }), _jsx(Input, { type: "date", name: "expiresAt", value: date, min: bounds.min, max: bounds.max, invalid: submitted && dateError !== null, onChange: (e) => setDate(e.target.value) }), _jsx(Description, { children: fmt(l.expiryDateHint, { max: API_KEY_LIMITS.maxExpiryDays }) }), submitted && dateError ? _jsx(ErrorMessage, { children: dateError }) : null] })) : null] }), failure ? (_jsx("p", { role: "alert", className: "mt-6 rounded-lg bg-(--tone-danger-soft) px-3 py-2 text-sm/6 text-(--tone-danger-fg)", children: failure })) : null] }), _jsxs(DialogActions, { children: [_jsx(Button, { plain: true, className: "min-h-11", onClick: onClose, disabled: pending, children: l.cancel }), _jsx(Button, { color: "brand", className: "min-h-11", type: "submit", disabled: pending, children: pending ? l.submitting : l.submit })] })] }));
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=create-api-key-dialog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-api-key-dialog.js","sourceRoot":"","sources":["../../../src/profile/api-keys/create-api-key-dialog.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Tiny presentation helpers shared by the key and grant cards. */
|
|
2
|
+
/** Replace `{name}` placeholders. Labels stay plain strings so a consumer's i18n can supply them. */
|
|
3
|
+
export declare function fmt(template: string, vars: Record<string, string | number>): string;
|
|
4
|
+
export declare function formatDate(value: string, locale?: string): string;
|
|
5
|
+
/** "3 days ago" / "in 12 days". `now` is injectable so stories and tests are deterministic. */
|
|
6
|
+
export declare function formatRelative(value: string, now: number, locale?: string): string;
|
|
7
|
+
/** The masked key shown in lists: prefix, ellipsis, last four. The full key is never available here. */
|
|
8
|
+
export declare function maskedKey(prefix: string, hint: string): string;
|
|
9
|
+
/** Inclusive date bounds (YYYY-MM-DD, local) for a custom expiry: tomorrow .. `maxDays` ahead. */
|
|
10
|
+
export declare function expiryBounds(now: number, maxDays: number): {
|
|
11
|
+
min: string;
|
|
12
|
+
max: string;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* The chosen local calendar day as a full UTC ISO date-time: 23:59:59.999 LOCAL time on that day,
|
|
16
|
+
* never later than `now + maxDays` (the backend rejects anything past creation + 365 days, and the
|
|
17
|
+
* end of the 365th day can fall hours beyond it).
|
|
18
|
+
*/
|
|
19
|
+
export declare function endOfLocalDayIso(date: string, now: number, maxDays: number): string;
|
|
20
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/profile/api-keys/format.ts"],"names":[],"mappings":"AAAA,mEAAmE;AAEnE,qGAAqG;AACrG,wBAAgB,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAEnF;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAIjE;AAUD,+FAA+F;AAC/F,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CASlF;AAED,wGAAwG;AACxG,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9D;AAWD,kGAAkG;AAClG,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAEvF;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAKnF"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/** Tiny presentation helpers shared by the key and grant cards. */
|
|
2
|
+
/** Replace `{name}` placeholders. Labels stay plain strings so a consumer's i18n can supply them. */
|
|
3
|
+
export function fmt(template, vars) {
|
|
4
|
+
return template.replace(/\{(\w+)\}/g, (_, key) => String(vars[key] ?? `{${key}}`));
|
|
5
|
+
}
|
|
6
|
+
export function formatDate(value, locale) {
|
|
7
|
+
const date = new Date(value);
|
|
8
|
+
if (Number.isNaN(date.valueOf()))
|
|
9
|
+
return value;
|
|
10
|
+
return new Intl.DateTimeFormat(locale, { dateStyle: "medium" }).format(date);
|
|
11
|
+
}
|
|
12
|
+
const UNITS = [
|
|
13
|
+
["year", 365 * 86_400],
|
|
14
|
+
["month", 30 * 86_400],
|
|
15
|
+
["day", 86_400],
|
|
16
|
+
["hour", 3_600],
|
|
17
|
+
["minute", 60],
|
|
18
|
+
];
|
|
19
|
+
/** "3 days ago" / "in 12 days". `now` is injectable so stories and tests are deterministic. */
|
|
20
|
+
export function formatRelative(value, now, locale) {
|
|
21
|
+
const then = new Date(value).valueOf();
|
|
22
|
+
if (Number.isNaN(then))
|
|
23
|
+
return value;
|
|
24
|
+
const seconds = Math.round((then - now) / 1000);
|
|
25
|
+
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
|
|
26
|
+
for (const [unit, size] of UNITS) {
|
|
27
|
+
if (Math.abs(seconds) >= size)
|
|
28
|
+
return rtf.format(Math.trunc(seconds / size), unit);
|
|
29
|
+
}
|
|
30
|
+
return rtf.format(0, "minute");
|
|
31
|
+
}
|
|
32
|
+
/** The masked key shown in lists: prefix, ellipsis, last four. The full key is never available here. */
|
|
33
|
+
export function maskedKey(prefix, hint) {
|
|
34
|
+
return `${prefix}…${hint}`;
|
|
35
|
+
}
|
|
36
|
+
const DAY = 86_400_000;
|
|
37
|
+
/** YYYY-MM-DD of a moment in the user's LOCAL timezone (what a date input shows and returns). */
|
|
38
|
+
function localDate(ms) {
|
|
39
|
+
const d = new Date(ms);
|
|
40
|
+
const p = (n) => String(n).padStart(2, "0");
|
|
41
|
+
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`;
|
|
42
|
+
}
|
|
43
|
+
/** Inclusive date bounds (YYYY-MM-DD, local) for a custom expiry: tomorrow .. `maxDays` ahead. */
|
|
44
|
+
export function expiryBounds(now, maxDays) {
|
|
45
|
+
return { min: localDate(now + DAY), max: localDate(now + maxDays * DAY) };
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The chosen local calendar day as a full UTC ISO date-time: 23:59:59.999 LOCAL time on that day,
|
|
49
|
+
* never later than `now + maxDays` (the backend rejects anything past creation + 365 days, and the
|
|
50
|
+
* end of the 365th day can fall hours beyond it).
|
|
51
|
+
*/
|
|
52
|
+
export function endOfLocalDayIso(date, now, maxDays) {
|
|
53
|
+
const [y, m, d] = date.split("-").map(Number);
|
|
54
|
+
const endOfDay = new Date(y, m - 1, d, 23, 59, 59, 999).getTime();
|
|
55
|
+
const cap = now + maxDays * DAY - 60_000;
|
|
56
|
+
return new Date(Math.min(endOfDay, cap)).toISOString();
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../../src/profile/api-keys/format.ts"],"names":[],"mappings":"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"}
|