@mvriu5/payload-ai 0.5.9 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +62 -6
  2. package/dist/ai/{proposals.d.ts → proposalSigning.d.ts} +1 -1
  3. package/dist/ai/{proposals.js → proposalSigning.js} +6 -11
  4. package/dist/ai/providerOptions.d.ts +17 -1
  5. package/dist/ai/providerOptions.js +35 -7
  6. package/dist/ai/providerRuntime.d.ts +2 -2
  7. package/dist/ai/providerRuntime.js +50 -16
  8. package/dist/ai/sensitiveData.js +2 -6
  9. package/dist/components/AIInput.d.ts +2 -1
  10. package/dist/components/AIInput.js +363 -135
  11. package/dist/components/AIInput.module.css +15 -1
  12. package/dist/components/APIKeyField.d.ts +3 -0
  13. package/dist/components/APIKeyField.js +63 -0
  14. package/dist/components/ActionToast.d.ts +30 -0
  15. package/dist/components/ActionToast.js +263 -0
  16. package/dist/components/AuditLogList.d.ts +32 -0
  17. package/dist/components/AuditLogList.js +104 -0
  18. package/dist/components/{RecentChangesList.module.css → AuditLogList.module.css} +18 -1
  19. package/dist/components/DiffDialog.d.ts +10 -3
  20. package/dist/components/DiffDialog.js +284 -97
  21. package/dist/components/DiffDialog.module.css +86 -2
  22. package/dist/components/Icons.d.ts +5 -0
  23. package/dist/components/Icons.js +436 -214
  24. package/dist/components/MentionPopover.d.ts +19 -0
  25. package/dist/components/MentionPopover.js +95 -0
  26. package/dist/components/{CollectionMentionPopover.module.css → MentionPopover.module.css} +0 -2
  27. package/dist/components/hooks/useAISettings.d.ts +6 -4
  28. package/dist/components/hooks/useAISettings.js +18 -3
  29. package/dist/components/hooks/useDocumentMentionSuggestions.d.ts +3 -3
  30. package/dist/components/hooks/useDocumentMentionSuggestions.js +2 -2
  31. package/dist/exports/client.d.ts +4 -2
  32. package/dist/exports/client.js +4 -2
  33. package/dist/handlers/applyActionHandler.d.ts +8 -0
  34. package/dist/handlers/applyActionHandler.js +563 -0
  35. package/dist/handlers/auditLogHandler.d.ts +6 -0
  36. package/dist/{endpoints/aiRecentChangesEndpointHandler.js → handlers/auditLogHandler.js} +12 -8
  37. package/dist/handlers/chatHandler.d.ts +42 -0
  38. package/dist/handlers/chatHandler.js +721 -0
  39. package/dist/handlers/mentionSuggestionHandler.d.ts +7 -0
  40. package/dist/handlers/mentionSuggestionHandler.js +97 -0
  41. package/dist/handlers/proposalDiffHandler.d.ts +7 -0
  42. package/dist/handlers/proposalDiffHandler.js +208 -0
  43. package/dist/index.d.ts +6 -6
  44. package/dist/index.js +52 -20
  45. package/dist/payload/collectionPermissions.d.ts +14 -13
  46. package/dist/payload/collectionPermissions.js +3 -2
  47. package/dist/payload/normalizeData.d.ts +8 -0
  48. package/dist/payload/normalizeData.js +25 -3
  49. package/dist/payload/schemaContext.d.ts +43 -16
  50. package/dist/payload/schemaContext.js +139 -18
  51. package/dist/payload/shared.d.ts +33 -0
  52. package/dist/payload/shared.js +114 -0
  53. package/package.json +45 -9
  54. package/dist/components/AIActionProposalList.d.ts +0 -26
  55. package/dist/components/AIActionProposalList.js +0 -162
  56. package/dist/components/AIApiKeyField.d.ts +0 -2
  57. package/dist/components/AIApiKeyField.js +0 -47
  58. package/dist/components/CollectionMentionPopover.d.ts +0 -16
  59. package/dist/components/CollectionMentionPopover.js +0 -77
  60. package/dist/components/RecentChangesList.d.ts +0 -18
  61. package/dist/components/RecentChangesList.js +0 -66
  62. package/dist/components/hooks/utils.d.ts +0 -1
  63. package/dist/components/hooks/utils.js +0 -3
  64. package/dist/endpoints/aiApplyActionEndpointHandler.d.ts +0 -8
  65. package/dist/endpoints/aiApplyActionEndpointHandler.js +0 -365
  66. package/dist/endpoints/aiChatEndpointHandler.d.ts +0 -35
  67. package/dist/endpoints/aiChatEndpointHandler.js +0 -382
  68. package/dist/endpoints/aiMentionSuggestionsEndpointHandler.d.ts +0 -7
  69. package/dist/endpoints/aiMentionSuggestionsEndpointHandler.js +0 -63
  70. package/dist/endpoints/aiProposalDiffEndpointHandler.d.ts +0 -7
  71. package/dist/endpoints/aiProposalDiffEndpointHandler.js +0 -138
  72. package/dist/endpoints/aiRecentChangesEndpointHandler.d.ts +0 -6
  73. /package/dist/components/{AIActionProposalList.module.css → ActionToast.module.css} +0 -0
