@mvriu5/payload-ai 0.5.8 → 0.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/AIActionProposalList.d.ts +2 -1
- package/dist/components/AIActionProposalList.js +74 -6
- package/dist/components/AIActionProposalList.module.css +49 -5
- package/dist/components/AIInput.js +125 -10
- package/dist/components/AIInput.module.css +27 -6
- package/dist/components/DiffDialog.d.ts +12 -0
- package/dist/components/DiffDialog.js +310 -0
- package/dist/components/DiffDialog.module.css +249 -0
- package/dist/components/Icons.d.ts +4 -0
- package/dist/components/Icons.js +87 -0
- package/dist/components/RecentChangesList.d.ts +18 -0
- package/dist/components/RecentChangesList.js +66 -0
- package/dist/components/RecentChangesList.module.css +135 -0
- package/dist/endpoints/aiApplyActionEndpointHandler.d.ts +1 -0
- package/dist/endpoints/aiApplyActionEndpointHandler.js +200 -4
- package/dist/endpoints/aiChatEndpointHandler.js +85 -24
- package/dist/endpoints/aiProposalDiffEndpointHandler.d.ts +7 -0
- package/dist/endpoints/aiProposalDiffEndpointHandler.js +138 -0
- package/dist/endpoints/aiRecentChangesEndpointHandler.d.ts +6 -0
- package/dist/endpoints/aiRecentChangesEndpointHandler.js +35 -0
- package/dist/index.js +111 -0
- package/dist/payload/schemaContext.d.ts +44 -1
- package/dist/payload/schemaContext.js +100 -12
- package/package.json +1 -1
|
@@ -11,6 +11,7 @@ export type AIActionProposal = {
|
|
|
11
11
|
slug?: string;
|
|
12
12
|
};
|
|
13
13
|
type AIActionProposalListProps = {
|
|
14
|
+
apiRoute: string;
|
|
14
15
|
appliedProposalIndexes: number[];
|
|
15
16
|
description?: string;
|
|
16
17
|
error?: string;
|
|
@@ -21,5 +22,5 @@ type AIActionProposalListProps = {
|
|
|
21
22
|
onApply: (proposal: AIActionProposal, index: number) => void;
|
|
22
23
|
proposals: AIActionProposal[];
|
|
23
24
|
};
|
|
24
|
-
export declare const AIActionProposalList: ({ appliedProposalIndexes, description, error, getViewURL, isApplying, onDismiss, onDismissError, onApply, proposals
|
|
25
|
+
export declare const AIActionProposalList: ({ apiRoute, appliedProposalIndexes, description, error, getViewURL, isApplying, onDismiss, onDismissError, onApply, proposals }: AIActionProposalListProps) => import("react").JSX.Element | null;
|
|
25
26
|
export {};
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import styles from "./AIActionProposalList.module.css";
|
|
2
2
|
import { redactSensitiveData } from "../ai/sensitiveData.js";
|
|
3
|
+
import { formatAdminURL } from "payload/shared";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { DiffDialog } from "./DiffDialog.js";
|
|
6
|
+
import { Apply, FileDiff, Reject } from "./Icons.js";
|
|
3
7
|
const maxDescriptionLength = 220;
|
|
4
8
|
const getDescriptionPreview = (description)=>{
|
|
5
9
|
if (description.length <= maxDescriptionLength) return description;
|
|
@@ -15,10 +19,46 @@ const getSafeProposalDetails = (proposal)=>{
|
|
|
15
19
|
}
|
|
16
20
|
return redactedProposal;
|
|
17
21
|
};
|
|
18
|
-
export const AIActionProposalList = ({ appliedProposalIndexes, description, error, getViewURL, isApplying, onDismiss, onDismissError, onApply, proposals })=>{
|
|
22
|
+
export const AIActionProposalList = ({ apiRoute, appliedProposalIndexes, description, error, getViewURL, isApplying, onDismiss, onDismissError, onApply, proposals })=>{
|
|
23
|
+
const [activeDiff, setActiveDiff] = useState(null);
|
|
24
|
+
const [diffError, setDiffError] = useState("");
|
|
25
|
+
const [loadingDiffIndex, setLoadingDiffIndex] = useState(null);
|
|
19
26
|
if (proposals.length === 0 && !error && !description) return null;
|
|
20
27
|
const descriptionPreview = description ? getDescriptionPreview(description) : "";
|
|
21
28
|
const isDescriptionTruncated = Boolean(description) && descriptionPreview !== description;
|
|
29
|
+
const openDiff = async (proposal, index)=>{
|
|
30
|
+
setDiffError("");
|
|
31
|
+
setLoadingDiffIndex(index);
|
|
32
|
+
try {
|
|
33
|
+
const res = await fetch(formatAdminURL({
|
|
34
|
+
apiRoute,
|
|
35
|
+
path: "/ai-proposal-diff"
|
|
36
|
+
}), {
|
|
37
|
+
body: JSON.stringify({
|
|
38
|
+
proposal
|
|
39
|
+
}),
|
|
40
|
+
headers: {
|
|
41
|
+
"Content-Type": "application/json"
|
|
42
|
+
},
|
|
43
|
+
method: "POST"
|
|
44
|
+
});
|
|
45
|
+
const result = await res.json().catch(()=>null);
|
|
46
|
+
if (!res.ok || !result) {
|
|
47
|
+
throw new Error(result?.error || "Could not load proposal diff.");
|
|
48
|
+
}
|
|
49
|
+
setActiveDiff({
|
|
50
|
+
diff: {
|
|
51
|
+
after: result.after,
|
|
52
|
+
before: result.before
|
|
53
|
+
},
|
|
54
|
+
proposal
|
|
55
|
+
});
|
|
56
|
+
} catch (err) {
|
|
57
|
+
setDiffError(err instanceof Error ? err.message : "Could not load proposal diff.");
|
|
58
|
+
} finally{
|
|
59
|
+
setLoadingDiffIndex(null);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
22
62
|
return /*#__PURE__*/ React.createElement("div", {
|
|
23
63
|
className: styles.list
|
|
24
64
|
}, error && /*#__PURE__*/ React.createElement("div", {
|
|
@@ -73,22 +113,50 @@ export const AIActionProposalList = ({ appliedProposalIndexes, description, erro
|
|
|
73
113
|
className: styles.footer
|
|
74
114
|
}, /*#__PURE__*/ React.createElement("div", {
|
|
75
115
|
className: styles.viewAction
|
|
76
|
-
},
|
|
116
|
+
}, /*#__PURE__*/ React.createElement("button", {
|
|
77
117
|
className: styles.secondaryButton,
|
|
118
|
+
disabled: loadingDiffIndex === index,
|
|
119
|
+
onClick: ()=>void openDiff(proposal, index),
|
|
120
|
+
type: "button"
|
|
121
|
+
}, /*#__PURE__*/ React.createElement(FileDiff, {
|
|
122
|
+
height: 16,
|
|
123
|
+
width: 16
|
|
124
|
+
}), loadingDiffIndex === index ? "Loading" : "Review"), viewURL && /*#__PURE__*/ React.createElement("a", {
|
|
125
|
+
className: styles.ghostButton,
|
|
78
126
|
href: viewURL,
|
|
79
127
|
rel: "noreferrer noopener",
|
|
80
128
|
target: "_blank"
|
|
81
|
-
}, "
|
|
129
|
+
}, "Go to source")), /*#__PURE__*/ React.createElement("div", {
|
|
82
130
|
className: styles.actions
|
|
83
131
|
}, onDismiss && /*#__PURE__*/ React.createElement("button", {
|
|
84
132
|
className: styles.secondaryButton,
|
|
85
133
|
onClick: onDismiss,
|
|
86
134
|
type: "button"
|
|
87
|
-
},
|
|
135
|
+
}, /*#__PURE__*/ React.createElement(Reject, {
|
|
136
|
+
height: 16,
|
|
137
|
+
width: 16
|
|
138
|
+
})), /*#__PURE__*/ React.createElement("button", {
|
|
88
139
|
className: styles.button,
|
|
89
140
|
disabled: isApplying || isApplied,
|
|
90
141
|
onClick: ()=>onApply(proposal, index),
|
|
91
142
|
type: "button"
|
|
92
|
-
},
|
|
93
|
-
|
|
143
|
+
}, /*#__PURE__*/ React.createElement(Apply, {
|
|
144
|
+
height: 16,
|
|
145
|
+
width: 16
|
|
146
|
+
})))));
|
|
147
|
+
}), diffError ? /*#__PURE__*/ React.createElement("div", {
|
|
148
|
+
className: `${styles.item} ${styles.errorItem}`
|
|
149
|
+
}, /*#__PURE__*/ React.createElement("div", null, /*#__PURE__*/ React.createElement("div", {
|
|
150
|
+
className: styles.label
|
|
151
|
+
}, "Diff review failed"), /*#__PURE__*/ React.createElement("div", {
|
|
152
|
+
className: styles.description
|
|
153
|
+
}, diffError)), /*#__PURE__*/ React.createElement("button", {
|
|
154
|
+
className: styles.button,
|
|
155
|
+
onClick: ()=>setDiffError(""),
|
|
156
|
+
type: "button"
|
|
157
|
+
}, "Dismiss")) : null, activeDiff ? /*#__PURE__*/ React.createElement(DiffDialog, {
|
|
158
|
+
diff: activeDiff.diff,
|
|
159
|
+
onClose: ()=>setActiveDiff(null),
|
|
160
|
+
proposal: activeDiff.proposal
|
|
161
|
+
}) : null);
|
|
94
162
|
};
|
|
@@ -94,6 +94,7 @@
|
|
|
94
94
|
.viewAction {
|
|
95
95
|
align-items: center;
|
|
96
96
|
display: flex;
|
|
97
|
+
gap: 8px;
|
|
97
98
|
min-width: 0;
|
|
98
99
|
}
|
|
99
100
|
|
|
@@ -106,37 +107,74 @@
|
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
.button {
|
|
110
|
+
align-items: center;
|
|
109
111
|
background: var(--theme-text);
|
|
110
112
|
border: 0;
|
|
111
113
|
border-radius: 4px;
|
|
112
114
|
color: var(--theme-bg);
|
|
113
115
|
cursor: pointer;
|
|
116
|
+
display: inline-flex;
|
|
114
117
|
flex: 0 0 auto;
|
|
115
118
|
font: inherit;
|
|
116
|
-
|
|
119
|
+
gap: 6px;
|
|
120
|
+
justify-content: center;
|
|
121
|
+
line-height: 24px;
|
|
122
|
+
min-height: 24px;
|
|
117
123
|
padding: 0 14px;
|
|
118
124
|
}
|
|
119
125
|
|
|
120
126
|
.secondaryButton {
|
|
127
|
+
align-items: center;
|
|
121
128
|
background: transparent;
|
|
122
129
|
border: 1px solid var(--theme-elevation-150);
|
|
123
130
|
border-radius: 4px;
|
|
124
131
|
color: var(--theme-text);
|
|
125
132
|
cursor: pointer;
|
|
133
|
+
display: inline-flex;
|
|
126
134
|
flex: 0 0 auto;
|
|
127
135
|
font: inherit;
|
|
128
|
-
|
|
129
|
-
|
|
136
|
+
gap: 6px;
|
|
137
|
+
justify-content: center;
|
|
138
|
+
line-height: 24px;
|
|
139
|
+
min-height: 24px;
|
|
130
140
|
padding: 0 14px;
|
|
131
141
|
text-decoration: none;
|
|
132
142
|
}
|
|
133
143
|
|
|
144
|
+
.secondaryButton svg {
|
|
145
|
+
color: var(--theme-elevation-500);
|
|
146
|
+
flex: 0 0 auto;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.button svg {
|
|
150
|
+
flex: 0 0 auto;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.ghostButton {
|
|
154
|
+
background: transparent;
|
|
155
|
+
border: 0;
|
|
156
|
+
border-radius: 4px;
|
|
157
|
+
color: var(--theme-elevation-600);
|
|
158
|
+
cursor: pointer;
|
|
159
|
+
flex: 0 0 auto;
|
|
160
|
+
font: inherit;
|
|
161
|
+
line-height: 24px;
|
|
162
|
+
min-height: 24px;
|
|
163
|
+
padding: 0 10px;
|
|
164
|
+
text-decoration: none;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.ghostButton:hover {
|
|
168
|
+
text-decoration: underline;
|
|
169
|
+
}
|
|
170
|
+
|
|
134
171
|
.button:disabled {
|
|
135
172
|
cursor: not-allowed;
|
|
136
173
|
opacity: 0.45;
|
|
137
174
|
}
|
|
138
175
|
|
|
139
|
-
.secondaryButton:disabled
|
|
176
|
+
.secondaryButton:disabled,
|
|
177
|
+
.ghostButton:disabled {
|
|
140
178
|
cursor: not-allowed;
|
|
141
179
|
opacity: 0.45;
|
|
142
180
|
}
|
|
@@ -163,13 +201,19 @@
|
|
|
163
201
|
flex-direction: column;
|
|
164
202
|
}
|
|
165
203
|
|
|
204
|
+
.viewAction {
|
|
205
|
+
align-self: stretch;
|
|
206
|
+
flex-direction: column;
|
|
207
|
+
}
|
|
208
|
+
|
|
166
209
|
.footer {
|
|
167
210
|
align-items: stretch;
|
|
168
211
|
flex-direction: column;
|
|
169
212
|
}
|
|
170
213
|
|
|
171
214
|
.button,
|
|
172
|
-
.secondaryButton
|
|
215
|
+
.secondaryButton,
|
|
216
|
+
.ghostButton {
|
|
173
217
|
width: 100%;
|
|
174
218
|
}
|
|
175
219
|
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useConfig } from "@payloadcms/ui";
|
|
3
3
|
import { formatAdminURL } from "payload/shared";
|
|
4
|
-
import { useMemo, useRef, useState } from "react";
|
|
4
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
5
5
|
import { getResolvedAIModelConfig } from "../ai/providerOptions.js";
|
|
6
6
|
import { getSerializableLabel, isInternalCollection } from "../payload/shared.js";
|
|
7
7
|
import { AIActionProposalList } from "./AIActionProposalList.js";
|
|
8
8
|
import styles from "./AIInput.module.css";
|
|
9
9
|
import { CollectionMentionPopover } from "./CollectionMentionPopover.js";
|
|
10
|
-
import { ClaudeIcon, GoogleGeminiIcon, MistralAiIcon, OpenaiIcon } from "./Icons.js";
|
|
10
|
+
import { ClaudeIcon, GoogleGeminiIcon, MistralAiIcon, OpenaiIcon, Send } from "./Icons.js";
|
|
11
|
+
import { RecentChangesList } from "./RecentChangesList.js";
|
|
11
12
|
import { useAISettings } from "./hooks/useAISettings.js";
|
|
12
13
|
import { useDocumentMentionSuggestions } from "./hooks/useDocumentMentionSuggestions.js";
|
|
13
14
|
const collectBlockOptions = ({ fields, parent })=>{
|
|
@@ -54,6 +55,34 @@ const getProviderIcon = (provider)=>{
|
|
|
54
55
|
return null;
|
|
55
56
|
}
|
|
56
57
|
};
|
|
58
|
+
const parseSSEEvent = (chunk)=>{
|
|
59
|
+
const lines = chunk.split("\n");
|
|
60
|
+
let eventName = "";
|
|
61
|
+
const dataLines = [];
|
|
62
|
+
for (const line of lines){
|
|
63
|
+
if (line.startsWith("event:")) {
|
|
64
|
+
eventName = line.slice(6).trim();
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (line.startsWith("data:")) {
|
|
68
|
+
dataLines.push(line.slice(5).trim());
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (!eventName) return null;
|
|
72
|
+
try {
|
|
73
|
+
const data = JSON.parse(dataLines.join("\n"));
|
|
74
|
+
if (eventName !== "text" && eventName !== "proposals" && eventName !== "error" && eventName !== "done") {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
data,
|
|
79
|
+
event: eventName
|
|
80
|
+
};
|
|
81
|
+
} catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
const sanitizeResponseText = (value)=>value.replace(/\*\*/g, "");
|
|
57
86
|
export const AIInput = ()=>{
|
|
58
87
|
const { config } = useConfig();
|
|
59
88
|
const editorRef = useRef(null);
|
|
@@ -75,6 +104,7 @@ export const AIInput = ()=>{
|
|
|
75
104
|
const [response, setResponse] = useState("");
|
|
76
105
|
const [error, setError] = useState("");
|
|
77
106
|
const [proposals, setProposals] = useState([]);
|
|
107
|
+
const [appliedChanges, setAppliedChanges] = useState([]);
|
|
78
108
|
const [isLoading, setIsLoading] = useState(false);
|
|
79
109
|
const [isApplying, setIsApplying] = useState(false);
|
|
80
110
|
const enabledCollectionSlugs = config.admin?.custom?.payloadAiPlugin?.collectionSlugs;
|
|
@@ -82,6 +112,39 @@ export const AIInput = ()=>{
|
|
|
82
112
|
enabledCollectionSlugs
|
|
83
113
|
]);
|
|
84
114
|
const isCollectionMentionEnabled = (slug)=>!enabledCollectionSlugSet || enabledCollectionSlugSet.has(slug);
|
|
115
|
+
const recentChangesEndpoint = useMemo(()=>formatAdminURL({
|
|
116
|
+
apiRoute: config.routes.api,
|
|
117
|
+
path: "/ai-recent-changes"
|
|
118
|
+
}), [
|
|
119
|
+
config.routes.api
|
|
120
|
+
]);
|
|
121
|
+
const loadRecentChanges = useCallback(async ()=>{
|
|
122
|
+
const res = await fetch(recentChangesEndpoint);
|
|
123
|
+
const result = await res.json().catch(()=>null);
|
|
124
|
+
if (res.ok && result?.changes) {
|
|
125
|
+
setAppliedChanges(result.changes);
|
|
126
|
+
}
|
|
127
|
+
}, [
|
|
128
|
+
recentChangesEndpoint
|
|
129
|
+
]);
|
|
130
|
+
useEffect(()=>{
|
|
131
|
+
void loadRecentChanges().catch(()=>undefined);
|
|
132
|
+
}, [
|
|
133
|
+
loadRecentChanges
|
|
134
|
+
]);
|
|
135
|
+
useEffect(()=>{
|
|
136
|
+
if (isLoading || error || proposals.length > 0 || !response) return;
|
|
137
|
+
const timeout = window.setTimeout(()=>{
|
|
138
|
+
setResponse("");
|
|
139
|
+
clearInput();
|
|
140
|
+
}, 5000);
|
|
141
|
+
return ()=>window.clearTimeout(timeout);
|
|
142
|
+
}, [
|
|
143
|
+
error,
|
|
144
|
+
isLoading,
|
|
145
|
+
proposals.length,
|
|
146
|
+
response
|
|
147
|
+
]);
|
|
85
148
|
const collections = config.collections.filter((collection)=>!isInternalCollection(collection.slug)).filter((collection)=>isCollectionMentionEnabled(collection.slug)).map((collection)=>({
|
|
86
149
|
label: getSerializableLabel(collection.labels?.singular, collection.slug),
|
|
87
150
|
slug: collection.slug,
|
|
@@ -247,6 +310,9 @@ export const AIInput = ()=>{
|
|
|
247
310
|
if (!trimmedPrompt) return;
|
|
248
311
|
setIsLoading(true);
|
|
249
312
|
setAppliedProposalIndexes([]);
|
|
313
|
+
setError("");
|
|
314
|
+
setProposals([]);
|
|
315
|
+
setResponse("");
|
|
250
316
|
try {
|
|
251
317
|
const res = await fetch(formatAdminURL({
|
|
252
318
|
apiRoute: config.routes.api,
|
|
@@ -262,15 +328,49 @@ export const AIInput = ()=>{
|
|
|
262
328
|
},
|
|
263
329
|
method: "POST"
|
|
264
330
|
});
|
|
265
|
-
const result = await res.json();
|
|
266
331
|
if (!res.ok) {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
332
|
+
const result = await res.json().catch(()=>null);
|
|
333
|
+
throw new Error(result?.error || "AI request failed");
|
|
334
|
+
}
|
|
335
|
+
if (!res.body) {
|
|
336
|
+
throw new Error("AI response stream is unavailable");
|
|
337
|
+
}
|
|
338
|
+
const reader = res.body.getReader();
|
|
339
|
+
const decoder = new TextDecoder();
|
|
340
|
+
let buffer = "";
|
|
341
|
+
while(true){
|
|
342
|
+
const { done, value } = await reader.read();
|
|
343
|
+
if (done) break;
|
|
344
|
+
buffer += decoder.decode(value, {
|
|
345
|
+
stream: true
|
|
346
|
+
});
|
|
347
|
+
const chunks = buffer.split("\n\n");
|
|
348
|
+
buffer = chunks.pop() || "";
|
|
349
|
+
for (const chunk of chunks){
|
|
350
|
+
const event = parseSSEEvent(chunk);
|
|
351
|
+
if (!event) continue;
|
|
352
|
+
if (event.event === "text") {
|
|
353
|
+
if (event.data.delta) {
|
|
354
|
+
setResponse((current)=>current + sanitizeResponseText(event.data.delta || ""));
|
|
355
|
+
}
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
if (event.event === "proposals") {
|
|
359
|
+
setProposals(event.data.proposals || []);
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
if (event.event === "error") {
|
|
363
|
+
throw new Error(event.data.error || "AI request failed");
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
const finalEvent = buffer.trim() ? parseSSEEvent(buffer.trim()) : null;
|
|
368
|
+
if (finalEvent?.event === "proposals") {
|
|
369
|
+
setProposals(finalEvent.data.proposals || []);
|
|
370
|
+
}
|
|
371
|
+
if (finalEvent?.event === "error") {
|
|
372
|
+
throw new Error(finalEvent.data.error || "AI request failed");
|
|
270
373
|
}
|
|
271
|
-
setError("");
|
|
272
|
-
setResponse(result.text || "");
|
|
273
|
-
setProposals(result.proposals || []);
|
|
274
374
|
} catch (err) {
|
|
275
375
|
setProposals([]);
|
|
276
376
|
setResponse("");
|
|
@@ -305,6 +405,13 @@ export const AIInput = ()=>{
|
|
|
305
405
|
setError("");
|
|
306
406
|
setProposals([]);
|
|
307
407
|
setResponse("");
|
|
408
|
+
if (result.change) {
|
|
409
|
+
setAppliedChanges((current)=>[
|
|
410
|
+
result.change,
|
|
411
|
+
...current
|
|
412
|
+
].slice(0, 12));
|
|
413
|
+
}
|
|
414
|
+
void loadRecentChanges().catch(()=>undefined);
|
|
308
415
|
clearInput();
|
|
309
416
|
} catch (err) {
|
|
310
417
|
setError(err instanceof Error ? err.message : "Could not apply proposal");
|
|
@@ -313,6 +420,8 @@ export const AIInput = ()=>{
|
|
|
313
420
|
}
|
|
314
421
|
};
|
|
315
422
|
return /*#__PURE__*/ React.createElement("div", {
|
|
423
|
+
className: styles.chatLayout
|
|
424
|
+
}, /*#__PURE__*/ React.createElement("div", {
|
|
316
425
|
className: styles.chat
|
|
317
426
|
}, /*#__PURE__*/ React.createElement("div", {
|
|
318
427
|
className: styles.chatHeader
|
|
@@ -382,7 +491,11 @@ export const AIInput = ()=>{
|
|
|
382
491
|
disabled: !prompt.trim() || !settingsProvider || !selectedModel || isLoading,
|
|
383
492
|
onClick: ()=>void handleSubmit(),
|
|
384
493
|
type: "button"
|
|
385
|
-
},
|
|
494
|
+
}, /*#__PURE__*/ React.createElement(Send, {
|
|
495
|
+
width: 14,
|
|
496
|
+
height: 14
|
|
497
|
+
}), isLoading ? "Sending..." : "Send")), /*#__PURE__*/ React.createElement(AIActionProposalList, {
|
|
498
|
+
apiRoute: config.routes.api,
|
|
386
499
|
appliedProposalIndexes: appliedProposalIndexes,
|
|
387
500
|
description: response,
|
|
388
501
|
error: error,
|
|
@@ -400,5 +513,7 @@ export const AIInput = ()=>{
|
|
|
400
513
|
},
|
|
401
514
|
onApply: (proposal, _index)=>void handleApplyProposal(proposal),
|
|
402
515
|
proposals: proposals
|
|
516
|
+
})), /*#__PURE__*/ React.createElement(RecentChangesList, {
|
|
517
|
+
changes: appliedChanges
|
|
403
518
|
}));
|
|
404
519
|
};
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
.chatLayout {
|
|
2
|
+
align-items: stretch;
|
|
3
|
+
display: grid;
|
|
4
|
+
gap: 16px;
|
|
5
|
+
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
|
6
|
+
margin-bottom: 24px;
|
|
7
|
+
max-width: 1280px;
|
|
8
|
+
}
|
|
9
|
+
|
|
1
10
|
.chat {
|
|
2
11
|
border: 1px solid var(--theme-elevation-150);
|
|
3
12
|
border-radius: 8px;
|
|
4
|
-
margin-bottom: 24px;
|
|
5
|
-
max-width: 920px;
|
|
6
13
|
padding: 20px;
|
|
7
14
|
}
|
|
8
15
|
|
|
@@ -52,7 +59,7 @@
|
|
|
52
59
|
|
|
53
60
|
.selectProviderIcon {
|
|
54
61
|
color: var(--theme-text);
|
|
55
|
-
height:
|
|
62
|
+
height: 12px;
|
|
56
63
|
left: 10px;
|
|
57
64
|
pointer-events: none;
|
|
58
65
|
position: absolute;
|
|
@@ -67,7 +74,7 @@
|
|
|
67
74
|
border-radius: 4px;
|
|
68
75
|
color: var(--theme-text);
|
|
69
76
|
font: inherit;
|
|
70
|
-
min-height:
|
|
77
|
+
min-height: 24px;
|
|
71
78
|
min-width: 160px;
|
|
72
79
|
padding: 0 28px 0 34px;
|
|
73
80
|
}
|
|
@@ -173,14 +180,23 @@
|
|
|
173
180
|
}
|
|
174
181
|
|
|
175
182
|
.chatButton {
|
|
183
|
+
align-items: center;
|
|
176
184
|
background: var(--theme-text);
|
|
177
185
|
border: 0;
|
|
178
186
|
border-radius: 4px;
|
|
179
187
|
color: var(--theme-bg);
|
|
180
188
|
cursor: pointer;
|
|
189
|
+
display: inline-flex;
|
|
181
190
|
font: inherit;
|
|
182
|
-
|
|
183
|
-
|
|
191
|
+
gap: 6px;
|
|
192
|
+
justify-content: center;
|
|
193
|
+
line-height: 24px;
|
|
194
|
+
min-height: 24px;
|
|
195
|
+
padding: 0 14px;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.chatButton svg {
|
|
199
|
+
flex: 0 0 auto;
|
|
184
200
|
}
|
|
185
201
|
|
|
186
202
|
.chatButton:disabled {
|
|
@@ -220,6 +236,10 @@
|
|
|
220
236
|
}
|
|
221
237
|
|
|
222
238
|
@media (max-width: 768px) {
|
|
239
|
+
.chatLayout {
|
|
240
|
+
grid-template-columns: minmax(0, 1fr);
|
|
241
|
+
}
|
|
242
|
+
|
|
223
243
|
.chatHeader {
|
|
224
244
|
flex-direction: column;
|
|
225
245
|
gap: 12px;
|
|
@@ -251,4 +271,5 @@
|
|
|
251
271
|
.chatButton {
|
|
252
272
|
align-self: stretch;
|
|
253
273
|
}
|
|
274
|
+
|
|
254
275
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AIActionProposal } from "./AIActionProposalList.js";
|
|
2
|
+
export type ProposalDiff = {
|
|
3
|
+
after: unknown;
|
|
4
|
+
before: unknown;
|
|
5
|
+
};
|
|
6
|
+
type DiffDialogProps = {
|
|
7
|
+
diff: ProposalDiff;
|
|
8
|
+
onClose: () => void;
|
|
9
|
+
proposal: AIActionProposal;
|
|
10
|
+
};
|
|
11
|
+
export declare const DiffDialog: ({ diff, onClose, proposal }: DiffDialogProps) => import("react").JSX.Element;
|
|
12
|
+
export {};
|