@stigmer/react 0.0.83 → 0.0.85

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.
Files changed (109) hide show
  1. package/demo/fixtures.d.ts +4 -0
  2. package/demo/fixtures.d.ts.map +1 -1
  3. package/demo/fixtures.js +4 -0
  4. package/demo/fixtures.js.map +1 -1
  5. package/index.d.ts +5 -3
  6. package/index.d.ts.map +1 -1
  7. package/index.js +3 -1
  8. package/index.js.map +1 -1
  9. package/library/ResourceListView.d.ts +57 -7
  10. package/library/ResourceListView.d.ts.map +1 -1
  11. package/library/ResourceListView.js +147 -37
  12. package/library/ResourceListView.js.map +1 -1
  13. package/library/index.d.ts +1 -1
  14. package/library/index.d.ts.map +1 -1
  15. package/library/index.js.map +1 -1
  16. package/mcp-server/McpServerConfigPanel.d.ts +45 -0
  17. package/mcp-server/McpServerConfigPanel.d.ts.map +1 -1
  18. package/mcp-server/McpServerConfigPanel.js +90 -14
  19. package/mcp-server/McpServerConfigPanel.js.map +1 -1
  20. package/mcp-server/McpServerConnectDialog.d.ts +51 -0
  21. package/mcp-server/McpServerConnectDialog.d.ts.map +1 -0
  22. package/mcp-server/McpServerConnectDialog.js +164 -0
  23. package/mcp-server/McpServerConnectDialog.js.map +1 -0
  24. package/mcp-server/McpServerDetailView.d.ts.map +1 -1
  25. package/mcp-server/McpServerDetailView.js +168 -23
  26. package/mcp-server/McpServerDetailView.js.map +1 -1
  27. package/mcp-server/McpServerPicker.d.ts.map +1 -1
  28. package/mcp-server/McpServerPicker.js +9 -3
  29. package/mcp-server/McpServerPicker.js.map +1 -1
  30. package/mcp-server/OAuthAppForm.d.ts +58 -0
  31. package/mcp-server/OAuthAppForm.d.ts.map +1 -0
  32. package/mcp-server/OAuthAppForm.js +67 -0
  33. package/mcp-server/OAuthAppForm.js.map +1 -0
  34. package/mcp-server/index.d.ts +8 -0
  35. package/mcp-server/index.d.ts.map +1 -1
  36. package/mcp-server/index.js +4 -0
  37. package/mcp-server/index.js.map +1 -1
  38. package/mcp-server/useDisconnectOAuth.d.ts +40 -0
  39. package/mcp-server/useDisconnectOAuth.d.ts.map +1 -0
  40. package/mcp-server/useDisconnectOAuth.js +46 -0
  41. package/mcp-server/useDisconnectOAuth.js.map +1 -0
  42. package/mcp-server/useMcpServerCredentials.d.ts +48 -0
  43. package/mcp-server/useMcpServerCredentials.d.ts.map +1 -1
  44. package/mcp-server/useMcpServerCredentials.js +18 -2
  45. package/mcp-server/useMcpServerCredentials.js.map +1 -1
  46. package/mcp-server/useOAuthGrantStatus.d.ts +9 -0
  47. package/mcp-server/useOAuthGrantStatus.d.ts.map +1 -1
  48. package/mcp-server/useOAuthGrantStatus.js +6 -1
  49. package/mcp-server/useOAuthGrantStatus.js.map +1 -1
  50. package/mcp-server/useOrgOAuthApp.d.ts +82 -0
  51. package/mcp-server/useOrgOAuthApp.d.ts.map +1 -0
  52. package/mcp-server/useOrgOAuthApp.js +160 -0
  53. package/mcp-server/useOrgOAuthApp.js.map +1 -0
  54. package/oauth-app/CreateOAuthAppForm.d.ts +41 -0
  55. package/oauth-app/CreateOAuthAppForm.d.ts.map +1 -0
  56. package/oauth-app/CreateOAuthAppForm.js +140 -0
  57. package/oauth-app/CreateOAuthAppForm.js.map +1 -0
  58. package/oauth-app/OAuthAppDetailPanel.d.ts +43 -0
  59. package/oauth-app/OAuthAppDetailPanel.d.ts.map +1 -0
  60. package/oauth-app/OAuthAppDetailPanel.js +202 -0
  61. package/oauth-app/OAuthAppDetailPanel.js.map +1 -0
  62. package/oauth-app/OAuthAppListPanel.d.ts +43 -0
  63. package/oauth-app/OAuthAppListPanel.d.ts.map +1 -0
  64. package/oauth-app/OAuthAppListPanel.js +79 -0
  65. package/oauth-app/OAuthAppListPanel.js.map +1 -0
  66. package/oauth-app/index.d.ts +15 -0
  67. package/oauth-app/index.d.ts.map +1 -0
  68. package/oauth-app/index.js +8 -0
  69. package/oauth-app/index.js.map +1 -0
  70. package/oauth-app/useCreateOAuthApp.d.ts +39 -0
  71. package/oauth-app/useCreateOAuthApp.d.ts.map +1 -0
  72. package/oauth-app/useCreateOAuthApp.js +50 -0
  73. package/oauth-app/useCreateOAuthApp.js.map +1 -0
  74. package/oauth-app/useDeleteOAuthApp.d.ts +31 -0
  75. package/oauth-app/useDeleteOAuthApp.d.ts.map +1 -0
  76. package/oauth-app/useDeleteOAuthApp.js +43 -0
  77. package/oauth-app/useDeleteOAuthApp.js.map +1 -0
  78. package/oauth-app/useOAuthAppList.d.ts +32 -0
  79. package/oauth-app/useOAuthAppList.d.ts.map +1 -0
  80. package/oauth-app/useOAuthAppList.js +61 -0
  81. package/oauth-app/useOAuthAppList.js.map +1 -0
  82. package/oauth-app/useUpdateOAuthApp.d.ts +38 -0
  83. package/oauth-app/useUpdateOAuthApp.d.ts.map +1 -0
  84. package/oauth-app/useUpdateOAuthApp.js +49 -0
  85. package/oauth-app/useUpdateOAuthApp.js.map +1 -0
  86. package/package.json +4 -4
  87. package/src/demo/fixtures.ts +8 -0
  88. package/src/index.ts +25 -0
  89. package/src/library/ResourceListView.tsx +303 -46
  90. package/src/library/index.ts +4 -1
  91. package/src/mcp-server/McpServerConfigPanel.tsx +370 -45
  92. package/src/mcp-server/McpServerConnectDialog.tsx +527 -0
  93. package/src/mcp-server/McpServerDetailView.tsx +448 -47
  94. package/src/mcp-server/McpServerPicker.tsx +10 -3
  95. package/src/mcp-server/OAuthAppForm.tsx +304 -0
  96. package/src/mcp-server/index.ts +12 -0
  97. package/src/mcp-server/useDisconnectOAuth.ts +76 -0
  98. package/src/mcp-server/useMcpServerCredentials.ts +70 -2
  99. package/src/mcp-server/useOAuthGrantStatus.ts +19 -1
  100. package/src/mcp-server/useOrgOAuthApp.ts +250 -0
  101. package/src/oauth-app/CreateOAuthAppForm.tsx +449 -0
  102. package/src/oauth-app/OAuthAppDetailPanel.tsx +671 -0
  103. package/src/oauth-app/OAuthAppListPanel.tsx +237 -0
  104. package/src/oauth-app/index.ts +14 -0
  105. package/src/oauth-app/useCreateOAuthApp.ts +70 -0
  106. package/src/oauth-app/useDeleteOAuthApp.ts +62 -0
  107. package/src/oauth-app/useOAuthAppList.ts +84 -0
  108. package/src/oauth-app/useUpdateOAuthApp.ts +69 -0
  109. package/styles.css +1 -1
