@wildo-ai/presets-components 1.1.3 → 1.1.4
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/esm/components/ai-elements/decision/approval.d.ts +24 -4
- package/dist/esm/components/ai-elements/decision/approval.d.ts.map +1 -1
- package/dist/esm/components/ai-elements/decision/approval.js +35 -7
- package/dist/esm/components/ai-elements/decision/approval.js.map +1 -1
- package/dist/esm/components/app/public-layout-main-container.d.ts.map +1 -1
- package/dist/esm/components/app/public-layout-main-container.js +1 -1
- package/dist/esm/components/app/public-layout-main-container.js.map +1 -1
- package/dist/esm/components/feedback/empty-state.d.ts.map +1 -1
- package/dist/esm/components/feedback/empty-state.js +11 -1
- package/dist/esm/components/feedback/empty-state.js.map +1 -1
- package/dist/esm/components/feedback/notification-center.js +1 -1
- package/dist/esm/components/feedback/notification-center.js.map +1 -1
- package/dist/esm/components/form/controls/file/providers/google-drive-picker.d.ts +52 -0
- package/dist/esm/components/form/controls/file/providers/google-drive-picker.d.ts.map +1 -0
- package/dist/esm/components/form/controls/file/providers/google-drive-picker.js +157 -0
- package/dist/esm/components/form/controls/file/providers/google-drive-picker.js.map +1 -0
- package/dist/esm/components/form/controls/file/providers/google-drive-picker.lazy.d.ts +16 -0
- package/dist/esm/components/form/controls/file/providers/google-drive-picker.lazy.d.ts.map +1 -0
- package/dist/esm/components/form/controls/file/providers/google-drive-picker.lazy.js +20 -0
- package/dist/esm/components/form/controls/file/providers/google-drive-picker.lazy.js.map +1 -0
- package/dist/esm/components/form/controls/file/providers/onedrive-picker.d.ts +37 -0
- package/dist/esm/components/form/controls/file/providers/onedrive-picker.d.ts.map +1 -0
- package/dist/esm/components/form/controls/file/providers/onedrive-picker.js +125 -0
- package/dist/esm/components/form/controls/file/providers/onedrive-picker.js.map +1 -0
- package/dist/esm/components/form/controls/file/providers/onedrive-picker.lazy.d.ts +16 -0
- package/dist/esm/components/form/controls/file/providers/onedrive-picker.lazy.d.ts.map +1 -0
- package/dist/esm/components/form/controls/file/providers/onedrive-picker.lazy.js +20 -0
- package/dist/esm/components/form/controls/file/providers/onedrive-picker.lazy.js.map +1 -0
- package/dist/esm/components/navigation/app-level/utility-panel.d.ts.map +1 -1
- package/dist/esm/components/navigation/app-level/utility-panel.js +9 -2
- package/dist/esm/components/navigation/app-level/utility-panel.js.map +1 -1
- package/dist/esm/components/sections/tabs.d.ts.map +1 -1
- package/dist/esm/components/sections/tabs.js +5 -1
- package/dist/esm/components/sections/tabs.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/registration/register-default-presets.d.ts.map +1 -1
- package/dist/esm/registration/register-default-presets.js +4 -0
- package/dist/esm/registration/register-default-presets.js.map +1 -1
- package/dist/esm/registration/register-provider-components.d.ts +31 -0
- package/dist/esm/registration/register-provider-components.d.ts.map +1 -0
- package/dist/esm/registration/register-provider-components.js +45 -0
- package/dist/esm/registration/register-provider-components.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +6 -5
|
@@ -24,23 +24,43 @@ export type AI_ApprovalRequestProps = ComponentProps<typeof Alert> & {
|
|
|
24
24
|
*/
|
|
25
25
|
toolName?: string;
|
|
26
26
|
executionContext?: Record<string, unknown>;
|
|
27
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Offer the approver an EDITOR over the proposed arguments (#566).
|
|
29
|
+
*
|
|
30
|
+
* Off by default, and it is not a styling preference: turning it on changes what an approval MEANS
|
|
31
|
+
* — the approver stops assenting to the agent's call and starts authoring one. A surface that
|
|
32
|
+
* shows the editor must be wired to a decision path that carries the result, or it collects a
|
|
33
|
+
* change and drops it, which is the failure #537 refused to ship.
|
|
34
|
+
*
|
|
35
|
+
* v1 is a RAW JSON editor rather than a generated form. The tool's `inputSchema` is not
|
|
36
|
+
* transported to the browser yet, and the server's validation — not the browser's — is the
|
|
37
|
+
* control, so a textarea the server refuses with a readable message is a complete and honest
|
|
38
|
+
* first version. The generated form is its own issue.
|
|
39
|
+
*/
|
|
40
|
+
allowArgumentModification?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* `modifiedToolArgs` is present only when the approver EDITED the arguments. Absent means "run the
|
|
43
|
+
* call as proposed", which is what every approval meant before this parameter existed.
|
|
44
|
+
*/
|
|
45
|
+
onApprove?: (approvalId: string, comment?: string, modifiedToolArgs?: Record<string, unknown>) => void;
|
|
28
46
|
onDeny?: (approvalId: string, comment?: string) => void;
|
|
29
47
|
onEscalate?: (approvalId: string, comment?: string) => void;
|
|
30
48
|
isProcessing?: boolean;
|
|
31
49
|
createdAt?: Date;
|
|
32
50
|
};
|
|
33
|
-
export declare const AI_ApprovalRequest: ({ approvalId, actionDescription, riskLevel, executionId, systemRef, expiresAt, requiredRoles, toolName, executionContext, onApprove, onDeny, onEscalate, isProcessing, createdAt, className, ...props }: AI_ApprovalRequestProps) => React.JSX.Element | null;
|
|
51
|
+
export declare const AI_ApprovalRequest: ({ approvalId, actionDescription, riskLevel, executionId, systemRef, expiresAt, requiredRoles, toolName, executionContext, allowArgumentModification, onApprove, onDeny, onEscalate, isProcessing, createdAt, className, ...props }: AI_ApprovalRequestProps) => React.JSX.Element | null;
|
|
34
52
|
export type AI_ApprovalActionsProps = ComponentProps<"div"> & {
|
|
35
53
|
approvalId: string;
|
|
36
54
|
riskLevel?: "low" | "medium" | "high" | "critical";
|
|
37
|
-
|
|
55
|
+
/** Present only while the approver has the argument editor open with a parseable draft (#566). */
|
|
56
|
+
modifiedToolArgs?: Record<string, unknown>;
|
|
57
|
+
onApprove?: (approvalId: string, comment?: string, modifiedToolArgs?: Record<string, unknown>) => void;
|
|
38
58
|
onDeny?: (approvalId: string, comment?: string) => void;
|
|
39
59
|
onEscalate?: (approvalId: string, comment?: string) => void;
|
|
40
60
|
isProcessing?: boolean;
|
|
41
61
|
disabled?: boolean;
|
|
42
62
|
};
|
|
43
|
-
export declare const AI_ApprovalActions: ({ approvalId, riskLevel, onApprove, onDeny, onEscalate, isProcessing, disabled, className, ...props }: AI_ApprovalActionsProps) => React.JSX.Element | null;
|
|
63
|
+
export declare const AI_ApprovalActions: ({ approvalId, riskLevel, modifiedToolArgs, onApprove, onDeny, onEscalate, isProcessing, disabled, className, ...props }: AI_ApprovalActionsProps) => React.JSX.Element | null;
|
|
44
64
|
export type AI_ApprovalQueueItem = {
|
|
45
65
|
approvalId: string;
|
|
46
66
|
executionId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval.d.ts","sourceRoot":"","sources":["../../../../../src/components/ai-elements/decision/approval.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EACL,KAAK,EAmBN,MAAM,6BAA6B,CAAC;AAGrC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAiD5C,MAAM,MAAM,uBAAuB,GAAG,cAAc,CAAC,OAAO,KAAK,CAAC,GAAG;IACnE,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;;;OAKG;IACH,SAAS,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3C,SAAS,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"approval.d.ts","sourceRoot":"","sources":["../../../../../src/components/ai-elements/decision/approval.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, Badge, Button, ButtonVariants_Variant, ScrollArea, TextareaRoot, cn, useI18n, Surface, } from '@wildo-ai/saas-frontend-lib';
|
|
5
5
|
import { FrontendComponentType, ButtonSize, SurfaceVariant } from "@wildo-ai/presets-components-models";
|
|
@@ -40,25 +40,53 @@ function useCountdown(expiresAt) {
|
|
|
40
40
|
: `${seconds}s`;
|
|
41
41
|
return { remaining, isExpired: false };
|
|
42
42
|
}
|
|
43
|
-
export const AI_ApprovalRequest = ({ approvalId, actionDescription, riskLevel, executionId, systemRef, expiresAt, requiredRoles, toolName, executionContext, onApprove, onDeny, onEscalate, isProcessing, createdAt, className, ...props }) => {
|
|
43
|
+
export const AI_ApprovalRequest = ({ approvalId, actionDescription, riskLevel, executionId, systemRef, expiresAt, requiredRoles, toolName, executionContext, allowArgumentModification, onApprove, onDeny, onEscalate, isProcessing, createdAt, className, ...props }) => {
|
|
44
44
|
const { tComponent, isReady } = useI18n({ component: CT });
|
|
45
45
|
const { remaining, isExpired } = useCountdown(expiresAt);
|
|
46
46
|
const variant = riskLevel === "critical" || riskLevel === "high" ? "destructive" : "default";
|
|
47
|
+
/*
|
|
48
|
+
* The argument editor's state (#566).
|
|
49
|
+
*
|
|
50
|
+
* `draft` is `null` while the approver is reading rather than editing — distinct from an empty
|
|
51
|
+
* string, which is a draft they have cleared. Opening the editor seeds it from the PROPOSED
|
|
52
|
+
* arguments, so the starting point is the call the agent asked for and an approver changes one
|
|
53
|
+
* value rather than retyping the object.
|
|
54
|
+
*/
|
|
55
|
+
const [draft, setDraft] = React.useState(null);
|
|
56
|
+
const parsedDraft = React.useMemo(() => {
|
|
57
|
+
if (draft === null)
|
|
58
|
+
return { value: undefined, invalid: false };
|
|
59
|
+
try {
|
|
60
|
+
const value = JSON.parse(draft);
|
|
61
|
+
// An array or a scalar is valid JSON and cannot be a tool's arguments. Refusing it HERE spares
|
|
62
|
+
// the round trip; the server refuses it too, which is what actually protects the call.
|
|
63
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
64
|
+
return { value: undefined, invalid: true };
|
|
65
|
+
return { value: value, invalid: false };
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return { value: undefined, invalid: true };
|
|
69
|
+
}
|
|
70
|
+
}, [draft]);
|
|
47
71
|
if (!isReady)
|
|
48
72
|
return null;
|
|
49
|
-
return (_jsxs(Alert, { variant: variant, className: cn("flex flex-col gap-card-sm", className), ...props, children: [_jsxs("div", { className: "flex items-center justify-between gap-element", children: [_jsxs("div", { className: "flex items-center gap-element", children: [riskLevel && (_jsx(Badge, { variant: riskLevel === "critical" || riskLevel === "high" ? "destructive" : "outline", className: "text-2xs", children: tComponent(CT, `risk${riskLevel.charAt(0).toUpperCase()}${riskLevel.slice(1)}`) })), systemRef && (_jsx("span", { className: "text-2xs text-muted-foreground", children: systemRef }))] }), remaining && (_jsx(Badge, { variant: "secondary", className: "text-2xs tabular-nums", children: tComponent(CT, "expiresCountdown", { time: remaining }) })), isExpired && (_jsx(Badge, { variant: "destructive", className: "text-2xs", children: tComponent(CT, "expired") }))] }), _jsx(AlertDescription, { className: "text-sm", children: actionDescription }), requiredRoles && requiredRoles.length > 0 && (_jsxs("div", { className: "flex items-center gap-element", children: [_jsxs("span", { className: "text-2xs text-muted-foreground", children: [tComponent(CT, "requiredRoles"), ":"] }), _jsx("div", { className: "flex gap-1", children: requiredRoles.map((role) => (_jsx(Badge, { variant: "outline", className: "text-2xs", children: role }, role))) })] })), toolName !== undefined && (_jsxs("div", { className: "flex items-center gap-element", children: [_jsxs("span", { className: "text-2xs text-muted-foreground", children: [tComponent(CT, "toolCall"), ":"] }), _jsx("code", { className: "rounded bg-muted px-1 py-0.5 text-2xs font-mono", children: toolName })] })), executionContext && Object.keys(executionContext).length > 0 && (_jsxs("div", { className: "flex flex-col gap-element", children: [_jsxs("span", { className: "text-2xs text-muted-foreground", children: [tComponent(CT, "toolArguments"), ":"] }), _jsx(Surface, { asChild: true, emitPolicyVars: false, variant: SurfaceVariant.INSET, children: _jsx("dl", { className: "grid grid-cols-[auto_1fr] gap-x-element gap-y-0.5 rounded-md bg-muted p-2 text-2xs", children: Object.entries(executionContext).map(([key, value]) => (_jsxs(React.Fragment, { children: [_jsx("dt", { className: "font-mono text-muted-foreground", children: key }), _jsx("dd", { className: "min-w-0 break-words font-mono", children: typeof value === "string" || typeof value === "number" || typeof value === "boolean"
|
|
73
|
+
return (_jsxs(Alert, { variant: variant, className: cn("flex flex-col gap-card-sm", className), ...props, children: [_jsxs("div", { className: "flex items-center justify-between gap-element", children: [_jsxs("div", { className: "flex items-center gap-element", children: [riskLevel && (_jsx(Badge, { variant: riskLevel === "critical" || riskLevel === "high" ? "destructive" : "outline", className: "text-2xs", children: tComponent(CT, `risk${riskLevel.charAt(0).toUpperCase()}${riskLevel.slice(1)}`) })), systemRef && (_jsx("span", { className: "text-2xs text-muted-foreground", children: systemRef }))] }), remaining && (_jsx(Badge, { variant: "secondary", className: "text-2xs tabular-nums", children: tComponent(CT, "expiresCountdown", { time: remaining }) })), isExpired && (_jsx(Badge, { variant: "destructive", className: "text-2xs", children: tComponent(CT, "expired") }))] }), _jsx(AlertDescription, { className: "text-sm", children: actionDescription }), requiredRoles && requiredRoles.length > 0 && (_jsxs("div", { className: "flex items-center gap-element", children: [_jsxs("span", { className: "text-2xs text-muted-foreground", children: [tComponent(CT, "requiredRoles"), ":"] }), _jsx("div", { className: "flex gap-1", children: requiredRoles.map((role) => (_jsx(Badge, { variant: "outline", className: "text-2xs", children: role }, role))) })] })), toolName !== undefined && (_jsxs("div", { className: "flex items-center gap-element", children: [_jsxs("span", { className: "text-2xs text-muted-foreground", children: [tComponent(CT, "toolCall"), ":"] }), _jsx("code", { className: "rounded bg-muted px-1 py-0.5 text-2xs font-mono", children: toolName })] })), executionContext && Object.keys(executionContext).length > 0 && (_jsxs("div", { className: "flex flex-col gap-element", children: [_jsxs("div", { className: "flex items-center justify-between gap-element", children: [_jsxs("span", { className: "text-2xs text-muted-foreground", children: [tComponent(CT, "toolArguments"), ":"] }), allowArgumentModification && (_jsx(Button, { type: "button", variant: ButtonVariants_Variant.GHOST, size: ButtonSize.SM, disabled: isProcessing || isExpired, onClick: () => setDraft(draft === null ? JSON.stringify(executionContext, null, 2) : null), children: tComponent(CT, draft === null ? "editArguments" : "discardArgumentEdits") }))] }), draft === null ? (_jsx(Surface, { asChild: true, emitPolicyVars: false, variant: SurfaceVariant.INSET, children: _jsx("dl", { className: "grid grid-cols-[auto_1fr] gap-x-element gap-y-0.5 rounded-md bg-muted p-2 text-2xs", children: Object.entries(executionContext).map(([key, value]) => (_jsxs(React.Fragment, { children: [_jsx("dt", { className: "font-mono text-muted-foreground", children: key }), _jsx("dd", { className: "min-w-0 break-words font-mono", children: typeof value === "string" || typeof value === "number" || typeof value === "boolean"
|
|
50
74
|
? String(value)
|
|
51
|
-
: JSON.stringify(value) })] }, key))) }) })] })), _jsx(AI_ApprovalActions, { approvalId: approvalId, riskLevel: riskLevel, onApprove: onApprove, onDeny: onDeny, onEscalate: onEscalate, isProcessing: isProcessing,
|
|
75
|
+
: JSON.stringify(value) })] }, key))) }) })) : (_jsxs(_Fragment, { children: [_jsx(TextareaRoot, { rows: Math.min(12, Object.keys(executionContext).length + 3), value: draft, onChange: (e) => setDraft(e.target.value), className: "font-mono text-2xs", disabled: isProcessing || isExpired, "aria-invalid": parsedDraft.invalid || undefined, "aria-label": tComponent(CT, "editArguments") }), parsedDraft.invalid && (_jsx("span", { className: "text-2xs text-destructive", children: tComponent(CT, "argumentsNotValidJson") }))] }))] })), _jsx(AI_ApprovalActions, { approvalId: approvalId, riskLevel: riskLevel, onApprove: onApprove, onDeny: onDeny, onEscalate: onEscalate, isProcessing: isProcessing,
|
|
76
|
+
// Approving with unparseable text would send nothing and silently run the model's own
|
|
77
|
+
// arguments — a change collected and dropped, which is the one outcome this feature exists
|
|
78
|
+
// to prevent. The button is unavailable until the draft is an object.
|
|
79
|
+
disabled: isExpired || parsedDraft.invalid, modifiedToolArgs: parsedDraft.value })] }));
|
|
52
80
|
};
|
|
53
|
-
export const AI_ApprovalActions = ({ approvalId, riskLevel, onApprove, onDeny, onEscalate, isProcessing, disabled, className, ...props }) => {
|
|
81
|
+
export const AI_ApprovalActions = ({ approvalId, riskLevel, modifiedToolArgs, onApprove, onDeny, onEscalate, isProcessing, disabled, className, ...props }) => {
|
|
54
82
|
const { tComponent, isReady } = useI18n({ component: CT });
|
|
55
83
|
const [comment, setComment] = React.useState("");
|
|
56
84
|
const isHighRisk = riskLevel === "high" || riskLevel === "critical";
|
|
57
85
|
const actionsDisabled = isProcessing || disabled;
|
|
58
86
|
if (!isReady)
|
|
59
87
|
return null;
|
|
60
|
-
const approveButton = (_jsx(Button, { type: "button", variant: ButtonVariants_Variant.DEFAULT, size: ButtonSize.SM, disabled: actionsDisabled, onClick: isHighRisk ? undefined : () => onApprove?.(approvalId, comment || undefined), children: isProcessing ? tComponent(CT, "processing") : tComponent(CT, "approve") }));
|
|
61
|
-
return (_jsxs("div", { className: cn("flex flex-col gap-2", className), ...props, children: [_jsx(TextareaRoot, { rows: 2, value: comment, onChange: (e) => setComment(e.target.value), placeholder: tComponent(CT, "commentPlaceholder"), className: "text-xs", disabled: actionsDisabled }), _jsxs("div", { className: "flex items-center gap-element", children: [isHighRisk ? (_jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: approveButton }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: tComponent(CT, "confirmTitle") }), _jsx(AlertDialogDescription, { children: tComponent(CT, "confirmDescription") })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: tComponent(CT, "confirmCancel") }), _jsx(AlertDialogAction, { onClick: () => onApprove?.(approvalId, comment || undefined), children: tComponent(CT, "confirmProceed") })] })] })] })) : (approveButton), _jsx(Button, { type: "button", variant: ButtonVariants_Variant.OUTLINE, size: ButtonSize.SM, disabled: actionsDisabled, onClick: () => onDeny?.(approvalId, comment || undefined), children: tComponent(CT, "deny") }), onEscalate && (_jsx(Button, { type: "button", variant: ButtonVariants_Variant.SECONDARY, size: ButtonSize.SM, disabled: actionsDisabled, onClick: () => onEscalate?.(approvalId, comment || undefined), children: tComponent(CT, "escalate") }))] })] }));
|
|
88
|
+
const approveButton = (_jsx(Button, { type: "button", variant: ButtonVariants_Variant.DEFAULT, size: ButtonSize.SM, disabled: actionsDisabled, onClick: isHighRisk ? undefined : () => onApprove?.(approvalId, comment || undefined, modifiedToolArgs), children: isProcessing ? tComponent(CT, "processing") : tComponent(CT, "approve") }));
|
|
89
|
+
return (_jsxs("div", { className: cn("flex flex-col gap-2", className), ...props, children: [_jsx(TextareaRoot, { rows: 2, value: comment, onChange: (e) => setComment(e.target.value), placeholder: tComponent(CT, "commentPlaceholder"), className: "text-xs", disabled: actionsDisabled }), _jsxs("div", { className: "flex items-center gap-element", children: [isHighRisk ? (_jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: approveButton }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: tComponent(CT, "confirmTitle") }), _jsx(AlertDialogDescription, { children: tComponent(CT, "confirmDescription") })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: tComponent(CT, "confirmCancel") }), _jsx(AlertDialogAction, { onClick: () => onApprove?.(approvalId, comment || undefined, modifiedToolArgs), children: tComponent(CT, "confirmProceed") })] })] })] })) : (approveButton), _jsx(Button, { type: "button", variant: ButtonVariants_Variant.OUTLINE, size: ButtonSize.SM, disabled: actionsDisabled, onClick: () => onDeny?.(approvalId, comment || undefined), children: tComponent(CT, "deny") }), onEscalate && (_jsx(Button, { type: "button", variant: ButtonVariants_Variant.SECONDARY, size: ButtonSize.SM, disabled: actionsDisabled, onClick: () => onEscalate?.(approvalId, comment || undefined), children: tComponent(CT, "escalate") }))] })] }));
|
|
62
90
|
};
|
|
63
91
|
//===============================================================
|
|
64
92
|
// AI_ApprovalQueue
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval.js","sourceRoot":"","sources":["../../../../../src/components/ai-elements/decision/approval.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport {\n Alert,\n AlertDescription,\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n Badge,\n Button,\n ButtonVariants_Variant,\n ScrollArea,\n TextareaRoot,\n cn,\n useI18n,\n Surface,\n} from '@wildo-ai/saas-frontend-lib';\n\nimport { FrontendComponentType, ButtonSize, SurfaceVariant } from \"@wildo-ai/presets-components-models\";\nimport type { ComponentProps } from \"react\";\n\nconst CT: FrontendComponentType = FrontendComponentType.LOW_LEVEL_AI_APPROVAL;\n\n//===============================================================\n// Human-in-the-Loop Approval Components\n//\n// BACKEND DEPENDENCIES:\n// - FlowsActorsContext.respondToApproval() — implemented (WebSocket emit)\n// - WebSocket event: FLOWS_ACTORS_APPROVAL_REQUEST — implemented\n// - FlowsActorsExecution.pendingApproval — schema ready:\n// { approvalId, actionDescription, riskLevel, expiresAt?, requiredRoles? }\n//\n// Components render approval UI from props. Wire to context via\n// the saas-frontend-lib wrapper (flows-actors/approval.tsx).\n//===============================================================\n\n//===============================================================\n// useCountdown — shared countdown hook\n//===============================================================\n\nfunction useCountdown(expiresAt: Date | undefined): { remaining: string | null; isExpired: boolean } {\n const [now, setNow] = React.useState(() => Date.now());\n\n React.useEffect(() => {\n if (!expiresAt) return;\n const id = setInterval(() => setNow(Date.now()), 1_000);\n return () => clearInterval(id);\n }, [expiresAt]);\n\n if (!expiresAt) return { remaining: null, isExpired: false };\n\n const diff = expiresAt.getTime() - now;\n if (diff <= 0) return { remaining: null, isExpired: true };\n\n const totalSeconds = Math.floor(diff / 1_000);\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n const remaining = minutes > 0\n ? `${minutes}m ${String(seconds).padStart(2, \"0\")}s`\n : `${seconds}s`;\n\n return { remaining, isExpired: false };\n}\n\n//===============================================================\n// AI_ApprovalRequest\n//===============================================================\n\nexport type AI_ApprovalRequestProps = ComponentProps<typeof Alert> & {\n approvalId: string;\n actionDescription: string;\n /**\n * OPTIONAL, because nothing populates it. A risk level exists only on\n * `WS_FlowsActorsApprovalRequestPayload`, a payload no code emits; the announcement a paused turn\n * really sends carries a tool name and its arguments and no risk claim (#528). Absent means the\n * badge is not rendered — a default here would show a severity nobody declared.\n */\n riskLevel?: \"low\" | \"medium\" | \"high\" | \"critical\";\n executionId: string;\n systemRef?: string;\n expiresAt?: Date;\n requiredRoles?: string[];\n /**\n * The gated tool call, and the arguments proposed for it.\n *\n * `toolName` is an IDENTIFIER, rendered as authored — it is the thing the agent asked to run,\n * and humanizing it here would invent display text no i18n tree owns.\n * `executionContext` carries the arguments (#455).\n */\n toolName?: string;\n executionContext?: Record<string, unknown>;\n onApprove?: (approvalId: string, comment?: string) => void;\n onDeny?: (approvalId: string, comment?: string) => void;\n onEscalate?: (approvalId: string, comment?: string) => void;\n isProcessing?: boolean;\n createdAt?: Date;\n};\n\nexport const AI_ApprovalRequest = ({\n approvalId,\n actionDescription,\n riskLevel,\n executionId,\n systemRef,\n expiresAt,\n requiredRoles,\n toolName,\n executionContext,\n onApprove,\n onDeny,\n onEscalate,\n isProcessing,\n createdAt,\n className,\n ...props\n}: AI_ApprovalRequestProps): React.JSX.Element | null => {\n const { tComponent, isReady } = useI18n({ component: CT });\n const { remaining, isExpired } = useCountdown(expiresAt);\n const variant = riskLevel === \"critical\" || riskLevel === \"high\" ? \"destructive\" : \"default\";\n\n if (!isReady) return null;\n\n return (\n <Alert variant={variant} className={cn(\"flex flex-col gap-card-sm\", className)} {...props}>\n <div className=\"flex items-center justify-between gap-element\">\n <div className=\"flex items-center gap-element\">\n {riskLevel && (\n <Badge\n variant={riskLevel === \"critical\" || riskLevel === \"high\" ? \"destructive\" : \"outline\"}\n className=\"text-2xs\"\n >\n {tComponent(CT, `risk${riskLevel.charAt(0).toUpperCase()}${riskLevel.slice(1)}` as any)}\n </Badge>\n )}\n {systemRef && (\n <span className=\"text-2xs text-muted-foreground\">{systemRef}</span>\n )}\n </div>\n\n {/* Countdown / Expired indicator */}\n {remaining && (\n <Badge variant=\"secondary\" className=\"text-2xs tabular-nums\">\n {tComponent(CT, \"expiresCountdown\", { time: remaining })}\n </Badge>\n )}\n {isExpired && (\n <Badge variant=\"destructive\" className=\"text-2xs\">\n {tComponent(CT, \"expired\")}\n </Badge>\n )}\n </div>\n\n <AlertDescription className=\"text-sm\">\n {actionDescription}\n </AlertDescription>\n\n {/* Required roles display */}\n {requiredRoles && requiredRoles.length > 0 && (\n <div className=\"flex items-center gap-element\">\n <span className=\"text-2xs text-muted-foreground\">{tComponent(CT, \"requiredRoles\")}:</span>\n <div className=\"flex gap-1\">\n {requiredRoles.map((role) => (\n <Badge key={role} variant=\"outline\" className=\"text-2xs\">\n {role}\n </Badge>\n ))}\n </div>\n </div>\n )}\n\n {/* The gated tool call — WHAT the approver is being asked to authorize (#455). */}\n {toolName !== undefined && (\n <div className=\"flex items-center gap-element\">\n <span className=\"text-2xs text-muted-foreground\">{tComponent(CT, \"toolCall\")}:</span>\n {/*\n * Rendered as authored. A tool name is an IDENTIFIER the agent runtime owns, and turning\n * `renameTodo` into \"Rename Todo\" would invent display text no i18n tree can correct —\n * the exact fallback `display-text-comes-from-i18n.md` retired. The approver is better\n * served by the name the system will actually run.\n */}\n <code className=\"rounded bg-muted px-1 py-0.5 text-2xs font-mono\">{toolName}</code>\n </div>\n )}\n\n {/*\n * The proposed ARGUMENTS, one row per key, expanded by default.\n *\n * This was a collapsed `JSON.stringify` in a `<pre>`. Two things were wrong with that and only\n * the second is cosmetic: a blob is not readable at approval speed, and COLLAPSED-BY-DEFAULT\n * hides the very thing being approved — an approver who never opens it is signing an unread\n * document, which is how an approval prompt stops being read at all.\n *\n * Keys render VERBATIM. They are the tool's own parameter names, they carry no i18n entry, and\n * humanizing them is forbidden for the same reason as the tool name. A value that is not a\n * primitive is serialized, because a nested object has no honest one-line form — and that\n * narrow case is the only place a JSON fragment survives.\n */}\n {executionContext && Object.keys(executionContext).length > 0 && (\n <div className=\"flex flex-col gap-element\">\n <span className=\"text-2xs text-muted-foreground\">{tComponent(CT, \"toolArguments\")}:</span>\n <Surface asChild emitPolicyVars={false} variant={SurfaceVariant.INSET}>\n <dl className=\"grid grid-cols-[auto_1fr] gap-x-element gap-y-0.5 rounded-md bg-muted p-2 text-2xs\">\n {Object.entries(executionContext).map(([key, value]) => (\n <React.Fragment key={key}>\n <dt className=\"font-mono text-muted-foreground\">{key}</dt>\n <dd className=\"min-w-0 break-words font-mono\">\n {typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\"\n ? String(value)\n : JSON.stringify(value)}\n </dd>\n </React.Fragment>\n ))}\n </dl>\n </Surface>\n </div>\n )}\n\n <AI_ApprovalActions\n approvalId={approvalId}\n riskLevel={riskLevel}\n onApprove={onApprove}\n onDeny={onDeny}\n onEscalate={onEscalate}\n isProcessing={isProcessing}\n disabled={isExpired}\n />\n </Alert>\n );\n};\n\n//===============================================================\n// AI_ApprovalActions\n//===============================================================\n\nexport type AI_ApprovalActionsProps = ComponentProps<\"div\"> & {\n approvalId: string;\n riskLevel?: \"low\" | \"medium\" | \"high\" | \"critical\";\n onApprove?: (approvalId: string, comment?: string) => void;\n onDeny?: (approvalId: string, comment?: string) => void;\n onEscalate?: (approvalId: string, comment?: string) => void;\n isProcessing?: boolean;\n disabled?: boolean;\n};\n\nexport const AI_ApprovalActions = ({\n approvalId,\n riskLevel,\n onApprove,\n onDeny,\n onEscalate,\n isProcessing,\n disabled,\n className,\n ...props\n}: AI_ApprovalActionsProps): React.JSX.Element | null => {\n const { tComponent, isReady } = useI18n({ component: CT });\n const [comment, setComment] = React.useState(\"\");\n const isHighRisk = riskLevel === \"high\" || riskLevel === \"critical\";\n const actionsDisabled = isProcessing || disabled;\n\n if (!isReady) return null;\n\n const approveButton = (\n <Button\n type=\"button\"\n variant={ButtonVariants_Variant.DEFAULT}\n size={ButtonSize.SM}\n disabled={actionsDisabled}\n onClick={isHighRisk ? undefined : () => onApprove?.(approvalId, comment || undefined)}\n >\n {isProcessing ? tComponent(CT, \"processing\") : tComponent(CT, \"approve\")}\n </Button>\n );\n\n return (\n <div className={cn(\"flex flex-col gap-2\", className)} {...props}>\n {/* Comment textarea */}\n <TextareaRoot\n rows={2}\n value={comment}\n onChange={(e) => setComment(e.target.value)}\n placeholder={tComponent(CT, \"commentPlaceholder\")}\n className=\"text-xs\"\n disabled={actionsDisabled}\n />\n\n <div className=\"flex items-center gap-element\">\n {/* Approve — with confirmation dialog for high/critical risk */}\n {isHighRisk ? (\n <AlertDialog>\n <AlertDialogTrigger asChild>\n {approveButton}\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>{tComponent(CT, \"confirmTitle\")}</AlertDialogTitle>\n <AlertDialogDescription>{tComponent(CT, \"confirmDescription\")}</AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>{tComponent(CT, \"confirmCancel\")}</AlertDialogCancel>\n <AlertDialogAction onClick={() => onApprove?.(approvalId, comment || undefined)}>\n {tComponent(CT, \"confirmProceed\")}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n ) : (\n approveButton\n )}\n\n {/* Deny */}\n <Button\n type=\"button\"\n variant={ButtonVariants_Variant.OUTLINE}\n size={ButtonSize.SM}\n disabled={actionsDisabled}\n onClick={() => onDeny?.(approvalId, comment || undefined)}\n >\n {tComponent(CT, \"deny\")}\n </Button>\n\n {/* Escalate (optional) */}\n {onEscalate && (\n <Button\n type=\"button\"\n variant={ButtonVariants_Variant.SECONDARY}\n size={ButtonSize.SM}\n disabled={actionsDisabled}\n onClick={() => onEscalate?.(approvalId, comment || undefined)}\n >\n {tComponent(CT, \"escalate\")}\n </Button>\n )}\n </div>\n </div>\n );\n};\n\n//===============================================================\n// AI_ApprovalQueue\n//===============================================================\n\nconst RISK_ORDER: Record<string, number> = { critical: 0, high: 1, medium: 2, low: 3 };\n\nexport type AI_ApprovalQueueItem = {\n approvalId: string;\n executionId: string;\n systemRef: string;\n actionDescription: string;\n /** OPTIONAL for the same reason as on a single request — nothing populates it (#528). */\n riskLevel?: \"low\" | \"medium\" | \"high\" | \"critical\";\n expiresAt?: Date;\n requiredRoles?: string[];\n executionContext?: Record<string, unknown>;\n createdAt?: Date;\n};\n\nexport type AI_ApprovalQueueProps = ComponentProps<\"div\"> & {\n items: AI_ApprovalQueueItem[];\n onApprove?: (approvalId: string, comment?: string) => void;\n onDeny?: (approvalId: string, comment?: string) => void;\n onEscalate?: (approvalId: string, comment?: string) => void;\n processingIds?: Set<string>;\n filter?: string;\n onFilterChange?: (filter: string) => void;\n};\n\nfunction useRelativeTimeFormatter(): (date: Date) => string {\n const { tComponent } = useI18n({ component: CT });\n return React.useCallback((date: Date): string => {\n const seconds = Math.floor((Date.now() - date.getTime()) / 1_000);\n if (seconds < 60) return tComponent(CT, \"timeAgoSeconds\", { count: String(seconds) });\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return tComponent(CT, \"timeAgoMinutes\", { count: String(minutes) });\n const hours = Math.floor(minutes / 60);\n return tComponent(CT, \"timeAgoHours\", { count: String(hours) });\n }, [tComponent]);\n}\n\nexport const AI_ApprovalQueue = ({\n items,\n onApprove,\n onDeny,\n onEscalate,\n processingIds,\n filter,\n onFilterChange,\n className,\n ...props\n}: AI_ApprovalQueueProps): React.JSX.Element | null => {\n const { tComponent, isReady } = useI18n({ component: CT });\n const formatRelativeTime = useRelativeTimeFormatter();\n const [sortByRisk, setSortByRisk] = React.useState(true);\n const [internalFilter, setInternalFilter] = React.useState(\"\");\n\n const activeFilter = filter ?? internalFilter;\n\n const filtered = React.useMemo(() => {\n let result = items;\n if (activeFilter) {\n const q = activeFilter.toLowerCase();\n result = result.filter((i) =>\n i.systemRef.toLowerCase().includes(q) ||\n i.actionDescription.toLowerCase().includes(q) ||\n i.executionId.toLowerCase().includes(q)\n );\n }\n if (sortByRisk) {\n result = [...result].sort((a, b) =>\n (RISK_ORDER[a.riskLevel] ?? 4) - (RISK_ORDER[b.riskLevel] ?? 4)\n );\n }\n return result;\n }, [items, activeFilter, sortByRisk]);\n\n if (!isReady) return null;\n\n return (\n <div className={cn(\"flex flex-col gap-card\", className)} {...props}>\n <div className=\"flex items-center justify-between gap-element\">\n <div className=\"flex items-center gap-element\">\n <h3 className=\"text-sm font-semibold\">\n {tComponent(CT, \"queueTitle\")}\n </h3>\n <Badge variant=\"secondary\">{items.length}</Badge>\n </div>\n\n <Button\n type=\"button\"\n variant={sortByRisk ? ButtonVariants_Variant.SECONDARY : ButtonVariants_Variant.GHOST}\n size={ButtonSize.SM}\n className=\"h-6 text-2xs\"\n onClick={() => setSortByRisk(!sortByRisk)}\n >\n {tComponent(CT, \"queueSortRisk\")}\n </Button>\n </div>\n\n {items.length === 0 ? (\n <p className=\"py-card text-center text-sm text-muted-foreground\">\n {tComponent(CT, \"queueEmpty\")}\n </p>\n ) : (\n <ScrollArea className=\"max-h-96\">\n <div className=\"flex flex-col gap-card-sm\">\n {filtered.map((item) => (\n <div key={item.approvalId} className=\"relative\">\n {item.createdAt && (\n <span className=\"absolute end-2 top-2 text-2xs text-muted-foreground\">\n {formatRelativeTime(item.createdAt)}\n </span>\n )}\n <AI_ApprovalRequest\n approvalId={item.approvalId}\n executionId={item.executionId}\n systemRef={item.systemRef}\n actionDescription={item.actionDescription}\n riskLevel={item.riskLevel}\n expiresAt={item.expiresAt}\n requiredRoles={item.requiredRoles}\n executionContext={item.executionContext}\n createdAt={item.createdAt}\n onApprove={onApprove}\n onDeny={onDeny}\n onEscalate={onEscalate}\n isProcessing={processingIds?.has(item.approvalId)}\n />\n </div>\n ))}\n </div>\n </ScrollArea>\n )}\n </div>\n );\n};\n"]}
|
|
1
|
+
{"version":3,"file":"approval.js","sourceRoot":"","sources":["../../../../../src/components/ai-elements/decision/approval.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport {\n Alert,\n AlertDescription,\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n Badge,\n Button,\n ButtonVariants_Variant,\n ScrollArea,\n TextareaRoot,\n cn,\n useI18n,\n Surface,\n} from '@wildo-ai/saas-frontend-lib';\n\nimport { FrontendComponentType, ButtonSize, SurfaceVariant } from \"@wildo-ai/presets-components-models\";\nimport type { ComponentProps } from \"react\";\n\nconst CT: FrontendComponentType = FrontendComponentType.LOW_LEVEL_AI_APPROVAL;\n\n//===============================================================\n// Human-in-the-Loop Approval Components\n//\n// BACKEND DEPENDENCIES:\n// - FlowsActorsContext.respondToApproval() — implemented (WebSocket emit)\n// - WebSocket event: FLOWS_ACTORS_APPROVAL_REQUEST — implemented\n// - FlowsActorsExecution.pendingApproval — schema ready:\n// { approvalId, actionDescription, riskLevel, expiresAt?, requiredRoles? }\n//\n// Components render approval UI from props. Wire to context via\n// the saas-frontend-lib wrapper (flows-actors/approval.tsx).\n//===============================================================\n\n//===============================================================\n// useCountdown — shared countdown hook\n//===============================================================\n\nfunction useCountdown(expiresAt: Date | undefined): { remaining: string | null; isExpired: boolean } {\n const [now, setNow] = React.useState(() => Date.now());\n\n React.useEffect(() => {\n if (!expiresAt) return;\n const id = setInterval(() => setNow(Date.now()), 1_000);\n return () => clearInterval(id);\n }, [expiresAt]);\n\n if (!expiresAt) return { remaining: null, isExpired: false };\n\n const diff = expiresAt.getTime() - now;\n if (diff <= 0) return { remaining: null, isExpired: true };\n\n const totalSeconds = Math.floor(diff / 1_000);\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n const remaining = minutes > 0\n ? `${minutes}m ${String(seconds).padStart(2, \"0\")}s`\n : `${seconds}s`;\n\n return { remaining, isExpired: false };\n}\n\n//===============================================================\n// AI_ApprovalRequest\n//===============================================================\n\nexport type AI_ApprovalRequestProps = ComponentProps<typeof Alert> & {\n approvalId: string;\n actionDescription: string;\n /**\n * OPTIONAL, because nothing populates it. A risk level exists only on\n * `WS_FlowsActorsApprovalRequestPayload`, a payload no code emits; the announcement a paused turn\n * really sends carries a tool name and its arguments and no risk claim (#528). Absent means the\n * badge is not rendered — a default here would show a severity nobody declared.\n */\n riskLevel?: \"low\" | \"medium\" | \"high\" | \"critical\";\n executionId: string;\n systemRef?: string;\n expiresAt?: Date;\n requiredRoles?: string[];\n /**\n * The gated tool call, and the arguments proposed for it.\n *\n * `toolName` is an IDENTIFIER, rendered as authored — it is the thing the agent asked to run,\n * and humanizing it here would invent display text no i18n tree owns.\n * `executionContext` carries the arguments (#455).\n */\n toolName?: string;\n executionContext?: Record<string, unknown>;\n /**\n * Offer the approver an EDITOR over the proposed arguments (#566).\n *\n * Off by default, and it is not a styling preference: turning it on changes what an approval MEANS\n * — the approver stops assenting to the agent's call and starts authoring one. A surface that\n * shows the editor must be wired to a decision path that carries the result, or it collects a\n * change and drops it, which is the failure #537 refused to ship.\n *\n * v1 is a RAW JSON editor rather than a generated form. The tool's `inputSchema` is not\n * transported to the browser yet, and the server's validation — not the browser's — is the\n * control, so a textarea the server refuses with a readable message is a complete and honest\n * first version. The generated form is its own issue.\n */\n allowArgumentModification?: boolean;\n /**\n * `modifiedToolArgs` is present only when the approver EDITED the arguments. Absent means \"run the\n * call as proposed\", which is what every approval meant before this parameter existed.\n */\n onApprove?: (approvalId: string, comment?: string, modifiedToolArgs?: Record<string, unknown>) => void;\n onDeny?: (approvalId: string, comment?: string) => void;\n onEscalate?: (approvalId: string, comment?: string) => void;\n isProcessing?: boolean;\n createdAt?: Date;\n};\n\nexport const AI_ApprovalRequest = ({\n approvalId,\n actionDescription,\n riskLevel,\n executionId,\n systemRef,\n expiresAt,\n requiredRoles,\n toolName,\n executionContext,\n allowArgumentModification,\n onApprove,\n onDeny,\n onEscalate,\n isProcessing,\n createdAt,\n className,\n ...props\n}: AI_ApprovalRequestProps): React.JSX.Element | null => {\n const { tComponent, isReady } = useI18n({ component: CT });\n const { remaining, isExpired } = useCountdown(expiresAt);\n const variant = riskLevel === \"critical\" || riskLevel === \"high\" ? \"destructive\" : \"default\";\n\n /*\n * The argument editor's state (#566).\n *\n * `draft` is `null` while the approver is reading rather than editing — distinct from an empty\n * string, which is a draft they have cleared. Opening the editor seeds it from the PROPOSED\n * arguments, so the starting point is the call the agent asked for and an approver changes one\n * value rather than retyping the object.\n */\n const [draft, setDraft] = React.useState<string | null>(null);\n const parsedDraft = React.useMemo(() => {\n if (draft === null) return { value: undefined, invalid: false };\n try {\n const value = JSON.parse(draft) as unknown;\n // An array or a scalar is valid JSON and cannot be a tool's arguments. Refusing it HERE spares\n // the round trip; the server refuses it too, which is what actually protects the call.\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) return { value: undefined, invalid: true };\n return { value: value as Record<string, unknown>, invalid: false };\n } catch {\n return { value: undefined, invalid: true };\n }\n }, [draft]);\n\n if (!isReady) return null;\n\n return (\n <Alert variant={variant} className={cn(\"flex flex-col gap-card-sm\", className)} {...props}>\n <div className=\"flex items-center justify-between gap-element\">\n <div className=\"flex items-center gap-element\">\n {riskLevel && (\n <Badge\n variant={riskLevel === \"critical\" || riskLevel === \"high\" ? \"destructive\" : \"outline\"}\n className=\"text-2xs\"\n >\n {tComponent(CT, `risk${riskLevel.charAt(0).toUpperCase()}${riskLevel.slice(1)}` as any)}\n </Badge>\n )}\n {systemRef && (\n <span className=\"text-2xs text-muted-foreground\">{systemRef}</span>\n )}\n </div>\n\n {/* Countdown / Expired indicator */}\n {remaining && (\n <Badge variant=\"secondary\" className=\"text-2xs tabular-nums\">\n {tComponent(CT, \"expiresCountdown\", { time: remaining })}\n </Badge>\n )}\n {isExpired && (\n <Badge variant=\"destructive\" className=\"text-2xs\">\n {tComponent(CT, \"expired\")}\n </Badge>\n )}\n </div>\n\n <AlertDescription className=\"text-sm\">\n {actionDescription}\n </AlertDescription>\n\n {/* Required roles display */}\n {requiredRoles && requiredRoles.length > 0 && (\n <div className=\"flex items-center gap-element\">\n <span className=\"text-2xs text-muted-foreground\">{tComponent(CT, \"requiredRoles\")}:</span>\n <div className=\"flex gap-1\">\n {requiredRoles.map((role) => (\n <Badge key={role} variant=\"outline\" className=\"text-2xs\">\n {role}\n </Badge>\n ))}\n </div>\n </div>\n )}\n\n {/* The gated tool call — WHAT the approver is being asked to authorize (#455). */}\n {toolName !== undefined && (\n <div className=\"flex items-center gap-element\">\n <span className=\"text-2xs text-muted-foreground\">{tComponent(CT, \"toolCall\")}:</span>\n {/*\n * Rendered as authored. A tool name is an IDENTIFIER the agent runtime owns, and turning\n * `renameTodo` into \"Rename Todo\" would invent display text no i18n tree can correct —\n * the exact fallback `display-text-comes-from-i18n.md` retired. The approver is better\n * served by the name the system will actually run.\n */}\n <code className=\"rounded bg-muted px-1 py-0.5 text-2xs font-mono\">{toolName}</code>\n </div>\n )}\n\n {/*\n * The proposed ARGUMENTS, one row per key, expanded by default.\n *\n * This was a collapsed `JSON.stringify` in a `<pre>`. Two things were wrong with that and only\n * the second is cosmetic: a blob is not readable at approval speed, and COLLAPSED-BY-DEFAULT\n * hides the very thing being approved — an approver who never opens it is signing an unread\n * document, which is how an approval prompt stops being read at all.\n *\n * Keys render VERBATIM. They are the tool's own parameter names, they carry no i18n entry, and\n * humanizing them is forbidden for the same reason as the tool name. A value that is not a\n * primitive is serialized, because a nested object has no honest one-line form — and that\n * narrow case is the only place a JSON fragment survives.\n */}\n {executionContext && Object.keys(executionContext).length > 0 && (\n <div className=\"flex flex-col gap-element\">\n <div className=\"flex items-center justify-between gap-element\">\n <span className=\"text-2xs text-muted-foreground\">{tComponent(CT, \"toolArguments\")}:</span>\n {/*\n * The door to approve-with-modifications (#566), rendered only when the surface's owner\n * declared it. An approver who edits these is AUTHORING a call the agent never\n * proposed, so it is opt-in per surface rather than always present.\n */}\n {allowArgumentModification && (\n <Button\n type=\"button\"\n variant={ButtonVariants_Variant.GHOST}\n size={ButtonSize.SM}\n disabled={isProcessing || isExpired}\n onClick={() => setDraft(draft === null ? JSON.stringify(executionContext, null, 2) : null)}\n >\n {tComponent(CT, draft === null ? \"editArguments\" : \"discardArgumentEdits\")}\n </Button>\n )}\n </div>\n {draft === null ? (\n <Surface asChild emitPolicyVars={false} variant={SurfaceVariant.INSET}>\n <dl className=\"grid grid-cols-[auto_1fr] gap-x-element gap-y-0.5 rounded-md bg-muted p-2 text-2xs\">\n {Object.entries(executionContext).map(([key, value]) => (\n <React.Fragment key={key}>\n <dt className=\"font-mono text-muted-foreground\">{key}</dt>\n <dd className=\"min-w-0 break-words font-mono\">\n {typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\"\n ? String(value)\n : JSON.stringify(value)}\n </dd>\n </React.Fragment>\n ))}\n </dl>\n </Surface>\n ) : (\n <>\n <TextareaRoot\n rows={Math.min(12, Object.keys(executionContext).length + 3)}\n value={draft}\n onChange={(e) => setDraft(e.target.value)}\n className=\"font-mono text-2xs\"\n disabled={isProcessing || isExpired}\n aria-invalid={parsedDraft.invalid || undefined}\n aria-label={tComponent(CT, \"editArguments\")}\n />\n {/*\n * Local JSON validity only. Whether these arguments SUIT the tool is the server's\n * question — it holds the tool's `inputSchema`, refuses an edit that violates it, and\n * leaves the approval pending with a message naming the offending argument. Judging\n * that here would be a second, weaker copy of the control.\n */}\n {parsedDraft.invalid && (\n <span className=\"text-2xs text-destructive\">{tComponent(CT, \"argumentsNotValidJson\")}</span>\n )}\n </>\n )}\n </div>\n )}\n\n <AI_ApprovalActions\n approvalId={approvalId}\n riskLevel={riskLevel}\n onApprove={onApprove}\n onDeny={onDeny}\n onEscalate={onEscalate}\n isProcessing={isProcessing}\n // Approving with unparseable text would send nothing and silently run the model's own\n // arguments — a change collected and dropped, which is the one outcome this feature exists\n // to prevent. The button is unavailable until the draft is an object.\n disabled={isExpired || parsedDraft.invalid}\n modifiedToolArgs={parsedDraft.value}\n />\n </Alert>\n );\n};\n\n//===============================================================\n// AI_ApprovalActions\n//===============================================================\n\nexport type AI_ApprovalActionsProps = ComponentProps<\"div\"> & {\n approvalId: string;\n riskLevel?: \"low\" | \"medium\" | \"high\" | \"critical\";\n /** Present only while the approver has the argument editor open with a parseable draft (#566). */\n modifiedToolArgs?: Record<string, unknown>;\n onApprove?: (approvalId: string, comment?: string, modifiedToolArgs?: Record<string, unknown>) => void;\n onDeny?: (approvalId: string, comment?: string) => void;\n onEscalate?: (approvalId: string, comment?: string) => void;\n isProcessing?: boolean;\n disabled?: boolean;\n};\n\nexport const AI_ApprovalActions = ({\n approvalId,\n riskLevel,\n modifiedToolArgs,\n onApprove,\n onDeny,\n onEscalate,\n isProcessing,\n disabled,\n className,\n ...props\n}: AI_ApprovalActionsProps): React.JSX.Element | null => {\n const { tComponent, isReady } = useI18n({ component: CT });\n const [comment, setComment] = React.useState(\"\");\n const isHighRisk = riskLevel === \"high\" || riskLevel === \"critical\";\n const actionsDisabled = isProcessing || disabled;\n\n if (!isReady) return null;\n\n const approveButton = (\n <Button\n type=\"button\"\n variant={ButtonVariants_Variant.DEFAULT}\n size={ButtonSize.SM}\n disabled={actionsDisabled}\n onClick={isHighRisk ? undefined : () => onApprove?.(approvalId, comment || undefined, modifiedToolArgs)}\n >\n {isProcessing ? tComponent(CT, \"processing\") : tComponent(CT, \"approve\")}\n </Button>\n );\n\n return (\n <div className={cn(\"flex flex-col gap-2\", className)} {...props}>\n {/* Comment textarea */}\n <TextareaRoot\n rows={2}\n value={comment}\n onChange={(e) => setComment(e.target.value)}\n placeholder={tComponent(CT, \"commentPlaceholder\")}\n className=\"text-xs\"\n disabled={actionsDisabled}\n />\n\n <div className=\"flex items-center gap-element\">\n {/* Approve — with confirmation dialog for high/critical risk */}\n {isHighRisk ? (\n <AlertDialog>\n <AlertDialogTrigger asChild>\n {approveButton}\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>{tComponent(CT, \"confirmTitle\")}</AlertDialogTitle>\n <AlertDialogDescription>{tComponent(CT, \"confirmDescription\")}</AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>{tComponent(CT, \"confirmCancel\")}</AlertDialogCancel>\n <AlertDialogAction onClick={() => onApprove?.(approvalId, comment || undefined, modifiedToolArgs)}>\n {tComponent(CT, \"confirmProceed\")}\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n ) : (\n approveButton\n )}\n\n {/* Deny */}\n <Button\n type=\"button\"\n variant={ButtonVariants_Variant.OUTLINE}\n size={ButtonSize.SM}\n disabled={actionsDisabled}\n onClick={() => onDeny?.(approvalId, comment || undefined)}\n >\n {tComponent(CT, \"deny\")}\n </Button>\n\n {/* Escalate (optional) */}\n {onEscalate && (\n <Button\n type=\"button\"\n variant={ButtonVariants_Variant.SECONDARY}\n size={ButtonSize.SM}\n disabled={actionsDisabled}\n onClick={() => onEscalate?.(approvalId, comment || undefined)}\n >\n {tComponent(CT, \"escalate\")}\n </Button>\n )}\n </div>\n </div>\n );\n};\n\n//===============================================================\n// AI_ApprovalQueue\n//===============================================================\n\nconst RISK_ORDER: Record<string, number> = { critical: 0, high: 1, medium: 2, low: 3 };\n\nexport type AI_ApprovalQueueItem = {\n approvalId: string;\n executionId: string;\n systemRef: string;\n actionDescription: string;\n /** OPTIONAL for the same reason as on a single request — nothing populates it (#528). */\n riskLevel?: \"low\" | \"medium\" | \"high\" | \"critical\";\n expiresAt?: Date;\n requiredRoles?: string[];\n executionContext?: Record<string, unknown>;\n createdAt?: Date;\n};\n\nexport type AI_ApprovalQueueProps = ComponentProps<\"div\"> & {\n items: AI_ApprovalQueueItem[];\n onApprove?: (approvalId: string, comment?: string) => void;\n onDeny?: (approvalId: string, comment?: string) => void;\n onEscalate?: (approvalId: string, comment?: string) => void;\n processingIds?: Set<string>;\n filter?: string;\n onFilterChange?: (filter: string) => void;\n};\n\nfunction useRelativeTimeFormatter(): (date: Date) => string {\n const { tComponent } = useI18n({ component: CT });\n return React.useCallback((date: Date): string => {\n const seconds = Math.floor((Date.now() - date.getTime()) / 1_000);\n if (seconds < 60) return tComponent(CT, \"timeAgoSeconds\", { count: String(seconds) });\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return tComponent(CT, \"timeAgoMinutes\", { count: String(minutes) });\n const hours = Math.floor(minutes / 60);\n return tComponent(CT, \"timeAgoHours\", { count: String(hours) });\n }, [tComponent]);\n}\n\nexport const AI_ApprovalQueue = ({\n items,\n onApprove,\n onDeny,\n onEscalate,\n processingIds,\n filter,\n onFilterChange,\n className,\n ...props\n}: AI_ApprovalQueueProps): React.JSX.Element | null => {\n const { tComponent, isReady } = useI18n({ component: CT });\n const formatRelativeTime = useRelativeTimeFormatter();\n const [sortByRisk, setSortByRisk] = React.useState(true);\n const [internalFilter, setInternalFilter] = React.useState(\"\");\n\n const activeFilter = filter ?? internalFilter;\n\n const filtered = React.useMemo(() => {\n let result = items;\n if (activeFilter) {\n const q = activeFilter.toLowerCase();\n result = result.filter((i) =>\n i.systemRef.toLowerCase().includes(q) ||\n i.actionDescription.toLowerCase().includes(q) ||\n i.executionId.toLowerCase().includes(q)\n );\n }\n if (sortByRisk) {\n result = [...result].sort((a, b) =>\n (RISK_ORDER[a.riskLevel] ?? 4) - (RISK_ORDER[b.riskLevel] ?? 4)\n );\n }\n return result;\n }, [items, activeFilter, sortByRisk]);\n\n if (!isReady) return null;\n\n return (\n <div className={cn(\"flex flex-col gap-card\", className)} {...props}>\n <div className=\"flex items-center justify-between gap-element\">\n <div className=\"flex items-center gap-element\">\n <h3 className=\"text-sm font-semibold\">\n {tComponent(CT, \"queueTitle\")}\n </h3>\n <Badge variant=\"secondary\">{items.length}</Badge>\n </div>\n\n <Button\n type=\"button\"\n variant={sortByRisk ? ButtonVariants_Variant.SECONDARY : ButtonVariants_Variant.GHOST}\n size={ButtonSize.SM}\n className=\"h-6 text-2xs\"\n onClick={() => setSortByRisk(!sortByRisk)}\n >\n {tComponent(CT, \"queueSortRisk\")}\n </Button>\n </div>\n\n {items.length === 0 ? (\n <p className=\"py-card text-center text-sm text-muted-foreground\">\n {tComponent(CT, \"queueEmpty\")}\n </p>\n ) : (\n <ScrollArea className=\"max-h-96\">\n <div className=\"flex flex-col gap-card-sm\">\n {filtered.map((item) => (\n <div key={item.approvalId} className=\"relative\">\n {item.createdAt && (\n <span className=\"absolute end-2 top-2 text-2xs text-muted-foreground\">\n {formatRelativeTime(item.createdAt)}\n </span>\n )}\n <AI_ApprovalRequest\n approvalId={item.approvalId}\n executionId={item.executionId}\n systemRef={item.systemRef}\n actionDescription={item.actionDescription}\n riskLevel={item.riskLevel}\n expiresAt={item.expiresAt}\n requiredRoles={item.requiredRoles}\n executionContext={item.executionContext}\n createdAt={item.createdAt}\n onApprove={onApprove}\n onDeny={onDeny}\n onEscalate={onEscalate}\n isProcessing={processingIds?.has(item.approvalId)}\n />\n </div>\n ))}\n </div>\n </ScrollArea>\n )}\n </div>\n );\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public-layout-main-container.d.ts","sourceRoot":"","sources":["../../../../src/components/app/public-layout-main-container.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EACL,6CAA6C,EAU9C,MAAM,6BAA6B,CAAC;AAuErC,eAAO,MAAM,wCAAwC,GAAI,wCAItD,6CAA6C,KAAG,KAAK,CAAC,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"public-layout-main-container.d.ts","sourceRoot":"","sources":["../../../../src/components/app/public-layout-main-container.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EACL,6CAA6C,EAU9C,MAAM,6BAA6B,CAAC;AAuErC,eAAO,MAAM,wCAAwC,GAAI,wCAItD,6CAA6C,KAAG,KAAK,CAAC,GAAG,CAAC,OAmE5D,CAAC"}
|
|
@@ -51,7 +51,7 @@ const PublicShellBrandHeader = ({ identity }) => {
|
|
|
51
51
|
export const PublicLayoutPreset_MainContainer_Default = ({ children = null, useCardLayout = false, className = "" }) => {
|
|
52
52
|
const { brandHeader } = usePublicShellLayout(useCardLayout);
|
|
53
53
|
if (useCardLayout) {
|
|
54
|
-
return (_jsx(Surface, { asChild: true, emitPolicyVars: false, variant: SurfaceVariant.SHELL, policyOverride: NON_CANONICAL_SHELL_SURFACE_POLICY_OVERRIDE, children: _jsx("div", { className: "h-screen w-screen overflow-auto", children: _jsx("
|
|
54
|
+
return (_jsx(Surface, { asChild: true, emitPolicyVars: false, variant: SurfaceVariant.SHELL, policyOverride: NON_CANONICAL_SHELL_SURFACE_POLICY_OVERRIDE, children: _jsx("div", { className: "h-screen w-screen overflow-auto", children: _jsx("main", { className: "min-h-full flex items-center justify-center p-container", children: _jsx(Card, { className: cn('w-full max-w-md', className), policyOverride: { a11y: { landmarkRole: 'none' } }, children: _jsxs(CardContent, { className: "p-container-xl", children: [brandHeader && _jsx(PublicShellBrandHeader, { identity: brandHeader }), children] }) }) }) }) }));
|
|
55
55
|
}
|
|
56
56
|
return (_jsx(Surface, { asChild: true, emitPolicyVars: false, variant: SurfaceVariant.SHELL, policyOverride: NON_CANONICAL_SHELL_SURFACE_POLICY_OVERRIDE, children: _jsx("div", { className: cn('h-screen w-screen overflow-auto', className), children: _jsx("main", { className: "min-h-full py-section", children: _jsx("div", { className: "max-w-7xl mx-auto px-card sm:px-container lg:px-container-lg", children: children }) }) }) }));
|
|
57
57
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public-layout-main-container.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"public-layout-main-container.js","sourceRoot":"","sources":["../../../../src/components/app/public-layout-main-container.tsx"],"names":[],"mappings":";AAEA,OAAO,EAEL,IAAI,EACJ,WAAW,EACX,oBAAoB,EACpB,oBAAoB,EACpB,KAAK,EACL,EAAE,EACF,2CAA2C,EAC3C,OAAO,GAER,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAyB,cAAc,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAA;AAE1H;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,sBAAsB,GAAG,CAAC,EAAE,QAAQ,EAA+B,EAA4B,EAAE;IACrG,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IACzG,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,CAAC;IAC9B,MAAM,aAAa,GAAG,SAAS,CAAC,UAAU,CAAC,UAAU,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAElF,IAAI,OAAO;QAAE,OAAO,IAAI,CAAC;IAEzB,OAAO,CACL,eAAK,SAAS,EAAC,oDAAoD,aAChE,OAAO,IAAI,CACV,cAAK,SAAS,EAAC,uCAAuC,YACpD,cACE,GAAG,EAAE,OAAO;oBACZ;;;;uBAIG;oBACH,GAAG,EAAE,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,iBACnB,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,EACjD,OAAO,EAAE,WAAW,EACpB,SAAS,EAAC,gCAAgC,GAC1C,GACE,CACP,EACA,CAAC,eAAe,IAAI,IAAI,KAAK,EAAE,IAAI,CAClC,YAAG,SAAS,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,aAAa,CAAC,KAAK,EAAE,EAAE,IAAI,UAAU,EAAE,6BAA6B,CAAC,YACvG,IAAI,GACH,CACL,IACG,CACP,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,wCAAwC,GAAG,CAAC,EACvD,QAAQ,GAAG,IAAI,EACf,aAAa,GAAG,KAAK,EACrB,SAAS,GAAG,EAAE,EACgC,EAAqB,EAAE;IAErE,MAAM,EAAE,WAAW,EAAE,GAAG,oBAAoB,CAAC,aAAa,CAAC,CAAC;IAE5D,IAAI,aAAa,EAAE,CAAC;QAClB,OAAO,CACL,KAAC,OAAO,IAAC,OAAO,QAAC,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,CAAC,KAAK,EAAE,cAAc,EAAE,2CAA2C,YAChI,cAAK,SAAS,EAAC,iCAAiC,YAgB9C,eAAM,SAAS,EAAC,yDAAyD,YASvE,KAAC,IAAI,IACH,SAAS,EAAE,EAAE,CAAC,iBAAiB,EAAE,SAAS,CAAC,EAC3C,cAAc,EAAE,EAAE,IAAI,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,YAElD,MAAC,WAAW,IAAC,SAAS,EAAC,gBAAgB,aAUpC,WAAW,IAAI,KAAC,sBAAsB,IAAC,QAAQ,EAAE,WAAW,GAAI,EAChE,QAAQ,IACG,GACT,GACF,GACH,GACE,CACX,CAAC;IACJ,CAAC;IAED,OAAO,CACL,KAAC,OAAO,IAAC,OAAO,QAAC,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,CAAC,KAAK,EAAE,cAAc,EAAE,2CAA2C,YAChI,cAAK,SAAS,EAAE,EAAE,CAAC,iCAAiC,EAAE,SAAS,CAAC,YAC9D,eAAM,SAAS,EAAC,uBAAuB,YACrC,cAAK,SAAS,EAAC,8DAA8D,YAC1E,QAAQ,GACL,GACD,GACH,GACE,CACX,CAAC;AACJ,CAAC,CAAC","sourcesContent":["import React from 'react';\n\nimport {\n PublicLayoutPreset_MainContainer_DefaultProps,\n Card,\n CardContent,\n usePublicShellLayout,\n useBrandPresentation,\n useUI,\n cn,\n NON_CANONICAL_SHELL_SURFACE_POLICY_OVERRIDE,\n Surface,\n type BrandIdentity,\n} from '@wildo-ai/saas-frontend-lib';\n\nimport { FrontendComponentType, SurfaceVariant, TypographyVariant, UIBehavior } from \"@wildo-ai/presets-components-models\"\n\n/**\n * The surface's identity, at the top of the public card.\n *\n * Rendered ONLY when the application opted in (`publicShellIdentityMode`) — `usePublicShellLayout`\n * gates that, so reaching this component at all is the permission. What it draws is decided from the\n * DATA, and each branch is a defect that would otherwise ship silently:\n *\n * - a WORDMARK/LOCKUP already contains the name, so the name label is dropped rather than printed\n * twice — the brand resolver returns one for an application that generated no symbol;\n * - a mark whose URL 404s degrades to the name alone instead of a browser broken-image glyph;\n * - an identity with neither mark nor name renders nothing, not an empty gap above the card.\n *\n * The height is RESERVED rather than left to the image. A login card that jumps downward when a logo\n * finishes loading is the \"glitch\" this feature is most likely to introduce, and it is worst exactly\n * where it is most visible: a cold load on a slow link, which is the first impression the page\n * exists to make. The `h-14` box is fixed and `w-auto` lets a wide lockup keep its aspect ratio\n * inside it — sized against the name beneath rather than picked in the abstract, so mark and name\n * read as one unit (hence the tighter `gap-element-sm` between them, and the wider `mb-group` below\n * the pair).\n *\n * ## Why the name is styled from the recipe and is NOT a heading\n *\n * The type comes from the design system's `TYPOGRAPHY.HEADING` recipe rather than from classes\n * chosen here, so an application that restyles its headings restyles this too — the same thing\n * `CardTitle` does, and the reason it is worth a hook call for one line of text. `h1` SIZE — the top\n * of the design system's ordinary ladder — because the identity is what the card is opening with; at\n * `h2` it rendered visibly smaller than the action heading beneath it and read as a caption on the\n * logo rather than as the product's name. Measured on a screenshot, not reasoned about.\n *\n * It renders as a `<p>`, not a heading, because `Auth_Main` already emits the page's `<h1>` inside\n * this same card. A second one would give the document two competing top-level headings; the recipe\n * supplies the LOOK while the outline stays owned by the content.\n */\nconst PublicShellBrandHeader = ({ identity }: { identity: BrandIdentity }): React.JSX.Element | null => {\n const { name, logoUrl, hasMark, markCarriesName, isEmpty, onMarkError } = useBrandPresentation(identity);\n const { getRecipe } = useUI();\n const headingRecipe = getRecipe(UIBehavior.TYPOGRAPHY, TypographyVariant.HEADING);\n\n if (isEmpty) return null;\n\n return (\n <div className=\"flex flex-col items-center gap-element-sm mb-group\">\n {hasMark && (\n <div className=\"flex h-14 items-center justify-center\">\n <img\n src={logoUrl}\n /*\n * A mark that CARRIES the name is the only thing announcing it, so it is the accessible\n * name. A symbol sits beside the name text below and is decorative — announcing it too\n * would read the product name twice to a screen reader.\n */\n alt={markCarriesName ? name : ''}\n aria-hidden={markCarriesName ? undefined : 'true'}\n onError={onMarkError}\n className=\"max-h-14 w-auto object-contain\"\n />\n </div>\n )}\n {!markCarriesName && name !== '' && (\n <p className={cn(headingRecipe.base, headingRecipe.sizes?.h1 ?? 'text-3xl', 'text-center text-foreground')}>\n {name}\n </p>\n )}\n </div>\n );\n};\n\nexport const PublicLayoutPreset_MainContainer_Default = ({\n children = null,\n useCardLayout = false,\n className = \"\"\n}: PublicLayoutPreset_MainContainer_DefaultProps): React.JSX.Element => {\n\n const { brandHeader } = usePublicShellLayout(useCardLayout);\n\n if (useCardLayout) {\n return (\n <Surface asChild emitPolicyVars={false} variant={SurfaceVariant.SHELL} policyOverride={NON_CANONICAL_SHELL_SURFACE_POLICY_OVERRIDE}>\n <div className=\"h-screen w-screen overflow-auto\">\n {/*\n A `<main>`, exactly like the wide branch below — the two branches are the same page at\n different widths, and only one of them had a landmark.\n\n The card branch is every public AUTH surface (sign-in, register, invitation, password\n reset, MFA challenge), so its content sat in no landmark at all: axe reported\n `landmark-one-main` plus three `region` violations on `/login` in the first accessibility\n audit ever run against this product (#533). A screen-reader user had no \"skip to main\"\n target and no way to jump to the form.\n\n It goes HERE, on the centring wrapper, rather than on the card: `Card` deliberately opts\n out of a landmark (`landmarkRole: 'none'` below) because it is presentational chrome, and\n the shell `<div>` above owns scrolling. This element is the one that actually bounds the\n page's content.\n */}\n <main className=\"min-h-full flex items-center justify-center p-container\">\n {/*\n `landmarkRole: 'none'` opts this card out of the BASE variant's\n default `region` landmark. The card here is presentational\n chrome wrapping the public-auth panel — it doesn't represent a\n distinct semantic region on the page. Without the override the\n card would emit `role=\"region\"` without a label (no header,\n no aria-label) and the framework would warn on every render.\n */}\n <Card\n className={cn('w-full max-w-md', className)}\n policyOverride={{ a11y: { landmarkRole: 'none' } }}\n >\n <CardContent className=\"p-container-xl\">\n {/*\n The identity sits INSIDE the card, above the form's own heading — so the box reads\n as one object (\"this is <product>, sign in\") rather than as a card with a caption\n floating over it.\n\n Only the CARD branch carries it. The other branch is the wide static-content layout\n (terms, legal pages), which is reached with the application's chrome around it and\n does not ask \"sign in to what\".\n */}\n {brandHeader && <PublicShellBrandHeader identity={brandHeader} />}\n {children}\n </CardContent>\n </Card>\n </main>\n </div>\n </Surface>\n );\n }\n\n return (\n <Surface asChild emitPolicyVars={false} variant={SurfaceVariant.SHELL} policyOverride={NON_CANONICAL_SHELL_SURFACE_POLICY_OVERRIDE}>\n <div className={cn('h-screen w-screen overflow-auto', className)}>\n <main className=\"min-h-full py-section\">\n <div className=\"max-w-7xl mx-auto px-card sm:px-container lg:px-container-lg\">\n {children}\n </div>\n </main>\n </div>\n </Surface>\n );\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"empty-state.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/empty-state.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAQL,eAAe,EAChB,MAAM,6BAA6B,CAAC;AAQrC;;;;;;;;;GASG;AACH,eAAO,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"empty-state.d.ts","sourceRoot":"","sources":["../../../../src/components/feedback/empty-state.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAQL,eAAe,EAChB,MAAM,6BAA6B,CAAC;AAQrC;;;;;;;;;GASG;AACH,eAAO,MAAM,UAAU,wFAiGtB,CAAC"}
|
|
@@ -18,7 +18,17 @@ import { ButtonSize, SurfaceVariant } from "@wildo-ai/presets-components-models"
|
|
|
18
18
|
export const EmptyState = React.forwardRef(({ title, description, iconRef, primaryActionLabel, onPrimaryAction, showPrimaryAction = true, secondaryAction, variant = 'default', className, ...props }, ref) => {
|
|
19
19
|
const { renderIcon } = useIconRegistry();
|
|
20
20
|
const isCompact = variant === 'compact';
|
|
21
|
-
return (_jsx(Surface, { asChild: true, emitPolicyVars: false, variant: SurfaceVariant.INSET, children: _jsxs("div", { ref: ref, className: cn("flex flex-col items-center justify-center text-center border border-dashed border-border rounded-lg", isCompact ? "py-section px-card gap-element" : "py-section-xl px-card-lg gap-field", className), ...props, children: [iconRef && (_jsx("div", { className: "text-muted-foreground/50", children: renderIcon(iconRef, { size: isCompact ? IconSize.MD : IconSize.LG }) })), _jsxs("div", { className: cn("flex flex-col", isCompact ? "gap-element-sm" : "gap-element"), children: [_jsx("p", { className: cn("font-medium text-muted-foreground", isCompact ? "text-sm" : "text-base"), children: title }), description && (_jsx("p", { className: cn(
|
|
21
|
+
return (_jsx(Surface, { asChild: true, emitPolicyVars: false, variant: SurfaceVariant.INSET, children: _jsxs("div", { ref: ref, className: cn("flex flex-col items-center justify-center text-center border border-dashed border-border rounded-lg", isCompact ? "py-section px-card gap-element" : "py-section-xl px-card-lg gap-field", className), ...props, children: [iconRef && (_jsx("div", { className: "text-muted-foreground/50", children: renderIcon(iconRef, { size: isCompact ? IconSize.MD : IconSize.LG }) })), _jsxs("div", { className: cn("flex flex-col", isCompact ? "gap-element-sm" : "gap-element"), children: [_jsx("p", { className: cn("font-medium text-muted-foreground", isCompact ? "text-sm" : "text-base"), children: title }), description && (_jsx("p", { className: cn(
|
|
22
|
+
/*
|
|
23
|
+
* NOT `text-muted-foreground/70`. The 70% modifier composited to #7a889a on the
|
|
24
|
+
* light theme's #f1f5f9 surface — 3.29:1 against the 4.5:1 that normal text needs
|
|
25
|
+
* (axe, live stack, 2026-09-09, #533). The token at full opacity is the design
|
|
26
|
+
* system's muted colour and already passes; the modifier was muting the muted.
|
|
27
|
+
*
|
|
28
|
+
* Swept across all 8 sites that carried it, not just the ones the audit reached:
|
|
29
|
+
* same token, same modifier, same arithmetic on any light surface.
|
|
30
|
+
*/
|
|
31
|
+
"text-muted-foreground", isCompact ? "text-xs" : "text-sm", "max-w-[32rem] mx-auto"), children: description }))] }), (showPrimaryAction && onPrimaryAction && primaryActionLabel) || secondaryAction ? (_jsxs("div", { className: cn("flex flex-col items-center", isCompact ? "gap-element-sm" : "gap-element"), children: [showPrimaryAction && onPrimaryAction && primaryActionLabel && (_jsx(Button, { variant: ButtonVariants_Variant.OUTLINE, size: ButtonSize.SM, onClick: onPrimaryAction, className: "inline-flex items-center gap-element", children: primaryActionLabel })), secondaryAction && (_jsx("button", { type: "button", onClick: secondaryAction.onClick, className: cn("text-muted-foreground hover:text-foreground underline underline-offset-2 transition-colors", isCompact ? "text-xs" : "text-sm"), children: secondaryAction.label }))] })) : null] }) }));
|
|
22
32
|
});
|
|
23
33
|
EmptyState.displayName = "EmptyState";
|
|
24
34
|
//# sourceMappingURL=empty-state.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"empty-state.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"empty-state.js","sourceRoot":"","sources":["../../../../src/components/feedback/empty-state.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EACL,EAAE,EACF,eAAe,EAEf,QAAQ,EACR,MAAM,EACN,sBAAsB,EACtB,OAAO,GAER,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,UAAU,EAAyB,cAAc,EAAE,MAAM,qCAAqC,CAAA;AAEvG,gEAAgE;AAChE,YAAY;AACZ,gEAAgE;AAEhE;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,CACxC,CACE,EACE,KAAK,EACL,WAAW,EACX,OAAO,EACP,kBAAkB,EAClB,eAAe,EACf,iBAAiB,GAAG,IAAI,EACxB,eAAe,EACf,OAAO,GAAG,SAAS,EACnB,SAAS,EACT,GAAG,KAAK,EACT,EACD,GAAG,EACH,EAAE;IACF,MAAM,EAAE,UAAU,EAAE,GAAG,eAAe,EAAE,CAAC;IAEzC,MAAM,SAAS,GAAG,OAAO,KAAK,SAAS,CAAC;IAExC,OAAO,CACL,KAAC,OAAO,IAAC,OAAO,QAAC,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,CAAC,KAAK,YACnE,eACE,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,EAAE,CACX,qGAAqG,EACrG,SAAS,CAAC,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAC,oCAAoC,EACnF,SAAS,CACV,KACG,KAAK,aAGR,OAAO,IAAI,CACV,cAAK,SAAS,EAAC,0BAA0B,YACtC,UAAU,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,GACjE,CACP,EAGD,eAAK,SAAS,EAAE,EAAE,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,aAAa,CAAC,aAC/E,YAAG,SAAS,EAAE,EAAE,CACd,mCAAmC,EACnC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CACpC,YACE,KAAK,GACJ,EACH,WAAW,IAAI,CACd,YAAG,SAAS,EAAE,EAAE;4BACd;;;;;;;;+BAQG;4BACH,uBAAuB,EACvB,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EACjC,uBAAuB,CACxB,YACE,WAAW,GACV,CACL,IACG,EAGL,CAAC,iBAAiB,IAAI,eAAe,IAAI,kBAAkB,CAAC,IAAI,eAAe,CAAC,CAAC,CAAC,CACjF,eAAK,SAAS,EAAE,EAAE,CAAC,4BAA4B,EAAE,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,aAAa,CAAC,aAC3F,iBAAiB,IAAI,eAAe,IAAI,kBAAkB,IAAI,CAC7D,KAAC,MAAM,IACL,OAAO,EAAE,sBAAsB,CAAC,OAAO,EACvC,IAAI,EAAE,UAAU,CAAC,EAAE,EACnB,OAAO,EAAE,eAAe,EACxB,SAAS,EAAC,sCAAsC,YAE/C,kBAAkB,GACZ,CACV,EACA,eAAe,IAAI,CAClB,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,eAAe,CAAC,OAAO,EAChC,SAAS,EAAE,EAAE,CACX,4FAA4F,EAC5F,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAClC,YAEA,eAAe,CAAC,KAAK,GACf,CACV,IACG,CACP,CAAC,CAAC,CAAC,IAAI,IACJ,GACE,CACX,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,UAAU,CAAC,WAAW,GAAG,YAAY,CAAC","sourcesContent":["import * as React from \"react\"\nimport {\n cn,\n useIconRegistry,\n StandardIconReference,\n IconSize,\n Button,\n ButtonVariants_Variant,\n Surface,\n EmptyStateProps,\n} from '@wildo-ai/saas-frontend-lib';\n\nimport { ButtonSize, FrontendComponentType, SurfaceVariant } from \"@wildo-ai/presets-components-models\"\n\n// ─────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────\n\n/**\n * EmptyState — generic, resource-agnostic empty state component.\n *\n * A pure UI component that displays a placeholder when no content is available.\n * Accepts all display props (title, description, icon, actions) from outside —\n * does NOT know about resources, i18n, or any engine concepts.\n *\n * For resource-aware usage (list/table/search views), see ResourceEmptyState\n * in saas-frontend-lib which wraps this component with i18n and config resolution.\n */\nexport const EmptyState = React.forwardRef<HTMLDivElement, EmptyStateProps>(\n (\n {\n title,\n description,\n iconRef,\n primaryActionLabel,\n onPrimaryAction,\n showPrimaryAction = true,\n secondaryAction,\n variant = 'default',\n className,\n ...props\n },\n ref,\n ) => {\n const { renderIcon } = useIconRegistry();\n\n const isCompact = variant === 'compact';\n\n return (\n <Surface asChild emitPolicyVars={false} variant={SurfaceVariant.INSET}>\n <div\n ref={ref}\n className={cn(\n \"flex flex-col items-center justify-center text-center border border-dashed border-border rounded-lg\",\n isCompact ? \"py-section px-card gap-element\" : \"py-section-xl px-card-lg gap-field\",\n className,\n )}\n {...props}\n >\n {/* Icon */}\n {iconRef && (\n <div className=\"text-muted-foreground/50\">\n {renderIcon(iconRef, { size: isCompact ? IconSize.MD : IconSize.LG })}\n </div>\n )}\n\n {/* Text */}\n <div className={cn(\"flex flex-col\", isCompact ? \"gap-element-sm\" : \"gap-element\")}>\n <p className={cn(\n \"font-medium text-muted-foreground\",\n isCompact ? \"text-sm\" : \"text-base\",\n )}>\n {title}\n </p>\n {description && (\n <p className={cn(\n /*\n * NOT `text-muted-foreground/70`. The 70% modifier composited to #7a889a on the\n * light theme's #f1f5f9 surface — 3.29:1 against the 4.5:1 that normal text needs\n * (axe, live stack, 2026-09-09, #533). The token at full opacity is the design\n * system's muted colour and already passes; the modifier was muting the muted.\n *\n * Swept across all 8 sites that carried it, not just the ones the audit reached:\n * same token, same modifier, same arithmetic on any light surface.\n */\n \"text-muted-foreground\",\n isCompact ? \"text-xs\" : \"text-sm\",\n \"max-w-[32rem] mx-auto\",\n )}>\n {description}\n </p>\n )}\n </div>\n\n {/* Actions */}\n {(showPrimaryAction && onPrimaryAction && primaryActionLabel) || secondaryAction ? (\n <div className={cn(\"flex flex-col items-center\", isCompact ? \"gap-element-sm\" : \"gap-element\")}>\n {showPrimaryAction && onPrimaryAction && primaryActionLabel && (\n <Button\n variant={ButtonVariants_Variant.OUTLINE}\n size={ButtonSize.SM}\n onClick={onPrimaryAction}\n className=\"inline-flex items-center gap-element\"\n >\n {primaryActionLabel}\n </Button>\n )}\n {secondaryAction && (\n <button\n type=\"button\"\n onClick={secondaryAction.onClick}\n className={cn(\n \"text-muted-foreground hover:text-foreground underline underline-offset-2 transition-colors\",\n isCompact ? \"text-xs\" : \"text-sm\",\n )}\n >\n {secondaryAction.label}\n </button>\n )}\n </div>\n ) : null}\n </div>\n </Surface>\n );\n },\n);\n\nEmptyState.displayName = \"EmptyState\";\n"]}
|
|
@@ -41,7 +41,7 @@ const TYPE_INDICATORS = {
|
|
|
41
41
|
*/
|
|
42
42
|
export const NotificationCenter = React.forwardRef(({ notifications, sessionCount, onRemove, onClearAll, labelTitle = 'Notifications', labelNoNotifications = 'Nothing since this page loaded', labelClearAll = 'Clear all', labelDismiss = 'Dismiss', labelTimeJustNow, formatTimeMinutesAgo, formatTimeHoursAgo, formatTimeDaysAgo, className, ...props }, ref) => {
|
|
43
43
|
const timeLabels = { labelTimeJustNow, formatTimeMinutesAgo, formatTimeHoursAgo, formatTimeDaysAgo };
|
|
44
|
-
return (_jsx(Surface, { asChild: true, emitPolicyVars: false, variant: SurfaceVariant.RAISED, children: _jsxs("div", { ref: ref, className: cn("flex flex-col w-full max-w-sm border border-border rounded-lg bg-popover shadow-[var(--shadow-lg)]", className), ...props, children: [_jsxs("div", { className: "flex items-center justify-between px-card py-element border-b border-border", children: [_jsxs("div", { className: "flex items-center gap-element", children: [_jsx("h3", { className: "text-sm font-semibold text-foreground", children: labelTitle }), sessionCount > 0 && (_jsx("span", { className: "inline-flex items-center justify-center h-5 min-w-[20px] px-1.5 text-xs font-medium bg-primary text-primary-foreground rounded-full", children: sessionCount }))] }), _jsx("div", { className: "flex items-center gap-element-sm", children: notifications.length > 0 && onClearAll && (_jsx(Button, { variant: ButtonVariants_Variant.GHOST, size: ButtonSize.XS, className: "text-muted-foreground", onClick: onClearAll, children: labelClearAll })) })] }), _jsx(ScrollArea, { className: "max-h-[24rem]", children: notifications.length === 0 ? (_jsx("div", { className: "flex items-center justify-center py-section text-sm text-muted-foreground", children: labelNoNotifications })) : (_jsx("div", { className: "flex flex-col", children: notifications.map((notification) => (_jsx(Surface, { asChild: true, emitPolicyVars: false, variant: SurfaceVariant.INSET, children: _jsxs("div", { className: cn("flex items-start gap-element px-card py-element-lg border-b border-border/50 last:border-b-0"), children: [_jsx("div", { className: "flex-shrink-0 mt-1.5", children: _jsx("div", { className: cn("w-2 h-2 rounded-full", TYPE_INDICATORS[notification.type] ?? TYPE_INDICATORS.info) }) }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsxs("div", { className: "flex items-start justify-between gap-element-sm", children: [_jsxs("p", { className: "text-sm leading-snug font-medium text-foreground", children: [notification.wasCelebration && _jsx("span", { className: "me-1", children: "\uD83C\uDF89" }), notification.message] }), onRemove && (_jsx("button", { type: "button", className: "flex-shrink-0 text-muted-foreground/50 hover:text-muted-foreground text-xs", onClick: () => onRemove(notification.id), "aria-label": labelDismiss, children: "\u00D7" }))] }), _jsx("p", { className: "text-xs text-muted-foreground
|
|
44
|
+
return (_jsx(Surface, { asChild: true, emitPolicyVars: false, variant: SurfaceVariant.RAISED, children: _jsxs("div", { ref: ref, className: cn("flex flex-col w-full max-w-sm border border-border rounded-lg bg-popover shadow-[var(--shadow-lg)]", className), ...props, children: [_jsxs("div", { className: "flex items-center justify-between px-card py-element border-b border-border", children: [_jsxs("div", { className: "flex items-center gap-element", children: [_jsx("h3", { className: "text-sm font-semibold text-foreground", children: labelTitle }), sessionCount > 0 && (_jsx("span", { className: "inline-flex items-center justify-center h-5 min-w-[20px] px-1.5 text-xs font-medium bg-primary text-primary-foreground rounded-full", children: sessionCount }))] }), _jsx("div", { className: "flex items-center gap-element-sm", children: notifications.length > 0 && onClearAll && (_jsx(Button, { variant: ButtonVariants_Variant.GHOST, size: ButtonSize.XS, className: "text-muted-foreground", onClick: onClearAll, children: labelClearAll })) })] }), _jsx(ScrollArea, { className: "max-h-[24rem]", children: notifications.length === 0 ? (_jsx("div", { className: "flex items-center justify-center py-section text-sm text-muted-foreground", children: labelNoNotifications })) : (_jsx("div", { className: "flex flex-col", children: notifications.map((notification) => (_jsx(Surface, { asChild: true, emitPolicyVars: false, variant: SurfaceVariant.INSET, children: _jsxs("div", { className: cn("flex items-start gap-element px-card py-element-lg border-b border-border/50 last:border-b-0"), children: [_jsx("div", { className: "flex-shrink-0 mt-1.5", children: _jsx("div", { className: cn("w-2 h-2 rounded-full", TYPE_INDICATORS[notification.type] ?? TYPE_INDICATORS.info) }) }), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsxs("div", { className: "flex items-start justify-between gap-element-sm", children: [_jsxs("p", { className: "text-sm leading-snug font-medium text-foreground", children: [notification.wasCelebration && _jsx("span", { className: "me-1", children: "\uD83C\uDF89" }), notification.message] }), onRemove && (_jsx("button", { type: "button", className: "flex-shrink-0 text-muted-foreground/50 hover:text-muted-foreground text-xs", onClick: () => onRemove(notification.id), "aria-label": labelDismiss, children: "\u00D7" }))] }), _jsx("p", { className: "text-xs text-muted-foreground mt-0.5", children: getRelativeTime(notification.timestamp, timeLabels) }), notification.nextStep && (_jsxs(Button, { variant: ButtonVariants_Variant.LINK, size: ButtonSize.SM, className: "h-auto p-0 text-xs mt-1", onClick: () => notification.nextStep.onClick(), children: [notification.nextStep.label, " \u2192"] }))] })] }) }, notification.id))) })) })] }) }));
|
|
45
45
|
});
|
|
46
46
|
NotificationCenter.displayName = "NotificationCenter";
|
|
47
47
|
//# sourceMappingURL=notification-center.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notification-center.js","sourceRoot":"","sources":["../../../../src/components/feedback/notification-center.tsx"],"names":[],"mappings":"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","sourcesContent":["import * as React from \"react\"\nimport {\n NotificationCenterNotification,\n NotificationCenterProps,\n cn,\n Button,\n ButtonVariants_Variant,\n ScrollArea,\n Surface,\n} from '@wildo-ai/saas-frontend-lib';\n\nimport { ButtonSize, SurfaceVariant } from \"@wildo-ai/presets-components-models\"\n\n// ─────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────\n\nfunction getRelativeTime(\n timestamp: number,\n labels: Pick<NotificationCenterProps, 'labelTimeJustNow' | 'formatTimeMinutesAgo' | 'formatTimeHoursAgo' | 'formatTimeDaysAgo'>\n): string {\n const diff = Date.now() - timestamp;\n const minutes = Math.floor(diff / 60000);\n const hours = Math.floor(diff / 3600000);\n const days = Math.floor(diff / 86400000);\n\n if (minutes < 1) return labels.labelTimeJustNow ?? 'Just now';\n if (minutes < 60) return labels.formatTimeMinutesAgo?.(minutes) ?? `${minutes}m ago`;\n if (hours < 24) return labels.formatTimeHoursAgo?.(hours) ?? `${hours}h ago`;\n return labels.formatTimeDaysAgo?.(days) ?? `${days}d ago`;\n}\n\nconst TYPE_INDICATORS: Record<string, string> = {\n success: 'bg-success',\n error: 'bg-destructive',\n warning: 'bg-warning',\n info: 'bg-info',\n};\n\n// ─────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────\n\n/**\n * NotificationCenter — generic, resource-agnostic SESSION-FEED component.\n *\n * A pure UI component that displays what has arrived since the page loaded, with relative timestamps\n * and per-item actions. Read/unread state was removed on 2026-09-08 (#412): the store behind it has\n * no persistence, so \"read\" was a property that died with the page and marking something read meant\n * nothing. Does NOT know about resources, i18n, or\n * any engine concepts — all labels are passed as props.\n *\n * For engine integration, see the notification-center wrapper in saas-frontend-lib\n * which wires NotificationContext and resolves i18n labels.\n */\nexport const NotificationCenter = React.forwardRef<HTMLDivElement, NotificationCenterProps>(\n (\n {\n notifications,\n sessionCount,\n onRemove,\n onClearAll,\n labelTitle = 'Notifications',\n labelNoNotifications = 'Nothing since this page loaded',\n labelClearAll = 'Clear all',\n labelDismiss = 'Dismiss',\n labelTimeJustNow,\n formatTimeMinutesAgo,\n formatTimeHoursAgo,\n formatTimeDaysAgo,\n className,\n ...props\n },\n ref,\n ) => {\n const timeLabels = { labelTimeJustNow, formatTimeMinutesAgo, formatTimeHoursAgo, formatTimeDaysAgo };\n\n return (\n <Surface asChild emitPolicyVars={false} variant={SurfaceVariant.RAISED}>\n <div\n ref={ref}\n className={cn(\n \"flex flex-col w-full max-w-sm border border-border rounded-lg bg-popover shadow-[var(--shadow-lg)]\",\n className,\n )}\n {...props}\n >\n {/* Header */}\n <div className=\"flex items-center justify-between px-card py-element border-b border-border\">\n <div className=\"flex items-center gap-element\">\n <h3 className=\"text-sm font-semibold text-foreground\">{labelTitle}</h3>\n {/* Counts what arrived this session — there is no unread state to count. */}\n {sessionCount > 0 && (\n <span className=\"inline-flex items-center justify-center h-5 min-w-[20px] px-1.5 text-xs font-medium bg-primary text-primary-foreground rounded-full\">\n {sessionCount}\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-element-sm\">\n {notifications.length > 0 && onClearAll && (\n <Button variant={ButtonVariants_Variant.GHOST} size={ButtonSize.XS} className=\"text-muted-foreground\" onClick={onClearAll}>\n {labelClearAll}\n </Button>\n )}\n </div>\n </div>\n\n {/* Notification List */}\n <ScrollArea className=\"max-h-[24rem]\">\n {notifications.length === 0 ? (\n <div className=\"flex items-center justify-center py-section text-sm text-muted-foreground\">\n {labelNoNotifications}\n </div>\n ) : (\n <div className=\"flex flex-col\">\n {notifications.map((notification) => (\n <Surface key={notification.id} asChild emitPolicyVars={false} variant={SurfaceVariant.INSET}>\n {/*\n * Not clickable, and not styled as if it were. The row's only click action was\n * marking it read; with that gone, `cursor-pointer` and a hover highlight would\n * advertise an interaction that does nothing. Dismiss and the next-step link are\n * the row's real actions.\n */}\n <div\n className={cn(\n \"flex items-start gap-element px-card py-element-lg border-b border-border/50 last:border-b-0\",\n )}\n >\n {/* Type indicator dot */}\n <div className=\"flex-shrink-0 mt-1.5\">\n <div className={cn(\n \"w-2 h-2 rounded-full\",\n TYPE_INDICATORS[notification.type] ?? TYPE_INDICATORS.info,\n )} />\n </div>\n\n {/* Content */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-start justify-between gap-element-sm\">\n <p className=\"text-sm leading-snug font-medium text-foreground\">\n {notification.wasCelebration && <span className=\"me-1\">🎉</span>}\n {notification.message}\n </p>\n {onRemove && (\n <button\n type=\"button\"\n className=\"flex-shrink-0 text-muted-foreground/50 hover:text-muted-foreground text-xs\"\n onClick={() => onRemove(notification.id)}\n aria-label={labelDismiss}\n >\n ×\n </button>\n )}\n </div>\n <p className=\"text-xs text-muted-foreground/70 mt-0.5\">\n {getRelativeTime(notification.timestamp, timeLabels)}\n </p>\n {notification.nextStep && (\n <Button\n variant={ButtonVariants_Variant.LINK}\n size={ButtonSize.SM}\n className=\"h-auto p-0 text-xs mt-1\"\n onClick={() => notification.nextStep!.onClick()}\n >\n {notification.nextStep.label} →\n </Button>\n )}\n </div>\n </div>\n </Surface>\n ))}\n </div>\n )}\n </ScrollArea>\n </div>\n </Surface>\n );\n },\n);\n\nNotificationCenter.displayName = \"NotificationCenter\";\n"]}
|
|
1
|
+
{"version":3,"file":"notification-center.js","sourceRoot":"","sources":["../../../../src/components/feedback/notification-center.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAGL,EAAE,EACF,MAAM,EACN,sBAAsB,EACtB,UAAU,EACV,OAAO,GACR,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAA;AAEhF,gEAAgE;AAChE,UAAU;AACV,gEAAgE;AAEhE,SAAS,eAAe,CACtB,SAAiB,EACjB,MAA+H;IAE/H,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IACpC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC;IACzC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAC;IAEzC,IAAI,OAAO,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC,gBAAgB,IAAI,UAAU,CAAC;IAC9D,IAAI,OAAO,GAAG,EAAE;QAAE,OAAO,MAAM,CAAC,oBAAoB,EAAE,CAAC,OAAO,CAAC,IAAI,GAAG,OAAO,OAAO,CAAC;IACrF,IAAI,KAAK,GAAG,EAAE;QAAE,OAAO,MAAM,CAAC,kBAAkB,EAAE,CAAC,KAAK,CAAC,IAAI,GAAG,KAAK,OAAO,CAAC;IAC7E,OAAO,MAAM,CAAC,iBAAiB,EAAE,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,OAAO,CAAC;AAC5D,CAAC;AAED,MAAM,eAAe,GAA2B;IAC9C,OAAO,EAAE,YAAY;IACrB,KAAK,EAAE,gBAAgB;IACvB,OAAO,EAAE,YAAY;IACrB,IAAI,EAAE,SAAS;CAChB,CAAC;AAEF,gEAAgE;AAChE,YAAY;AACZ,gEAAgE;AAEhE;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,CAAC,UAAU,CAChD,CACE,EACE,aAAa,EACb,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,UAAU,GAAG,eAAe,EAC5B,oBAAoB,GAAG,gCAAgC,EACvD,aAAa,GAAG,WAAW,EAC3B,YAAY,GAAG,SAAS,EACxB,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,SAAS,EACT,GAAG,KAAK,EACT,EACD,GAAG,EACH,EAAE;IACF,MAAM,UAAU,GAAG,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,CAAC;IAErG,OAAO,CACL,KAAC,OAAO,IAAC,OAAO,QAAC,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,CAAC,MAAM,YACpE,eACE,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,EAAE,CACX,oGAAoG,EACpG,SAAS,CACV,KACG,KAAK,aAGT,eAAK,SAAS,EAAC,6EAA6E,aAC1F,eAAK,SAAS,EAAC,+BAA+B,aAC5C,aAAI,SAAS,EAAC,uCAAuC,YAAE,UAAU,GAAM,EAEtE,YAAY,GAAG,CAAC,IAAI,CACnB,eAAM,SAAS,EAAC,qIAAqI,YAClJ,YAAY,GACR,CACR,IACG,EACN,cAAK,SAAS,EAAC,kCAAkC,YAC9C,aAAa,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,IAAI,CACzC,KAAC,MAAM,IAAC,OAAO,EAAE,sBAAsB,CAAC,KAAK,EAAE,IAAI,EAAE,UAAU,CAAC,EAAE,EAAE,SAAS,EAAC,uBAAuB,EAAC,OAAO,EAAE,UAAU,YACtH,aAAa,GACP,CACV,GACG,IACF,EAGN,KAAC,UAAU,IAAC,SAAS,EAAC,eAAe,YAClC,aAAa,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAC5B,cAAK,SAAS,EAAC,2EAA2E,YACvF,oBAAoB,GACjB,CACP,CAAC,CAAC,CAAC,CACF,cAAK,SAAS,EAAC,eAAe,YAC3B,aAAa,CAAC,GAAG,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,CACnC,KAAC,OAAO,IAAuB,OAAO,QAAC,cAAc,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,CAAC,KAAK,YAOzF,eACE,SAAS,EAAE,EAAE,CACX,8FAA8F,CAC/F,aAGD,cAAK,SAAS,EAAC,sBAAsB,YACnC,cAAK,SAAS,EAAE,EAAE,CAChB,sBAAsB,EACtB,eAAe,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,eAAe,CAAC,IAAI,CAC3D,GAAI,GACD,EAGN,eAAK,SAAS,EAAC,gBAAgB,aAC7B,eAAK,SAAS,EAAC,iDAAiD,aAC9D,aAAG,SAAS,EAAC,kDAAkD,aAC5D,YAAY,CAAC,cAAc,IAAI,eAAM,SAAS,EAAC,MAAM,6BAAU,EAC/D,YAAY,CAAC,OAAO,IACnB,EACH,QAAQ,IAAI,CACX,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,4EAA4E,EACtF,OAAO,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,gBAC5B,YAAY,uBAGjB,CACV,IACG,EACN,YAAG,SAAS,EAAC,sCAAsC,YAChD,eAAe,CAAC,YAAY,CAAC,SAAS,EAAE,UAAU,CAAC,GAClD,EACH,YAAY,CAAC,QAAQ,IAAI,CACxB,MAAC,MAAM,IACL,OAAO,EAAE,sBAAsB,CAAC,IAAI,EACpC,IAAI,EAAE,UAAU,CAAC,EAAE,EACnB,SAAS,EAAC,yBAAyB,EACnC,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,QAAS,CAAC,OAAO,EAAE,aAE9C,YAAY,CAAC,QAAQ,CAAC,KAAK,eACrB,CACV,IACG,IACF,IApDM,YAAY,CAAC,EAAE,CAqDnB,CACX,CAAC,GACE,CACP,GACU,IACT,GACE,CACX,CAAC;AACJ,CAAC,CACF,CAAC;AAEF,kBAAkB,CAAC,WAAW,GAAG,oBAAoB,CAAC","sourcesContent":["import * as React from \"react\"\nimport {\n NotificationCenterNotification,\n NotificationCenterProps,\n cn,\n Button,\n ButtonVariants_Variant,\n ScrollArea,\n Surface,\n} from '@wildo-ai/saas-frontend-lib';\n\nimport { ButtonSize, SurfaceVariant } from \"@wildo-ai/presets-components-models\"\n\n// ─────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────\n\nfunction getRelativeTime(\n timestamp: number,\n labels: Pick<NotificationCenterProps, 'labelTimeJustNow' | 'formatTimeMinutesAgo' | 'formatTimeHoursAgo' | 'formatTimeDaysAgo'>\n): string {\n const diff = Date.now() - timestamp;\n const minutes = Math.floor(diff / 60000);\n const hours = Math.floor(diff / 3600000);\n const days = Math.floor(diff / 86400000);\n\n if (minutes < 1) return labels.labelTimeJustNow ?? 'Just now';\n if (minutes < 60) return labels.formatTimeMinutesAgo?.(minutes) ?? `${minutes}m ago`;\n if (hours < 24) return labels.formatTimeHoursAgo?.(hours) ?? `${hours}h ago`;\n return labels.formatTimeDaysAgo?.(days) ?? `${days}d ago`;\n}\n\nconst TYPE_INDICATORS: Record<string, string> = {\n success: 'bg-success',\n error: 'bg-destructive',\n warning: 'bg-warning',\n info: 'bg-info',\n};\n\n// ─────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────\n\n/**\n * NotificationCenter — generic, resource-agnostic SESSION-FEED component.\n *\n * A pure UI component that displays what has arrived since the page loaded, with relative timestamps\n * and per-item actions. Read/unread state was removed on 2026-09-08 (#412): the store behind it has\n * no persistence, so \"read\" was a property that died with the page and marking something read meant\n * nothing. Does NOT know about resources, i18n, or\n * any engine concepts — all labels are passed as props.\n *\n * For engine integration, see the notification-center wrapper in saas-frontend-lib\n * which wires NotificationContext and resolves i18n labels.\n */\nexport const NotificationCenter = React.forwardRef<HTMLDivElement, NotificationCenterProps>(\n (\n {\n notifications,\n sessionCount,\n onRemove,\n onClearAll,\n labelTitle = 'Notifications',\n labelNoNotifications = 'Nothing since this page loaded',\n labelClearAll = 'Clear all',\n labelDismiss = 'Dismiss',\n labelTimeJustNow,\n formatTimeMinutesAgo,\n formatTimeHoursAgo,\n formatTimeDaysAgo,\n className,\n ...props\n },\n ref,\n ) => {\n const timeLabels = { labelTimeJustNow, formatTimeMinutesAgo, formatTimeHoursAgo, formatTimeDaysAgo };\n\n return (\n <Surface asChild emitPolicyVars={false} variant={SurfaceVariant.RAISED}>\n <div\n ref={ref}\n className={cn(\n \"flex flex-col w-full max-w-sm border border-border rounded-lg bg-popover shadow-[var(--shadow-lg)]\",\n className,\n )}\n {...props}\n >\n {/* Header */}\n <div className=\"flex items-center justify-between px-card py-element border-b border-border\">\n <div className=\"flex items-center gap-element\">\n <h3 className=\"text-sm font-semibold text-foreground\">{labelTitle}</h3>\n {/* Counts what arrived this session — there is no unread state to count. */}\n {sessionCount > 0 && (\n <span className=\"inline-flex items-center justify-center h-5 min-w-[20px] px-1.5 text-xs font-medium bg-primary text-primary-foreground rounded-full\">\n {sessionCount}\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-element-sm\">\n {notifications.length > 0 && onClearAll && (\n <Button variant={ButtonVariants_Variant.GHOST} size={ButtonSize.XS} className=\"text-muted-foreground\" onClick={onClearAll}>\n {labelClearAll}\n </Button>\n )}\n </div>\n </div>\n\n {/* Notification List */}\n <ScrollArea className=\"max-h-[24rem]\">\n {notifications.length === 0 ? (\n <div className=\"flex items-center justify-center py-section text-sm text-muted-foreground\">\n {labelNoNotifications}\n </div>\n ) : (\n <div className=\"flex flex-col\">\n {notifications.map((notification) => (\n <Surface key={notification.id} asChild emitPolicyVars={false} variant={SurfaceVariant.INSET}>\n {/*\n * Not clickable, and not styled as if it were. The row's only click action was\n * marking it read; with that gone, `cursor-pointer` and a hover highlight would\n * advertise an interaction that does nothing. Dismiss and the next-step link are\n * the row's real actions.\n */}\n <div\n className={cn(\n \"flex items-start gap-element px-card py-element-lg border-b border-border/50 last:border-b-0\",\n )}\n >\n {/* Type indicator dot */}\n <div className=\"flex-shrink-0 mt-1.5\">\n <div className={cn(\n \"w-2 h-2 rounded-full\",\n TYPE_INDICATORS[notification.type] ?? TYPE_INDICATORS.info,\n )} />\n </div>\n\n {/* Content */}\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-start justify-between gap-element-sm\">\n <p className=\"text-sm leading-snug font-medium text-foreground\">\n {notification.wasCelebration && <span className=\"me-1\">🎉</span>}\n {notification.message}\n </p>\n {onRemove && (\n <button\n type=\"button\"\n className=\"flex-shrink-0 text-muted-foreground/50 hover:text-muted-foreground text-xs\"\n onClick={() => onRemove(notification.id)}\n aria-label={labelDismiss}\n >\n ×\n </button>\n )}\n </div>\n <p className=\"text-xs text-muted-foreground mt-0.5\">\n {getRelativeTime(notification.timestamp, timeLabels)}\n </p>\n {notification.nextStep && (\n <Button\n variant={ButtonVariants_Variant.LINK}\n size={ButtonSize.SM}\n className=\"h-auto p-0 text-xs mt-1\"\n onClick={() => notification.nextStep!.onClick()}\n >\n {notification.nextStep.label} →\n </Button>\n )}\n </div>\n </div>\n </Surface>\n ))}\n </div>\n )}\n </ScrollArea>\n </div>\n </Surface>\n );\n },\n);\n\nNotificationCenter.displayName = \"NotificationCenter\";\n"]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google Drive file picker — the component the `google-drive` provider contributes for
|
|
3
|
+
* `FRONTEND_FILE_PICKER`.
|
|
4
|
+
*
|
|
5
|
+
* ## Why it declares REMOTE_REFERENCE
|
|
6
|
+
*
|
|
7
|
+
* Drive's Picker hands back file METADATA — an id, a name, a mime type — never
|
|
8
|
+
* the bytes. Fetching the bytes is a separate authenticated call to the Drive
|
|
9
|
+
* API, and in a Wildo application the credential that call needs belongs to the
|
|
10
|
+
* backend. So a selection here is an opaque handle the application's executor
|
|
11
|
+
* door resolves, which is exactly `REMOTE_REFERENCE`.
|
|
12
|
+
*
|
|
13
|
+
* Its sibling `onedrive-picker.tsx` declares the OTHER arm,
|
|
14
|
+
* and the contrast is why issue #383 was answered per-vendor rather than
|
|
15
|
+
* globally: two real pickers for one capability genuinely return different
|
|
16
|
+
* things, and a framework insisting on one contract would have had to exclude
|
|
17
|
+
* one of them.
|
|
18
|
+
*
|
|
19
|
+
* ## Why it lives in presets-components, behind a lazy boundary
|
|
20
|
+
*
|
|
21
|
+
* The engine's provider MODULES live in `@wildo-ai/external-connectors-public`,
|
|
22
|
+
* which ships into three browser bundles behind a one-entry allow-list and
|
|
23
|
+
* deliberately has no renderer. A component cannot live there, and that
|
|
24
|
+
* package cannot name a loader that reaches this one either — it would close a
|
|
25
|
+
* package cycle. So the module DECLARES the picker (its delivery, its keys) and
|
|
26
|
+
* this library REGISTERS the loader beside its presets (`register-provider-components.ts`),
|
|
27
|
+
* keyed by capability and provider ref. `google-drive-picker.lazy.tsx` is the
|
|
28
|
+
* only door onto this file, and `check:lazy-boundaries` keeps it that way.
|
|
29
|
+
*
|
|
30
|
+
* This component has no vendor dependency: the Picker arrives as a `<script>`
|
|
31
|
+
* global the provider module declares. A per-vendor package was built for it
|
|
32
|
+
* first and retired for exactly that reason (#394).
|
|
33
|
+
*
|
|
34
|
+
* ## Not proven in a browser
|
|
35
|
+
*
|
|
36
|
+
* Nothing here has been driven against a real Drive account: the Picker
|
|
37
|
+
* authorizes as the SIGNED-IN USER, so it needs a user-consented OAuth token,
|
|
38
|
+
* which is the account-connection surface (#333) and does not exist yet. Without
|
|
39
|
+
* one this picker reports through `onError` and opens nothing — deliberately,
|
|
40
|
+
* rather than reading a token from `publicConfig`, which is served to every
|
|
41
|
+
* browser. Tracked with the rest of the frontend provider surface in #359.
|
|
42
|
+
*/
|
|
43
|
+
import { type ProviderFilePickerProps } from '@wildo-ai/saas-models/public-runtime';
|
|
44
|
+
/**
|
|
45
|
+
* Opens the Drive picker as soon as it mounts.
|
|
46
|
+
*
|
|
47
|
+
* Mounting IS opening: the framework host mounts a picker only once a user has
|
|
48
|
+
* asked for one, so an extra button inside the component would be a second click
|
|
49
|
+
* for the same intent.
|
|
50
|
+
*/
|
|
51
|
+
export declare function GoogleDrivePicker(props: ProviderFilePickerProps): null;
|
|
52
|
+
//# sourceMappingURL=google-drive-picker.d.ts.map
|