@@ -1,5 +1,5 @@
1
1
  .chatLayout {
2
- align-items: stretch;
2
+ align-items: start;
3
3
  display: grid;
4
4
  gap: 16px;
5
5
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
@@ -152,7 +152,16 @@
152
152
  }
153
153
 
154
154
  .prefix {
155
+ align-items: center;
155
156
  color: var(--theme-elevation-500);
157
+ display: inline-flex;
158
+ gap: 3px;
159
+ }
160
+
161
+ .badgeIcon {
162
+ flex: 0 0 auto;
163
+ height: 12px;
164
+ width: 12px;
156
165
  }
157
166
 
158
167
  .name {
@@ -179,6 +188,11 @@
179
188
  border-color: color-mix(in srgb, #7a5c9e 28%, var(--theme-elevation-150));
180
189
  }
181
190
 
191
+ .locale {
192
+ background: color-mix(in srgb, #2f5da8 12%, var(--theme-bg));
193
+ border-color: color-mix(in srgb, #2f5da8 28%, var(--theme-elevation-150));
194
+ }
195
+
182
196
  .chatButton {
183
197
  align-items: center;
184
198
  background: var(--theme-text);
@@ -0,0 +1,3 @@
1
+ import type { TextFieldClientComponent } from "payload";
2
+ declare const APIKeyField: TextFieldClientComponent;
3
+ export default APIKeyField;
@@ -0,0 +1,63 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useField } from "@payloadcms/ui";
4
+ const getFieldClassName = ({ className, isReadOnly, showError })=>[
5
+ "field-type",
6
+ "password",
7
+ className,
8
+ showError ? "error" : null,
9
+ isReadOnly ? "read-only" : null
10
+ ].filter(Boolean).join(" ");
11
+ const APIKeyField = ({ field, inputRef, path, readOnly })=>{
12
+ const { disabled, errorMessage, setValue, showError, value } = useField({
13
+ path
14
+ });
15
+ const fieldID = `field-${path.replace(/\./g, "__")}`;
16
+ const isReadOnly = readOnly || disabled || field.admin?.disabled;
17
+ const handleChange = (event)=>setValue(event.target.value);
18
+ return /*#__PURE__*/ _jsxs("div", {
19
+ className: getFieldClassName({
20
+ className: field.admin?.className,
21
+ isReadOnly,
22
+ showError
23
+ }),
24
+ children: [
25
+ /*#__PURE__*/ _jsxs("label", {
26
+ className: "field-label",
27
+ htmlFor: fieldID,
28
+ children: [
29
+ field?.label?.toString(),
30
+ field.required ? /*#__PURE__*/ _jsx("span", {
31
+ className: "required",
32
+ children: "*"
33
+ }) : null
34
+ ]
35
+ }),
36
+ /*#__PURE__*/ _jsxs("div", {
37
+ className: "field-type__wrap",
38
+ children: [
39
+ showError && errorMessage ? /*#__PURE__*/ _jsx("div", {
40
+ className: "field-error",
41
+ children: errorMessage
42
+ }) : null,
43
+ /*#__PURE__*/ _jsx("input", {
44
+ autoComplete: "new-password",
45
+ disabled: isReadOnly,
46
+ id: fieldID,
47
+ name: path,
48
+ onChange: handleChange,
49
+ placeholder: field.admin?.placeholder?.toString(),
50
+ ref: inputRef,
51
+ type: "password",
52
+ value: value || ""
53
+ }),
54
+ /*#__PURE__*/ _jsx("div", {
55
+ className: "field-description",
56
+ children: field.admin?.description?.toString()
57
+ })
58
+ ]
59
+ })
60
+ ]
61
+ });
62
+ };
63
+ export default APIKeyField;
@@ -0,0 +1,30 @@
1
+ export type ActionProposal = {
2
+ _aiSignature?: {
3
+ expiresAt: string;
4
+ value: string;
5
+ };
6
+ action: "create" | "delete" | "update" | "updateGlobal";
7
+ collection?: string;
8
+ id?: string;
9
+ label: string;
10
+ slug?: string;
11
+ };
12
+ type ActionToastProps = {
13
+ apiRoute: string;
14
+ appliedProposalIndexes: number[];
15
+ description?: string;
16
+ error?: string;
17
+ getViewURL?: (proposal: ActionProposal) => string | null;
18
+ isApplying: boolean;
19
+ onDismiss?: () => void;
20
+ onDismissError?: () => void;
21
+ onApply: (proposal: ActionProposal, index: number) => void;
22
+ proposals: ActionProposal[];
23
+ tokenUsage?: {
24
+ inputTokens?: number;
25
+ outputTokens?: number;
26
+ totalTokens?: number;
27
+ } | null;
28
+ };
29
+ export declare const ActionToast: ({ apiRoute, appliedProposalIndexes, description, error, getViewURL, isApplying, onDismiss, onDismissError, onApply, proposals, tokenUsage, }: ActionToastProps) => import("react").JSX.Element | null;
30
+ export {};
@@ -0,0 +1,263 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import styles from "./ActionToast.module.css";
3
+ import { redactSensitiveData } from "../ai/sensitiveData.js";
4
+ import { formatAdminURL } from "payload/shared";
5
+ import { useState } from "react";
6
+ import { DiffDialog } from "./DiffDialog.js";
7
+ import { Apply, FileDiff, Reject } from "./Icons.js";
8
+ const maxDescriptionLength = 220;
9
+ const getDescriptionPreview = (description)=>{
10
+ if (description.length <= maxDescriptionLength) return description;
11
+ return `${description.slice(0, maxDescriptionLength).trim()}...`;
12
+ };
13
+ const getSafeProposalDetails = (proposal)=>{
14
+ const redactedProposal = redactSensitiveData(proposal);
15
+ if (redactedProposal._aiSignature) {
16
+ redactedProposal._aiSignature = {
17
+ expiresAt: redactedProposal._aiSignature.expiresAt,
18
+ value: "[redacted]"
19
+ };
20
+ }
21
+ return redactedProposal;
22
+ };
23
+ export const ActionToast = ({ apiRoute, appliedProposalIndexes, description, error, getViewURL, isApplying, onDismiss, onDismissError, onApply, proposals, tokenUsage })=>{
24
+ const [activeDiff, setActiveDiff] = useState(null);
25
+ const [diffError, setDiffError] = useState("");
26
+ const [loadingDiffIndex, setLoadingDiffIndex] = useState(null);
27
+ if (proposals.length === 0 && !error && !description) return null;
28
+ const descriptionPreview = description ? getDescriptionPreview(description) : "";
29
+ const isDescriptionTruncated = Boolean(description) && descriptionPreview !== description;
30
+ const openDiff = async (proposal, index)=>{
31
+ setDiffError("");
32
+ setLoadingDiffIndex(index);
33
+ try {
34
+ const res = await fetch(formatAdminURL({
35
+ apiRoute,
36
+ path: "/ai-proposal-diff"
37
+ }), {
38
+ body: JSON.stringify({
39
+ proposal
40
+ }),
41
+ headers: {
42
+ "Content-Type": "application/json"
43
+ },
44
+ method: "POST"
45
+ });
46
+ const result = await res.json().catch(()=>null);
47
+ if (!res.ok || !result) {
48
+ throw new Error(result?.error || "Could not load proposal diff.");
49
+ }
50
+ setActiveDiff({
51
+ change: null,
52
+ diff: {
53
+ after: result.after,
54
+ before: result.before
55
+ },
56
+ proposal
57
+ });
58
+ } catch (err) {
59
+ setDiffError(err instanceof Error ? err.message : "Could not load proposal diff.");
60
+ } finally{
61
+ setLoadingDiffIndex(null);
62
+ }
63
+ };
64
+ return /*#__PURE__*/ _jsxs("div", {
65
+ className: styles.list,
66
+ children: [
67
+ error && /*#__PURE__*/ _jsxs("div", {
68
+ className: `${styles.item} ${styles.errorItem}`,
69
+ children: [
70
+ /*#__PURE__*/ _jsxs("div", {
71
+ children: [
72
+ /*#__PURE__*/ _jsx("div", {
73
+ className: styles.label,
74
+ children: "AI request failed"
75
+ }),
76
+ /*#__PURE__*/ _jsx("div", {
77
+ className: styles.description,
78
+ children: error
79
+ })
80
+ ]
81
+ }),
82
+ onDismissError && /*#__PURE__*/ _jsx("button", {
83
+ className: styles.button,
84
+ onClick: onDismissError,
85
+ type: "button",
86
+ children: "Dismiss"
87
+ })
88
+ ]
89
+ }),
90
+ !error && proposals.length === 0 && description && /*#__PURE__*/ _jsx("div", {
91
+ className: styles.item,
92
+ children: /*#__PURE__*/ _jsxs("div", {
93
+ children: [
94
+ /*#__PURE__*/ _jsx("div", {
95
+ className: styles.label,
96
+ children: "AI response"
97
+ }),
98
+ /*#__PURE__*/ _jsx("div", {
99
+ className: styles.description,
100
+ children: descriptionPreview
101
+ }),
102
+ isDescriptionTruncated && /*#__PURE__*/ _jsxs("details", {
103
+ className: styles.details,
104
+ children: [
105
+ /*#__PURE__*/ _jsx("summary", {
106
+ className: styles.summary,
107
+ children: "Full response"
108
+ }),
109
+ /*#__PURE__*/ _jsx("pre", {
110
+ className: styles.proposalDetails,
111
+ children: description
112
+ })
113
+ ]
114
+ })
115
+ ]
116
+ })
117
+ }),
118
+ proposals.map((proposal, index)=>{
119
+ const isApplied = appliedProposalIndexes.includes(index);
120
+ const viewURL = getViewURL?.(proposal);
121
+ return /*#__PURE__*/ _jsxs("div", {
122
+ className: styles.item,
123
+ children: [
124
+ /*#__PURE__*/ _jsxs("div", {
125
+ className: styles.content,
126
+ children: [
127
+ /*#__PURE__*/ _jsx("div", {
128
+ className: styles.label,
129
+ children: proposal.label
130
+ }),
131
+ /*#__PURE__*/ _jsxs("div", {
132
+ className: styles.meta,
133
+ children: [
134
+ proposal.action,
135
+ " in ",
136
+ proposal.collection || proposal.slug,
137
+ proposal.id ? ` #${proposal.id}` : ""
138
+ ]
139
+ }),
140
+ description && /*#__PURE__*/ _jsx("div", {
141
+ className: styles.description,
142
+ children: descriptionPreview
143
+ }),
144
+ description && isDescriptionTruncated && /*#__PURE__*/ _jsxs("details", {
145
+ className: styles.details,
146
+ children: [
147
+ /*#__PURE__*/ _jsx("summary", {
148
+ className: styles.summary,
149
+ children: "Full response"
150
+ }),
151
+ /*#__PURE__*/ _jsx("pre", {
152
+ className: styles.proposalDetails,
153
+ children: description
154
+ })
155
+ ]
156
+ }),
157
+ /*#__PURE__*/ _jsxs("details", {
158
+ className: styles.details,
159
+ children: [
160
+ /*#__PURE__*/ _jsx("summary", {
161
+ className: styles.summary,
162
+ children: "Details"
163
+ }),
164
+ /*#__PURE__*/ _jsx("pre", {
165
+ className: styles.proposalDetails,
166
+ children: JSON.stringify(getSafeProposalDetails(proposal), null, 2)
167
+ })
168
+ ]
169
+ })
170
+ ]
171
+ }),
172
+ /*#__PURE__*/ _jsxs("div", {
173
+ className: styles.footer,
174
+ children: [
175
+ /*#__PURE__*/ _jsxs("div", {
176
+ className: styles.viewAction,
177
+ children: [
178
+ /*#__PURE__*/ _jsxs("button", {
179
+ "aria-label": `Review proposal: ${proposal.label}`,
180
+ className: styles.secondaryButton,
181
+ disabled: loadingDiffIndex === index,
182
+ onClick: ()=>void openDiff(proposal, index),
183
+ type: "button",
184
+ children: [
185
+ /*#__PURE__*/ _jsx(FileDiff, {
186
+ height: 16,
187
+ width: 16
188
+ }),
189
+ loadingDiffIndex === index ? "Loading" : "Review"
190
+ ]
191
+ }),
192
+ viewURL && /*#__PURE__*/ _jsx("a", {
193
+ className: styles.ghostButton,
194
+ href: viewURL,
195
+ rel: "noreferrer noopener",
196
+ target: "_blank",
197
+ children: "Go to source"
198
+ })
199
+ ]
200
+ }),
201
+ /*#__PURE__*/ _jsxs("div", {
202
+ className: styles.actions,
203
+ children: [
204
+ onDismiss && /*#__PURE__*/ _jsx("button", {
205
+ "aria-label": "Dismiss proposals",
206
+ className: styles.secondaryButton,
207
+ onClick: onDismiss,
208
+ type: "button",
209
+ children: /*#__PURE__*/ _jsx(Reject, {
210
+ height: 16,
211
+ width: 16
212
+ })
213
+ }),
214
+ /*#__PURE__*/ _jsx("button", {
215
+ "aria-label": `Apply proposal: ${proposal.label}`,
216
+ className: styles.button,
217
+ disabled: isApplying || isApplied,
218
+ onClick: ()=>onApply(proposal, index),
219
+ type: "button",
220
+ children: /*#__PURE__*/ _jsx(Apply, {
221
+ height: 16,
222
+ width: 16
223
+ })
224
+ })
225
+ ]
226
+ })
227
+ ]
228
+ })
229
+ ]
230
+ }, `${proposal.action}-${index}`);
231
+ }),
232
+ diffError && /*#__PURE__*/ _jsxs("div", {
233
+ className: `${styles.item} ${styles.errorItem}`,
234
+ children: [
235
+ /*#__PURE__*/ _jsxs("div", {
236
+ children: [
237
+ /*#__PURE__*/ _jsx("div", {
238
+ className: styles.label,
239
+ children: "Diff review failed"
240
+ }),
241
+ /*#__PURE__*/ _jsx("div", {
242
+ className: styles.description,
243
+ children: diffError
244
+ })
245
+ ]
246
+ }),
247
+ /*#__PURE__*/ _jsx("button", {
248
+ className: styles.button,
249
+ onClick: ()=>setDiffError(""),
250
+ type: "button",
251
+ children: "Dismiss"
252
+ })
253
+ ]
254
+ }),
255
+ activeDiff && /*#__PURE__*/ _jsx(DiffDialog, {
256
+ diff: activeDiff.diff,
257
+ onClose: ()=>setActiveDiff(null),
258
+ proposal: activeDiff.proposal,
259
+ tokenUsage: tokenUsage || undefined
260
+ })
261
+ ]
262
+ });
263
+ };
@@ -0,0 +1,32 @@
1
+ import type { ActionProposal } from "./ActionToast.js";
2
+ import { type ProposalDiff } from "./DiffDialog.js";
3
+ export type AppliedChange = {
4
+ action?: ActionProposal["action"] | null;
5
+ additions: number;
6
+ after?: unknown;
7
+ before?: unknown;
8
+ collection?: string | null;
9
+ createdAt?: string | null;
10
+ documentID?: string | null;
11
+ inputTokens?: number | null;
12
+ outputTokens?: number | null;
13
+ removals: number;
14
+ slug?: string | null;
15
+ targetType?: string | null;
16
+ totalTokens?: number | null;
17
+ title: string;
18
+ userID?: string | null;
19
+ userLabel?: string | null;
20
+ url?: string | null;
21
+ };
22
+ type AuditLogListProps = {
23
+ allChangesURL?: string;
24
+ changes: AppliedChange[];
25
+ };
26
+ export type ActiveDiff = {
27
+ change: AppliedChange | null;
28
+ diff: ProposalDiff;
29
+ proposal: ActionProposal;
30
+ };
31
+ export declare const RecentChangesList: ({ allChangesURL, changes }: AuditLogListProps) => import("react").JSX.Element;
32
+ export {};
@@ -0,0 +1,104 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { ExternalLinkIcon } from "@payloadcms/ui";
4
+ import { DiffDialog } from "./DiffDialog.js";
5
+ import styles from "./AuditLogList.module.css";
6
+ const getChangeProposal = (change)=>({
7
+ action: change.action || "update",
8
+ collection: change.collection || undefined,
9
+ id: change.documentID || undefined,
10
+ label: change.title,
11
+ slug: change.slug || undefined
12
+ });
13
+ export const RecentChangesList = ({ allChangesURL, changes })=>{
14
+ const [activeDiff, setActiveDiff] = useState(null);
15
+ return /*#__PURE__*/ _jsxs("aside", {
16
+ className: styles.recentChanges,
17
+ children: [
18
+ /*#__PURE__*/ _jsxs("div", {
19
+ className: styles.header,
20
+ children: [
21
+ /*#__PURE__*/ _jsx("h3", {
22
+ className: styles.title,
23
+ children: "Recent changes"
24
+ }),
25
+ allChangesURL && /*#__PURE__*/ _jsx("a", {
26
+ className: styles.headerGhostButton,
27
+ href: allChangesURL,
28
+ children: "View all"
29
+ })
30
+ ]
31
+ }),
32
+ /*#__PURE__*/ _jsx("div", {
33
+ className: styles.list,
34
+ children: changes.length === 0 ? /*#__PURE__*/ _jsx("div", {
35
+ className: styles.empty,
36
+ children: "No changes yet."
37
+ }) : changes.slice(0, 10).map((change, index)=>/*#__PURE__*/ _jsxs("div", {
38
+ className: styles.item,
39
+ children: [
40
+ /*#__PURE__*/ _jsxs("div", {
41
+ className: styles.titleRow,
42
+ children: [
43
+ /*#__PURE__*/ _jsx("div", {
44
+ className: styles.itemTitle,
45
+ children: change.title
46
+ }),
47
+ change.url && /*#__PURE__*/ _jsx("a", {
48
+ className: styles.ghostButton,
49
+ href: change.url,
50
+ rel: "noreferrer noopener",
51
+ target: "_blank",
52
+ children: /*#__PURE__*/ _jsx(ExternalLinkIcon, {})
53
+ })
54
+ ]
55
+ }),
56
+ /*#__PURE__*/ _jsxs("div", {
57
+ className: styles.stats,
58
+ children: [
59
+ /*#__PURE__*/ _jsxs("code", {
60
+ className: styles.additions,
61
+ children: [
62
+ "+",
63
+ change.additions
64
+ ]
65
+ }),
66
+ /*#__PURE__*/ _jsxs("code", {
67
+ className: styles.removals,
68
+ children: [
69
+ "-",
70
+ change.removals
71
+ ]
72
+ })
73
+ ]
74
+ }),
75
+ /*#__PURE__*/ _jsx("button", {
76
+ className: styles.button,
77
+ onClick: ()=>{
78
+ if (change.before === undefined || change.after === undefined) {
79
+ return;
80
+ }
81
+ setActiveDiff({
82
+ change,
83
+ diff: {
84
+ after: change.after,
85
+ before: change.before
86
+ },
87
+ proposal: getChangeProposal(change)
88
+ });
89
+ },
90
+ type: "button",
91
+ children: "Review"
92
+ })
93
+ ]
94
+ }, `${change.title}-${index}`))
95
+ }),
96
+ activeDiff && activeDiff.change && /*#__PURE__*/ _jsx(DiffDialog, {
97
+ change: activeDiff.change,
98
+ diff: activeDiff.diff,
99
+ onClose: ()=>setActiveDiff(null),
100
+ proposal: activeDiff.proposal
101
+ })
102
+ ]
103
+ });
104
+ };
@@ -8,10 +8,27 @@
8
8
  }
9
9
 
10
10
  .header {
11
+ align-items: center;
12
+ display: flex;
11
13
  flex: 0 0 auto;
14
+ gap: 10px;
15
+ justify-content: space-between;
12
16
  margin-bottom: 10px;
13
17
  }
14
18
 
19
+ .headerGhostButton {
20
+ color: var(--theme-elevation-500);
21
+ flex: 0 0 auto;
22
+ font-size: 12px;
23
+ line-height: 24px;
24
+ min-height: 24px;
25
+ text-decoration: none;
26
+ }
27
+
28
+ .headerGhostButton:hover {
29
+ text-decoration: underline;
30
+ }
31
+
15
32
  .title {
16
33
  font-size: 14px;
17
34
  line-height: 1.3;
@@ -42,7 +59,7 @@
42
59
  display: grid;
43
60
  gap: 8px;
44
61
  grid-template-columns: minmax(0, 1fr) auto auto;
45
- padding: 10px;
62
+ padding: 4px 4px 4px 8px;
46
63
  }
47
64
 
48
65
  .titleRow {
@@ -1,12 +1,19 @@
1
- import type { AIActionProposal } from "./AIActionProposalList.js";
1
+ import type { ActionProposal } from "./ActionToast.js";
2
+ import type { AppliedChange } from "./AuditLogList.js";
2
3
  export type ProposalDiff = {
3
4
  after: unknown;
4
5
  before: unknown;
5
6
  };
6
7
  type DiffDialogProps = {
8
+ change?: AppliedChange;
7
9
  diff: ProposalDiff;
8
10
  onClose: () => void;
9
- proposal: AIActionProposal;
11
+ proposal: ActionProposal;
12
+ tokenUsage?: {
13
+ inputTokens?: number;
14
+ outputTokens?: number;
15
+ totalTokens?: number;
16
+ };
10
17
  };
11
- export declare const DiffDialog: ({ diff, onClose, proposal }: DiffDialogProps) => import("react").JSX.Element;
18
+ export declare const DiffDialog: ({ change, diff, onClose, proposal, tokenUsage }: DiffDialogProps) => import("react").JSX.Element;
12
19
  export {};