@@ -0,0 +1,160 @@
1
+ "use client";
2
+ import { useCallback, useEffect, useState } from "react";
3
+ import { create } from "@bufbuild/protobuf";
4
+ import { GetOrgOAuthAppInputSchema, SetOrgOAuthAppInputSchema, DeleteOrgOAuthAppInputSchema, } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/io_pb";
5
+ import { useStigmer } from "../hooks";
6
+ import { toError } from "../internal/toError";
7
+ const IDLE = {
8
+ hasOverride: false,
9
+ oauthAppId: null,
10
+ clientId: null,
11
+ isLoading: false,
12
+ error: null,
13
+ refetch: () => { },
14
+ setOrgOAuthApp: () => Promise.resolve(""),
15
+ isSetting: false,
16
+ setError: null,
17
+ deleteOrgOAuthApp: () => Promise.resolve(false),
18
+ isDeleting: false,
19
+ deleteError: null,
20
+ clearErrors: () => { },
21
+ };
22
+ /**
23
+ * Hybrid data + behavior hook for managing org-level BYOA OAuth app overrides.
24
+ *
25
+ * **Data side**: Auto-fetches `getOrgOAuthApp` when both parameters are
26
+ * non-null. Returns override existence, OAuthApp ID, and client ID for
27
+ * display. Follows the same fetch-on-mount pattern as
28
+ * {@link useOAuthGrantStatus}.
29
+ *
30
+ * **Behavior side**: Exposes `setOrgOAuthApp` and `deleteOrgOAuthApp`
31
+ * mutations bound to the hook's resource + org context, eliminating
32
+ * parameter repetition at call sites.
33
+ *
34
+ * Pass `null` for either parameter to skip fetching (stable no-op).
35
+ *
36
+ * @example
37
+ * ```tsx
38
+ * const orgApp = useOrgOAuthApp(mcpServer?.metadata?.id ?? null, org);
39
+ *
40
+ * if (orgApp.hasOverride) {
41
+ * return <span>Using your OAuth app (client: {orgApp.clientId})</span>;
42
+ * }
43
+ *
44
+ * const handleSubmit = async (clientId: string, clientSecret: string) => {
45
+ * await orgApp.setOrgOAuthApp(clientId, clientSecret);
46
+ * orgApp.refetch();
47
+ * credentials.refetch();
48
+ * };
49
+ * ```
50
+ */
51
+ export function useOrgOAuthApp(resourceId, org) {
52
+ const stigmer = useStigmer();
53
+ const [hasOverride, setHasOverride] = useState(false);
54
+ const [oauthAppId, setOauthAppId] = useState(null);
55
+ const [clientId, setClientId] = useState(null);
56
+ const [isLoading, setIsLoading] = useState(false);
57
+ const [error, setError] = useState(null);
58
+ const [fetchKey, setFetchKey] = useState(0);
59
+ const [isSetting, setIsSetting] = useState(false);
60
+ const [setError_, setSetError] = useState(null);
61
+ const [isDeleting, setIsDeleting] = useState(false);
62
+ const [deleteError, setDeleteError] = useState(null);
63
+ const refetch = useCallback(() => setFetchKey((k) => k + 1), []);
64
+ const clearErrors = useCallback(() => {
65
+ setSetError(null);
66
+ setDeleteError(null);
67
+ }, []);
68
+ useEffect(() => {
69
+ if (!resourceId || !org) {
70
+ setHasOverride(false);
71
+ setOauthAppId(null);
72
+ setClientId(null);
73
+ setIsLoading(false);
74
+ setError(null);
75
+ return;
76
+ }
77
+ const cancelled = { current: false };
78
+ setIsLoading(true);
79
+ setError(null);
80
+ stigmer.mcpServer
81
+ .getOrgOAuthApp(create(GetOrgOAuthAppInputSchema, { resourceId, org }))
82
+ .then((result) => {
83
+ if (cancelled.current)
84
+ return;
85
+ setHasOverride(result.hasOverride);
86
+ setOauthAppId(result.oauthAppId || null);
87
+ setClientId(result.clientId || null);
88
+ setIsLoading(false);
89
+ }, (err) => {
90
+ if (cancelled.current)
91
+ return;
92
+ setError(toError(err));
93
+ setIsLoading(false);
94
+ });
95
+ return () => {
96
+ cancelled.current = true;
97
+ };
98
+ }, [resourceId, org, stigmer, fetchKey]);
99
+ const setOrgOAuthApp = useCallback(async (newClientId, clientSecret) => {
100
+ if (!resourceId || !org) {
101
+ throw new Error("useOrgOAuthApp: resourceId and org are required for setOrgOAuthApp");
102
+ }
103
+ setIsSetting(true);
104
+ setSetError(null);
105
+ try {
106
+ const result = await stigmer.mcpServer.setOrgOAuthApp(create(SetOrgOAuthAppInputSchema, {
107
+ resourceId,
108
+ org,
109
+ clientId: newClientId,
110
+ clientSecret,
111
+ }));
112
+ return result.oauthAppId;
113
+ }
114
+ catch (err) {
115
+ const wrapped = toError(err);
116
+ setSetError(wrapped);
117
+ throw wrapped;
118
+ }
119
+ finally {
120
+ setIsSetting(false);
121
+ }
122
+ }, [stigmer, resourceId, org]);
123
+ const deleteOrgOAuthApp = useCallback(async () => {
124
+ if (!resourceId || !org) {
125
+ throw new Error("useOrgOAuthApp: resourceId and org are required for deleteOrgOAuthApp");
126
+ }
127
+ setIsDeleting(true);
128
+ setDeleteError(null);
129
+ try {
130
+ const result = await stigmer.mcpServer.deleteOrgOAuthApp(create(DeleteOrgOAuthAppInputSchema, { resourceId, org }));
131
+ return result.deleted;
132
+ }
133
+ catch (err) {
134
+ const wrapped = toError(err);
135
+ setDeleteError(wrapped);
136
+ throw wrapped;
137
+ }
138
+ finally {
139
+ setIsDeleting(false);
140
+ }
141
+ }, [stigmer, resourceId, org]);
142
+ if (!resourceId || !org)
143
+ return { ...IDLE, refetch, clearErrors };
144
+ return {
145
+ hasOverride,
146
+ oauthAppId,
147
+ clientId,
148
+ isLoading,
149
+ error,
150
+ refetch,
151
+ setOrgOAuthApp,
152
+ isSetting,
153
+ setError: setError_,
154
+ deleteOrgOAuthApp,
155
+ isDeleting,
156
+ deleteError,
157
+ clearErrors,
158
+ };
159
+ }
160
+ //# sourceMappingURL=useOrgOAuthApp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useOrgOAuthApp.js","sourceRoot":"","sources":["../../src/mcp-server/useOrgOAuthApp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { OAuthApp } from "@stigmer/protos/ai/stigmer/iam/oauthapp/v1/api_pb";
2
+ /** Props for {@link CreateOAuthAppForm}. */
3
+ export interface CreateOAuthAppFormProps {
4
+ /** Organization slug — the OAuth app will be created in this org. */
5
+ readonly org: string;
6
+ /** Fired with the newly created OAuth app on success. */
7
+ readonly onCreated?: (app: OAuthApp) => void;
8
+ /** Fired when the user cancels creation. */
9
+ readonly onCancel?: () => void;
10
+ /** Additional CSS class names for the root container. */
11
+ readonly className?: string;
12
+ }
13
+ /**
14
+ * Form for creating a new OAuth app within an organization.
15
+ *
16
+ * Collects the required OAuth configuration: **name**, **provider**,
17
+ * **client ID**, **client secret**, **authorization URL**, and
18
+ * **token URL**. An expandable "Advanced" section provides optional
19
+ * fields for scopes, userinfo URL, scope parameter name, and vendor
20
+ * approval settings.
21
+ *
22
+ * This is a pure presentational component with no dialog wrapper
23
+ * (headless-first). The parent is responsible for rendering it inside
24
+ * a card, dialog, or inline context as needed.
25
+ *
26
+ * All visual properties flow through `--stgm-*` design tokens.
27
+ *
28
+ * @example
29
+ * ```tsx
30
+ * <CreateOAuthAppForm
31
+ * org="acme"
32
+ * onCreated={(app) => {
33
+ * refetch();
34
+ * setShowForm(false);
35
+ * }}
36
+ * onCancel={() => setShowForm(false)}
37
+ * />
38
+ * ```
39
+ */
40
+ export declare function CreateOAuthAppForm({ org, onCreated, onCancel, className, }: CreateOAuthAppFormProps): import("react/jsx-runtime").JSX.Element;
41
+ //# sourceMappingURL=CreateOAuthAppForm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CreateOAuthAppForm.d.ts","sourceRoot":"","sources":["../../src/oauth-app/CreateOAuthAppForm.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mDAAmD,CAAC;AAQlF,4CAA4C;AAC5C,MAAM,WAAW,uBAAuB;IACtC,qEAAqE;IACrE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAC;IAC7C,4CAA4C;IAC5C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IAC/B,yDAAyD;IACzD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,GAAG,EACH,SAAS,EACT,QAAQ,EACR,SAAS,GACV,EAAE,uBAAuB,2CA6RzB"}
@@ -0,0 +1,140 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useCallback, useState } from "react";
4
+ import { cn } from "@stigmer/theme";
5
+ import { getUserMessage } from "@stigmer/sdk";
6
+ import { VendorApprovalStatus } from "@stigmer/protos/ai/stigmer/iam/oauthapp/v1/spec_pb";
7
+ import { useCreateOAuthApp } from "./useCreateOAuthApp";
8
+ /**
9
+ * Form for creating a new OAuth app within an organization.
10
+ *
11
+ * Collects the required OAuth configuration: **name**, **provider**,
12
+ * **client ID**, **client secret**, **authorization URL**, and
13
+ * **token URL**. An expandable "Advanced" section provides optional
14
+ * fields for scopes, userinfo URL, scope parameter name, and vendor
15
+ * approval settings.
16
+ *
17
+ * This is a pure presentational component with no dialog wrapper
18
+ * (headless-first). The parent is responsible for rendering it inside
19
+ * a card, dialog, or inline context as needed.
20
+ *
21
+ * All visual properties flow through `--stgm-*` design tokens.
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * <CreateOAuthAppForm
26
+ * org="acme"
27
+ * onCreated={(app) => {
28
+ * refetch();
29
+ * setShowForm(false);
30
+ * }}
31
+ * onCancel={() => setShowForm(false)}
32
+ * />
33
+ * ```
34
+ */
35
+ export function CreateOAuthAppForm({ org, onCreated, onCancel, className, }) {
36
+ const { create, isCreating, error, clearError } = useCreateOAuthApp();
37
+ const [name, setName] = useState("");
38
+ const [provider, setProvider] = useState("");
39
+ const [clientId, setClientId] = useState("");
40
+ const [clientSecret, setClientSecret] = useState("");
41
+ const [authorizationUrl, setAuthorizationUrl] = useState("");
42
+ const [tokenUrl, setTokenUrl] = useState("");
43
+ const [showAdvanced, setShowAdvanced] = useState(false);
44
+ const [scopes, setScopes] = useState("");
45
+ const [userinfoUrl, setUserinfoUrl] = useState("");
46
+ const [scopeParameterName, setScopeParameterName] = useState("");
47
+ const [vendorApprovalStatus, setVendorApprovalStatus] = useState("unspecified");
48
+ const [vendorApprovalDocsUrl, setVendorApprovalDocsUrl] = useState("");
49
+ const trimmedName = name.trim();
50
+ const trimmedProvider = provider.trim();
51
+ const trimmedClientId = clientId.trim();
52
+ const trimmedClientSecret = clientSecret.trim();
53
+ const trimmedAuthUrl = authorizationUrl.trim();
54
+ const trimmedTokenUrl = tokenUrl.trim();
55
+ const canSubmit = trimmedName !== "" &&
56
+ trimmedProvider !== "" &&
57
+ trimmedClientId !== "" &&
58
+ trimmedClientSecret !== "" &&
59
+ trimmedAuthUrl !== "" &&
60
+ trimmedTokenUrl !== "" &&
61
+ !isCreating;
62
+ const handleSubmit = useCallback(async (e) => {
63
+ e.preventDefault();
64
+ if (!canSubmit)
65
+ return;
66
+ clearError();
67
+ try {
68
+ const parsedScopes = scopes
69
+ .split(",")
70
+ .map((s) => s.trim())
71
+ .filter(Boolean);
72
+ const app = await create({
73
+ name: trimmedName,
74
+ org,
75
+ provider: trimmedProvider,
76
+ clientId: trimmedClientId,
77
+ clientSecret: trimmedClientSecret,
78
+ authorizationUrl: trimmedAuthUrl,
79
+ tokenUrl: trimmedTokenUrl,
80
+ ...(parsedScopes.length > 0 && { scopes: parsedScopes }),
81
+ ...(userinfoUrl.trim() && { userinfoUrl: userinfoUrl.trim() }),
82
+ ...(scopeParameterName.trim() && {
83
+ scopeParameterName: scopeParameterName.trim(),
84
+ }),
85
+ ...(vendorApprovalStatus !== "unspecified" && {
86
+ vendorApprovalStatus: APPROVAL_STATUS_MAP[vendorApprovalStatus],
87
+ }),
88
+ ...(vendorApprovalDocsUrl.trim() && {
89
+ vendorApprovalDocsUrl: vendorApprovalDocsUrl.trim(),
90
+ }),
91
+ });
92
+ onCreated?.(app);
93
+ }
94
+ catch {
95
+ // error state is managed by useCreateOAuthApp
96
+ }
97
+ }, [
98
+ canSubmit,
99
+ trimmedName,
100
+ org,
101
+ trimmedProvider,
102
+ trimmedClientId,
103
+ trimmedClientSecret,
104
+ trimmedAuthUrl,
105
+ trimmedTokenUrl,
106
+ scopes,
107
+ userinfoUrl,
108
+ scopeParameterName,
109
+ vendorApprovalStatus,
110
+ vendorApprovalDocsUrl,
111
+ create,
112
+ clearError,
113
+ onCreated,
114
+ ]);
115
+ return (_jsxs("form", { onSubmit: handleSubmit, className: cn("space-y-3", className), children: [_jsxs("div", { className: "space-y-3", children: [_jsx(FormField, { id: "stgm-oauth-name", label: "Name", value: name, onChange: setName, placeholder: "e.g. My Slack App", disabled: isCreating, required: true }), _jsx(FormField, { id: "stgm-oauth-provider", label: "Provider", value: provider, onChange: setProvider, placeholder: "e.g. Slack, GitHub, Salesforce", hint: "Human-readable vendor name for display", disabled: isCreating, required: true }), _jsx(FormField, { id: "stgm-oauth-client-id", label: "Client ID", value: clientId, onChange: setClientId, placeholder: "OAuth client identifier", disabled: isCreating, required: true }), _jsx(FormField, { id: "stgm-oauth-client-secret", label: "Client secret", value: clientSecret, onChange: setClientSecret, placeholder: "OAuth client secret", type: "password", disabled: isCreating, required: true }), _jsx(FormField, { id: "stgm-oauth-auth-url", label: "Authorization URL", value: authorizationUrl, onChange: setAuthorizationUrl, placeholder: "https://vendor.com/oauth/authorize", hint: "Vendor's OAuth authorization endpoint", disabled: isCreating, required: true }), _jsx(FormField, { id: "stgm-oauth-token-url", label: "Token URL", value: tokenUrl, onChange: setTokenUrl, placeholder: "https://vendor.com/oauth/token", hint: "Vendor's OAuth token exchange endpoint", disabled: isCreating, required: true }), _jsxs("div", { children: [_jsxs("button", { type: "button", onClick: () => setShowAdvanced((v) => !v), className: "text-muted-foreground hover:text-foreground flex items-center gap-1 text-[0.65rem] font-medium transition-colors", children: [_jsx(ChevronIcon, { expanded: showAdvanced }), "Advanced settings"] }), showAdvanced && (_jsxs("div", { className: "mt-2 space-y-3 border-l-2 border-border/60 pl-3", children: [_jsx(FormField, { id: "stgm-oauth-scopes", label: "Scopes", value: scopes, onChange: setScopes, placeholder: "read, write, admin", hint: "Comma-separated OAuth scopes to request", disabled: isCreating }), _jsx(FormField, { id: "stgm-oauth-userinfo-url", label: "Userinfo URL", value: userinfoUrl, onChange: setUserinfoUrl, placeholder: "https://vendor.com/userinfo", hint: "OIDC endpoint for fetching user profile data (optional)", disabled: isCreating }), _jsx(FormField, { id: "stgm-oauth-scope-param", label: "Scope parameter name", value: scopeParameterName, onChange: setScopeParameterName, placeholder: "scope", hint: 'Defaults to "scope". Some vendors use a non-standard name (e.g. "user_scope" for Slack).', disabled: isCreating }), _jsxs("div", { className: "space-y-1", children: [_jsx("label", { htmlFor: "stgm-oauth-approval-status", className: "text-xs font-medium text-foreground", children: "Vendor approval status" }), _jsxs("select", { id: "stgm-oauth-approval-status", value: vendorApprovalStatus, onChange: (e) => setVendorApprovalStatus(e.target.value), disabled: isCreating, className: cn("w-full rounded-md border border-input bg-background px-2.5 py-1.5 text-xs text-foreground", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", "disabled:pointer-events-none disabled:opacity-50"), children: [_jsx("option", { value: "unspecified", children: "Unspecified (treated as approved)" }), _jsx("option", { value: "pending", children: "Pending" }), _jsx("option", { value: "approved", children: "Approved" }), _jsx("option", { value: "rejected", children: "Rejected" })] }), _jsx("p", { className: "text-[0.65rem] text-muted-foreground", children: "Vendor marketplace approval lifecycle status" })] }), _jsx(FormField, { id: "stgm-oauth-approval-docs", label: "Vendor approval docs URL", value: vendorApprovalDocsUrl, onChange: setVendorApprovalDocsUrl, placeholder: "https://docs.example.com/byoa", hint: "Help link shown when vendor approval is pending", disabled: isCreating })] }))] })] }), error && (_jsx("p", { className: "text-destructive text-[0.65rem]", role: "alert", children: getUserMessage(error) })), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("button", { type: "submit", disabled: !canSubmit, className: cn("inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium", "bg-primary text-primary-foreground hover:bg-primary/90", "disabled:pointer-events-none disabled:opacity-40"), children: [isCreating && _jsx(SpinnerIcon, {}), "Create OAuth app"] }), onCancel && (_jsx("button", { type: "button", onClick: onCancel, disabled: isCreating, className: cn("rounded-md px-3 py-1.5 text-xs", "text-muted-foreground hover:text-foreground hover:bg-accent/50", "disabled:pointer-events-none disabled:opacity-50"), children: "Cancel" }))] })] }));
116
+ }
117
+ // ---------------------------------------------------------------------------
118
+ // Constants
119
+ // ---------------------------------------------------------------------------
120
+ const APPROVAL_STATUS_MAP = {
121
+ pending: VendorApprovalStatus.PENDING,
122
+ approved: VendorApprovalStatus.APPROVED,
123
+ rejected: VendorApprovalStatus.REJECTED,
124
+ };
125
+ // ---------------------------------------------------------------------------
126
+ // FormField (internal)
127
+ // ---------------------------------------------------------------------------
128
+ function FormField({ id, label, value, onChange, placeholder, hint, type = "text", disabled, required, }) {
129
+ return (_jsxs("div", { className: "space-y-1", children: [_jsx("label", { htmlFor: id, className: "text-xs font-medium text-foreground", children: label }), _jsx("input", { id: id, type: type, value: value, onChange: (e) => onChange(e.target.value), placeholder: placeholder, disabled: disabled, required: required, className: cn("w-full rounded-md border border-input bg-background px-2.5 py-1.5 text-xs text-foreground", "placeholder:text-muted-foreground", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", "disabled:pointer-events-none disabled:opacity-50") }), hint && (_jsx("p", { className: "text-[0.65rem] text-muted-foreground", children: hint }))] }));
130
+ }
131
+ // ---------------------------------------------------------------------------
132
+ // Icons
133
+ // ---------------------------------------------------------------------------
134
+ function ChevronIcon({ expanded }) {
135
+ return (_jsx("svg", { width: "10", height: "10", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", className: cn("shrink-0 transition-transform", expanded && "rotate-90"), children: _jsx("path", { d: "M6 4l4 4-4 4" }) }));
136
+ }
137
+ function SpinnerIcon() {
138
+ return (_jsx("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", className: "animate-spin", "aria-hidden": "true", children: _jsx("path", { d: "M8 2a6 6 0 1 0 6 6" }) }));
139
+ }
140
+ //# sourceMappingURL=CreateOAuthAppForm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CreateOAuthAppForm.js","sourceRoot":"","sources":["../../src/oauth-app/CreateOAuthAppForm.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import type { OAuthApp } from "@stigmer/protos/ai/stigmer/iam/oauthapp/v1/api_pb";
2
+ /** Props for {@link OAuthAppDetailPanel}. */
3
+ export interface OAuthAppDetailPanelProps {
4
+ /** The OAuth app resource to display and edit. */
5
+ readonly oauthApp: OAuthApp;
6
+ /** Fired with the updated resource after a successful save. */
7
+ readonly onUpdated?: (app: OAuthApp) => void;
8
+ /** Fired after the resource is successfully deleted. */
9
+ readonly onDeleted?: () => void;
10
+ /** Fired when the user clicks the back button. */
11
+ readonly onBack?: () => void;
12
+ /** Additional CSS class names for the root container. */
13
+ readonly className?: string;
14
+ }
15
+ /**
16
+ * View and edit panel for an existing OAuth app.
17
+ *
18
+ * In **view mode**, displays all OAuth configuration fields in a
19
+ * structured label/value layout with "Edit" and "Delete" buttons.
20
+ *
21
+ * In **edit mode**, fields become editable inputs. The client secret
22
+ * field shows a placeholder — leave it empty to keep the existing
23
+ * secret, or enter a new value to replace it. "Save" submits the
24
+ * update via {@link useUpdateOAuthApp}; "Cancel" discards changes
25
+ * and returns to view mode.
26
+ *
27
+ * Delete uses an inline confirmation pattern (no modal) to avoid
28
+ * portal/z-index issues for SDK embedders.
29
+ *
30
+ * All visual properties flow through `--stgm-*` design tokens.
31
+ *
32
+ * @example
33
+ * ```tsx
34
+ * <OAuthAppDetailPanel
35
+ * oauthApp={app}
36
+ * onUpdated={(updated) => refetch()}
37
+ * onDeleted={() => { refetch(); setFlow({ phase: "idle" }); }}
38
+ * onBack={() => setFlow({ phase: "idle" })}
39
+ * />
40
+ * ```
41
+ */
42
+ export declare function OAuthAppDetailPanel({ oauthApp, onUpdated, onDeleted, onBack, className, }: OAuthAppDetailPanelProps): import("react/jsx-runtime").JSX.Element;
43
+ //# sourceMappingURL=OAuthAppDetailPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OAuthAppDetailPanel.d.ts","sourceRoot":"","sources":["../../src/oauth-app/OAuthAppDetailPanel.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mDAAmD,CAAC;AAUlF,6CAA6C;AAC7C,MAAM,WAAW,wBAAwB;IACvC,kDAAkD;IAClD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,+DAA+D;IAC/D,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAC;IAC7C,wDAAwD;IACxD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,kDAAkD;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,yDAAyD;IACzD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,QAAQ,EACR,SAAS,EACT,SAAS,EACT,MAAM,EACN,SAAS,GACV,EAAE,wBAAwB,2CAiY1B"}
@@ -0,0 +1,202 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useCallback, useState } from "react";
4
+ import { cn } from "@stigmer/theme";
5
+ import { getUserMessage } from "@stigmer/sdk";
6
+ import { VendorApprovalStatus } from "@stigmer/protos/ai/stigmer/iam/oauthapp/v1/spec_pb";
7
+ import { timestampDate } from "@bufbuild/protobuf/wkt";
8
+ import { useUpdateOAuthApp } from "./useUpdateOAuthApp";
9
+ import { useDeleteOAuthApp } from "./useDeleteOAuthApp";
10
+ /**
11
+ * View and edit panel for an existing OAuth app.
12
+ *
13
+ * In **view mode**, displays all OAuth configuration fields in a
14
+ * structured label/value layout with "Edit" and "Delete" buttons.
15
+ *
16
+ * In **edit mode**, fields become editable inputs. The client secret
17
+ * field shows a placeholder — leave it empty to keep the existing
18
+ * secret, or enter a new value to replace it. "Save" submits the
19
+ * update via {@link useUpdateOAuthApp}; "Cancel" discards changes
20
+ * and returns to view mode.
21
+ *
22
+ * Delete uses an inline confirmation pattern (no modal) to avoid
23
+ * portal/z-index issues for SDK embedders.
24
+ *
25
+ * All visual properties flow through `--stgm-*` design tokens.
26
+ *
27
+ * @example
28
+ * ```tsx
29
+ * <OAuthAppDetailPanel
30
+ * oauthApp={app}
31
+ * onUpdated={(updated) => refetch()}
32
+ * onDeleted={() => { refetch(); setFlow({ phase: "idle" }); }}
33
+ * onBack={() => setFlow({ phase: "idle" })}
34
+ * />
35
+ * ```
36
+ */
37
+ export function OAuthAppDetailPanel({ oauthApp, onUpdated, onDeleted, onBack, className, }) {
38
+ const spec = oauthApp.spec;
39
+ const meta = oauthApp.metadata;
40
+ const { update, isUpdating, error: updateError, clearError: clearUpdateError } = useUpdateOAuthApp();
41
+ const { deleteApp, isDeleting, error: deleteError, clearError: clearDeleteError } = useDeleteOAuthApp();
42
+ const [mode, setMode] = useState("view");
43
+ const [confirmingDelete, setConfirmingDelete] = useState(false);
44
+ // Edit form state — initialized from current resource
45
+ const [provider, setProvider] = useState(spec?.provider ?? "");
46
+ const [clientId, setClientId] = useState(spec?.clientId ?? "");
47
+ const [clientSecret, setClientSecret] = useState("");
48
+ const [authorizationUrl, setAuthorizationUrl] = useState(spec?.authorizationUrl ?? "");
49
+ const [tokenUrl, setTokenUrl] = useState(spec?.tokenUrl ?? "");
50
+ const [scopes, setScopes] = useState(spec?.scopes.join(", ") ?? "");
51
+ const [userinfoUrl, setUserinfoUrl] = useState(spec?.userinfoUrl ?? "");
52
+ const [scopeParameterName, setScopeParameterName] = useState(spec?.scopeParameterName ?? "");
53
+ const [vendorApprovalStatus, setVendorApprovalStatus] = useState(approvalStatusToKey(spec?.vendorApprovalStatus));
54
+ const [vendorApprovalDocsUrl, setVendorApprovalDocsUrl] = useState(spec?.vendorApprovalDocsUrl ?? "");
55
+ const enterEdit = useCallback(() => {
56
+ setProvider(spec?.provider ?? "");
57
+ setClientId(spec?.clientId ?? "");
58
+ setClientSecret("");
59
+ setAuthorizationUrl(spec?.authorizationUrl ?? "");
60
+ setTokenUrl(spec?.tokenUrl ?? "");
61
+ setScopes(spec?.scopes.join(", ") ?? "");
62
+ setUserinfoUrl(spec?.userinfoUrl ?? "");
63
+ setScopeParameterName(spec?.scopeParameterName ?? "");
64
+ setVendorApprovalStatus(approvalStatusToKey(spec?.vendorApprovalStatus));
65
+ setVendorApprovalDocsUrl(spec?.vendorApprovalDocsUrl ?? "");
66
+ clearUpdateError();
67
+ setMode("edit");
68
+ }, [spec, clearUpdateError]);
69
+ const cancelEdit = useCallback(() => {
70
+ clearUpdateError();
71
+ setMode("view");
72
+ }, [clearUpdateError]);
73
+ const handleSave = useCallback(async (e) => {
74
+ e.preventDefault();
75
+ clearUpdateError();
76
+ const parsedScopes = scopes
77
+ .split(",")
78
+ .map((s) => s.trim())
79
+ .filter(Boolean);
80
+ try {
81
+ const updated = await update({
82
+ name: meta?.name ?? "",
83
+ slug: meta?.slug,
84
+ org: meta?.org ?? "",
85
+ provider: provider.trim(),
86
+ clientId: clientId.trim(),
87
+ ...(clientSecret.trim() && { clientSecret: clientSecret.trim() }),
88
+ authorizationUrl: authorizationUrl.trim(),
89
+ tokenUrl: tokenUrl.trim(),
90
+ ...(parsedScopes.length > 0 && { scopes: parsedScopes }),
91
+ ...(userinfoUrl.trim() && { userinfoUrl: userinfoUrl.trim() }),
92
+ ...(scopeParameterName.trim() && {
93
+ scopeParameterName: scopeParameterName.trim(),
94
+ }),
95
+ ...(vendorApprovalStatus !== "unspecified" && {
96
+ vendorApprovalStatus: APPROVAL_STATUS_MAP[vendorApprovalStatus],
97
+ }),
98
+ ...(vendorApprovalDocsUrl.trim() && {
99
+ vendorApprovalDocsUrl: vendorApprovalDocsUrl.trim(),
100
+ }),
101
+ });
102
+ setMode("view");
103
+ onUpdated?.(updated);
104
+ }
105
+ catch {
106
+ // error state is managed by useUpdateOAuthApp
107
+ }
108
+ }, [
109
+ meta, provider, clientId, clientSecret, authorizationUrl, tokenUrl,
110
+ scopes, userinfoUrl, scopeParameterName, vendorApprovalStatus,
111
+ vendorApprovalDocsUrl, update, clearUpdateError, onUpdated,
112
+ ]);
113
+ const handleDelete = useCallback(async () => {
114
+ const id = meta?.id;
115
+ if (!id)
116
+ return;
117
+ clearDeleteError();
118
+ try {
119
+ await deleteApp(id);
120
+ onDeleted?.();
121
+ }
122
+ catch {
123
+ // error state is managed by useDeleteOAuthApp
124
+ }
125
+ }, [meta, deleteApp, clearDeleteError, onDeleted]);
126
+ const canSave = provider.trim() !== "" &&
127
+ clientId.trim() !== "" &&
128
+ authorizationUrl.trim() !== "" &&
129
+ tokenUrl.trim() !== "" &&
130
+ !isUpdating;
131
+ const createdAt = oauthApp.status?.audit?.specAudit?.createdAt;
132
+ const updatedAt = oauthApp.status?.audit?.specAudit?.updatedAt;
133
+ return (_jsxs("div", { className: cn("space-y-4", className), children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0", children: [onBack && (_jsxs("button", { type: "button", onClick: onBack, className: "text-muted-foreground hover:text-foreground mb-1 flex items-center gap-1 text-xs transition-colors", children: [_jsx(ArrowLeftIcon, {}), "Back to list"] })), _jsx("h3", { className: "text-foreground truncate text-sm font-semibold", children: spec?.provider || meta?.name || "OAuth App" }), meta?.slug && (_jsx("span", { className: "text-muted-foreground font-mono text-xs", children: meta.slug }))] }), mode === "view" && (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx("button", { type: "button", onClick: enterEdit, className: cn("shrink-0 rounded-md px-2.5 py-1.5 text-xs font-medium", "text-muted-foreground hover:text-foreground hover:bg-accent/50", "transition-colors"), children: "Edit" }), _jsx("button", { type: "button", onClick: () => {
134
+ clearDeleteError();
135
+ setConfirmingDelete(true);
136
+ }, className: cn("shrink-0 rounded-md px-2.5 py-1.5 text-xs font-medium", "text-destructive/70 hover:text-destructive hover:bg-destructive/10", "transition-colors"), children: "Delete" })] }))] }), confirmingDelete && (_jsxs("div", { className: "rounded-md border border-destructive/30 bg-destructive/5 p-3", role: "alert", children: [_jsx("p", { className: "text-foreground mb-2 text-xs font-medium", children: "Delete this OAuth app?" }), _jsx("p", { className: "text-muted-foreground mb-3 text-[0.65rem]", children: "This action is permanent. Any MCP server overrides referencing this app will lose their binding." }), deleteError && (_jsx("p", { className: "text-destructive mb-2 text-[0.65rem]", role: "alert", children: getUserMessage(deleteError) })), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("button", { type: "button", onClick: handleDelete, disabled: isDeleting, className: cn("inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium", "bg-destructive text-destructive-foreground hover:bg-destructive/90", "disabled:pointer-events-none disabled:opacity-40"), children: [isDeleting && _jsx(SpinnerIcon, {}), "Delete permanently"] }), _jsx("button", { type: "button", onClick: () => {
137
+ setConfirmingDelete(false);
138
+ clearDeleteError();
139
+ }, disabled: isDeleting, className: cn("rounded-md px-2.5 py-1.5 text-xs", "text-muted-foreground hover:text-foreground hover:bg-accent/50", "disabled:pointer-events-none disabled:opacity-50"), children: "Cancel" })] })] })), mode === "view" ? (_jsx(ViewMode, { spec: spec, createdAt: createdAt, updatedAt: updatedAt })) : (_jsxs("form", { onSubmit: handleSave, className: "space-y-3", children: [_jsx(FieldInput, { id: "stgm-oauth-edit-provider", label: "Provider", value: provider, onChange: setProvider, placeholder: "e.g. Slack", disabled: isUpdating, required: true }), _jsx(FieldInput, { id: "stgm-oauth-edit-client-id", label: "Client ID", value: clientId, onChange: setClientId, placeholder: "OAuth client identifier", disabled: isUpdating, required: true }), _jsx(FieldInput, { id: "stgm-oauth-edit-client-secret", label: "Client secret", value: clientSecret, onChange: setClientSecret, placeholder: "Leave empty to keep existing secret", type: "password", hint: "Only enter a value to replace the existing secret", disabled: isUpdating }), _jsx(FieldInput, { id: "stgm-oauth-edit-auth-url", label: "Authorization URL", value: authorizationUrl, onChange: setAuthorizationUrl, placeholder: "https://vendor.com/oauth/authorize", disabled: isUpdating, required: true }), _jsx(FieldInput, { id: "stgm-oauth-edit-token-url", label: "Token URL", value: tokenUrl, onChange: setTokenUrl, placeholder: "https://vendor.com/oauth/token", disabled: isUpdating, required: true }), _jsx(FieldInput, { id: "stgm-oauth-edit-scopes", label: "Scopes", value: scopes, onChange: setScopes, placeholder: "read, write, admin", hint: "Comma-separated OAuth scopes", disabled: isUpdating }), _jsx(FieldInput, { id: "stgm-oauth-edit-userinfo-url", label: "Userinfo URL", value: userinfoUrl, onChange: setUserinfoUrl, placeholder: "https://vendor.com/userinfo", hint: "OIDC endpoint for fetching user profile data (optional)", disabled: isUpdating }), _jsx(FieldInput, { id: "stgm-oauth-edit-scope-param", label: "Scope parameter name", value: scopeParameterName, onChange: setScopeParameterName, placeholder: "scope", hint: 'Defaults to "scope". Some vendors use a non-standard name.', disabled: isUpdating }), _jsxs("div", { className: "space-y-1", children: [_jsx("label", { htmlFor: "stgm-oauth-edit-approval-status", className: "text-xs font-medium text-foreground", children: "Vendor approval status" }), _jsxs("select", { id: "stgm-oauth-edit-approval-status", value: vendorApprovalStatus, onChange: (e) => setVendorApprovalStatus(e.target.value), disabled: isUpdating, className: cn("w-full rounded-md border border-input bg-background px-2.5 py-1.5 text-xs text-foreground", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", "disabled:pointer-events-none disabled:opacity-50"), children: [_jsx("option", { value: "unspecified", children: "Unspecified (treated as approved)" }), _jsx("option", { value: "pending", children: "Pending" }), _jsx("option", { value: "approved", children: "Approved" }), _jsx("option", { value: "rejected", children: "Rejected" })] })] }), _jsx(FieldInput, { id: "stgm-oauth-edit-approval-docs", label: "Vendor approval docs URL", value: vendorApprovalDocsUrl, onChange: setVendorApprovalDocsUrl, placeholder: "https://docs.example.com/byoa", hint: "Help link shown when vendor approval is pending", disabled: isUpdating }), updateError && (_jsx("p", { className: "text-destructive text-[0.65rem]", role: "alert", children: getUserMessage(updateError) })), _jsxs("div", { className: "flex items-center gap-2 pt-1", children: [_jsxs("button", { type: "submit", disabled: !canSave, className: cn("inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium", "bg-primary text-primary-foreground hover:bg-primary/90", "disabled:pointer-events-none disabled:opacity-40"), children: [isUpdating && _jsx(SpinnerIcon, {}), "Save changes"] }), _jsx("button", { type: "button", onClick: cancelEdit, disabled: isUpdating, className: cn("rounded-md px-2.5 py-1.5 text-xs", "text-muted-foreground hover:text-foreground hover:bg-accent/50", "disabled:pointer-events-none disabled:opacity-50"), children: "Cancel" })] })] }))] }));
140
+ }
141
+ // ---------------------------------------------------------------------------
142
+ // Constants
143
+ // ---------------------------------------------------------------------------
144
+ const APPROVAL_STATUS_MAP = {
145
+ pending: VendorApprovalStatus.PENDING,
146
+ approved: VendorApprovalStatus.APPROVED,
147
+ rejected: VendorApprovalStatus.REJECTED,
148
+ };
149
+ const APPROVAL_STATUS_LABELS = {
150
+ [VendorApprovalStatus.UNSPECIFIED]: "Unspecified",
151
+ [VendorApprovalStatus.PENDING]: "Pending",
152
+ [VendorApprovalStatus.APPROVED]: "Approved",
153
+ [VendorApprovalStatus.REJECTED]: "Rejected",
154
+ };
155
+ function approvalStatusToKey(status) {
156
+ switch (status) {
157
+ case VendorApprovalStatus.PENDING:
158
+ return "pending";
159
+ case VendorApprovalStatus.APPROVED:
160
+ return "approved";
161
+ case VendorApprovalStatus.REJECTED:
162
+ return "rejected";
163
+ default:
164
+ return "unspecified";
165
+ }
166
+ }
167
+ // ---------------------------------------------------------------------------
168
+ // View mode
169
+ // ---------------------------------------------------------------------------
170
+ function ViewMode({ spec, createdAt, updatedAt, }) {
171
+ return (_jsxs("dl", { className: "space-y-2.5", children: [_jsx(Field, { label: "Provider", value: spec?.provider }), _jsx(Field, { label: "Client ID", value: spec?.clientId, mono: true }), _jsx(Field, { label: "Client secret", value: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" }), _jsx(Field, { label: "Authorization URL", value: spec?.authorizationUrl, mono: true }), _jsx(Field, { label: "Token URL", value: spec?.tokenUrl, mono: true }), spec?.scopes && spec.scopes.length > 0 && (_jsx(Field, { label: "Scopes", value: spec.scopes.join(", "), mono: true })), spec?.userinfoUrl && (_jsx(Field, { label: "Userinfo URL", value: spec.userinfoUrl, mono: true })), spec?.scopeParameterName && (_jsx(Field, { label: "Scope parameter name", value: spec.scopeParameterName, mono: true })), spec?.vendorApprovalStatus !== undefined &&
172
+ spec.vendorApprovalStatus !== VendorApprovalStatus.UNSPECIFIED && (_jsx(Field, { label: "Vendor approval", value: APPROVAL_STATUS_LABELS[spec.vendorApprovalStatus] ??
173
+ "Unknown" })), spec?.vendorApprovalDocsUrl && (_jsx(Field, { label: "Approval docs", value: spec.vendorApprovalDocsUrl, mono: true })), _jsxs("div", { className: "flex gap-6", children: [createdAt && (_jsx(Field, { label: "Created", value: formatDate(timestampDate(createdAt)) })), updatedAt && (_jsx(Field, { label: "Updated", value: formatDate(timestampDate(updatedAt)) }))] })] }));
174
+ }
175
+ // ---------------------------------------------------------------------------
176
+ // Shared primitives
177
+ // ---------------------------------------------------------------------------
178
+ function Field({ label, value, mono, }) {
179
+ if (!value)
180
+ return null;
181
+ return (_jsxs("div", { children: [_jsx("dt", { className: "text-muted-foreground text-[0.65rem] font-medium", children: label }), _jsx("dd", { className: cn("text-foreground mt-0.5 break-all text-xs", mono && "font-mono"), children: value })] }));
182
+ }
183
+ function FieldInput({ id, label, value, onChange, placeholder, hint, type = "text", disabled, required, }) {
184
+ return (_jsxs("div", { className: "space-y-1", children: [_jsx("label", { htmlFor: id, className: "text-xs font-medium text-foreground", children: label }), _jsx("input", { id: id, type: type, value: value, onChange: (e) => onChange(e.target.value), placeholder: placeholder, disabled: disabled, required: required, className: cn("w-full rounded-md border border-input bg-background px-2.5 py-1.5 text-xs text-foreground", "placeholder:text-muted-foreground", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", "disabled:pointer-events-none disabled:opacity-50") }), hint && (_jsx("p", { className: "text-[0.65rem] text-muted-foreground", children: hint }))] }));
185
+ }
186
+ function formatDate(date) {
187
+ return date.toLocaleDateString(undefined, {
188
+ month: "short",
189
+ day: "numeric",
190
+ year: "numeric",
191
+ });
192
+ }
193
+ // ---------------------------------------------------------------------------
194
+ // Icons
195
+ // ---------------------------------------------------------------------------
196
+ function ArrowLeftIcon() {
197
+ return (_jsx("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: _jsx("path", { d: "M10 3L5 8l5 5" }) }));
198
+ }
199
+ function SpinnerIcon() {
200
+ return (_jsx("svg", { width: "12", height: "12", viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", className: "animate-spin", "aria-hidden": "true", children: _jsx("path", { d: "M8 2a6 6 0 1 0 6 6" }) }));
201
+ }
202
+ //# sourceMappingURL=OAuthAppDetailPanel.js.map