@chrysb/alphaclaw 0.5.3 → 0.5.4-beta.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.
- package/lib/public/js/components/agent-send-modal.js +11 -25
- package/lib/public/js/components/doctor/index.js +6 -5
- package/lib/public/js/components/file-tree.js +26 -1
- package/lib/public/js/components/file-viewer/constants.js +2 -0
- package/lib/public/js/components/file-viewer/index.js +1 -0
- package/lib/public/js/components/file-viewer/markdown-split-view.js +2 -1
- package/lib/public/js/components/file-viewer/use-file-viewer.js +24 -6
- package/lib/public/js/components/file-viewer/utils.js +19 -0
- package/lib/public/js/components/google/gmail-setup-wizard.js +117 -50
- package/lib/public/js/components/google/index.js +45 -44
- package/lib/public/js/components/google/use-gmail-watch.js +2 -2
- package/lib/public/js/components/icons.js +13 -0
- package/lib/public/js/components/models-tab/index.js +5 -3
- package/lib/public/js/components/models-tab/provider-auth-card.js +1 -1
- package/lib/public/js/components/onboarding/welcome-form-step.js +9 -1
- package/lib/public/js/components/onboarding/welcome-pre-step.js +10 -5
- package/lib/public/js/components/session-select-field.js +72 -0
- package/lib/public/js/components/webhooks.js +114 -44
- package/lib/public/js/components/welcome/use-welcome.js +41 -20
- package/lib/public/js/hooks/use-destination-session-selection.js +85 -0
- package/lib/public/js/hooks/useAgentSessions.js +14 -0
- package/lib/public/js/lib/api.js +10 -4
- package/lib/public/js/lib/clipboard.js +40 -0
- package/lib/public/js/lib/model-config.js +2 -2
- package/lib/server/auth-profiles.js +3 -0
- package/lib/server/constants.js +2 -2
- package/lib/server/db/usage/pricing.js +1 -1
- package/lib/server/doctor/prompt.js +32 -10
- package/lib/server/gmail-watch.js +49 -22
- package/lib/server/onboarding/github.js +1 -1
- package/lib/server/routes/gmail.js +5 -1
- package/lib/server/routes/models.js +84 -1
- package/lib/server/routes/system.js +28 -26
- package/lib/server/routes/webhooks.js +2 -2
- package/lib/server/webhooks.js +32 -4
- package/package.json +1 -1
|
@@ -5,6 +5,7 @@ import { ModalShell } from "./modal-shell.js";
|
|
|
5
5
|
import { ActionButton } from "./action-button.js";
|
|
6
6
|
import { PageHeader } from "./page-header.js";
|
|
7
7
|
import { CloseIcon } from "./icons.js";
|
|
8
|
+
import { SessionSelectField } from "./session-select-field.js";
|
|
8
9
|
import { useAgentSessions } from "../hooks/useAgentSessions.js";
|
|
9
10
|
|
|
10
11
|
const html = htm.bind(h);
|
|
@@ -83,31 +84,16 @@ export const AgentSendModal = ({
|
|
|
83
84
|
</button>
|
|
84
85
|
`}
|
|
85
86
|
/>
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
? html`<option value="">No sessions available</option>`
|
|
97
|
-
: null}
|
|
98
|
-
${sessions.map(
|
|
99
|
-
(sessionRow) => html`
|
|
100
|
-
<option value=${String(sessionRow?.key || "")}>
|
|
101
|
-
${String(sessionRow?.label || sessionRow?.key || "Session")}
|
|
102
|
-
</option>
|
|
103
|
-
`,
|
|
104
|
-
)}
|
|
105
|
-
</select>
|
|
106
|
-
${loadingSessions
|
|
107
|
-
? html`<div class="text-xs text-gray-500">Loading sessions...</div>`
|
|
108
|
-
: null}
|
|
109
|
-
${loadError ? html`<div class="text-xs text-red-400">${loadError}</div>` : null}
|
|
110
|
-
</div>
|
|
87
|
+
<${SessionSelectField}
|
|
88
|
+
label="Send to session"
|
|
89
|
+
sessions=${sessions}
|
|
90
|
+
selectedSessionKey=${selectedSessionKey}
|
|
91
|
+
onChangeSessionKey=${setSelectedSessionKey}
|
|
92
|
+
disabled=${loadingSessions || sending}
|
|
93
|
+
loading=${loadingSessions}
|
|
94
|
+
error=${loadError}
|
|
95
|
+
emptyOptionLabel="No sessions available"
|
|
96
|
+
/>
|
|
111
97
|
<div class="space-y-2">
|
|
112
98
|
<label class="text-xs text-gray-500">${messageLabel}</label>
|
|
113
99
|
<textarea
|
|
@@ -523,11 +523,12 @@ export const DoctorTab = ({ isActive = false, onOpenFile = () => {} }) => {
|
|
|
523
523
|
${selectedRunIsInProgress
|
|
524
524
|
? html`
|
|
525
525
|
<div class="ac-surface-inset rounded-xl p-4">
|
|
526
|
-
<div class="text-xs leading-5 text-gray-400">
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
526
|
+
<div class="flex items-center gap-2 text-xs leading-5 text-gray-400">
|
|
527
|
+
<${LoadingSpinner} className="h-3.5 w-3.5" />
|
|
528
|
+
<span>
|
|
529
|
+
Run in progress. Findings will appear when analysis
|
|
530
|
+
completes.
|
|
531
|
+
</span>
|
|
531
532
|
</div>
|
|
532
533
|
</div>
|
|
533
534
|
`
|
|
@@ -42,10 +42,12 @@ import {
|
|
|
42
42
|
FolderAddLineIcon,
|
|
43
43
|
DeleteBinLineIcon,
|
|
44
44
|
DownloadLineIcon,
|
|
45
|
+
FileCopyLineIcon,
|
|
45
46
|
} from "./icons.js";
|
|
46
47
|
import { LoadingSpinner } from "./loading-spinner.js";
|
|
47
48
|
import { ConfirmDialog } from "./confirm-dialog.js";
|
|
48
49
|
import { showToast } from "./toast.js";
|
|
50
|
+
import { copyTextToClipboard } from "../lib/clipboard.js";
|
|
49
51
|
|
|
50
52
|
const html = htm.bind(h);
|
|
51
53
|
const kTreeIndentPx = 9;
|
|
@@ -226,6 +228,7 @@ const TreeContextMenu = ({
|
|
|
226
228
|
isLocked,
|
|
227
229
|
onNewFile,
|
|
228
230
|
onNewFolder,
|
|
231
|
+
onCopyPath,
|
|
229
232
|
onDownload,
|
|
230
233
|
onDelete,
|
|
231
234
|
onClose,
|
|
@@ -255,6 +258,7 @@ const TreeContextMenu = ({
|
|
|
255
258
|
const isRoot = targetType === "root";
|
|
256
259
|
const contextFolder = isFolder ? targetPath : "";
|
|
257
260
|
const canCreate = !isLocked && (isFolder || isRoot);
|
|
261
|
+
const canCopyPath = Boolean((isFolder || isFile) && targetPath);
|
|
258
262
|
const canDownload = isFile && targetPath;
|
|
259
263
|
const canDelete = !isLocked && (isFolder || isFile) && targetPath;
|
|
260
264
|
|
|
@@ -282,11 +286,22 @@ const TreeContextMenu = ({
|
|
|
282
286
|
</button>
|
|
283
287
|
`
|
|
284
288
|
: null}
|
|
285
|
-
${canDownload || canDelete
|
|
289
|
+
${canCopyPath || canDownload || canDelete
|
|
286
290
|
? html`
|
|
287
291
|
${canCreate
|
|
288
292
|
? html`<div class="tree-context-menu-sep"></div>`
|
|
289
293
|
: null}
|
|
294
|
+
${canCopyPath
|
|
295
|
+
? html`
|
|
296
|
+
<button
|
|
297
|
+
class="tree-context-menu-item"
|
|
298
|
+
onclick=${() => { onCopyPath(targetPath); onClose(); }}
|
|
299
|
+
>
|
|
300
|
+
<${FileCopyLineIcon} className="tree-context-menu-icon" />
|
|
301
|
+
<span>Copy Path</span>
|
|
302
|
+
</button>
|
|
303
|
+
`
|
|
304
|
+
: null}
|
|
290
305
|
${canDownload
|
|
291
306
|
? html`
|
|
292
307
|
<button
|
|
@@ -970,6 +985,15 @@ export const FileTree = ({
|
|
|
970
985
|
}
|
|
971
986
|
};
|
|
972
987
|
|
|
988
|
+
const copyPath = async (targetPath) => {
|
|
989
|
+
const copied = await copyTextToClipboard(targetPath);
|
|
990
|
+
if (copied) {
|
|
991
|
+
showToast("Path copied", "success");
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
showToast("Could not copy path", "error");
|
|
995
|
+
};
|
|
996
|
+
|
|
973
997
|
const handleDragDrop = async (action, sourcePath, targetFolder) => {
|
|
974
998
|
if (action === "start") {
|
|
975
999
|
setDragSourcePath(sourcePath);
|
|
@@ -1236,6 +1260,7 @@ export const FileTree = ({
|
|
|
1236
1260
|
isLocked=${!!contextMenu.isLocked}
|
|
1237
1261
|
onNewFile=${(folder) => requestCreate(folder, "file")}
|
|
1238
1262
|
onNewFolder=${(folder) => requestCreate(folder, "folder")}
|
|
1263
|
+
onCopyPath=${copyPath}
|
|
1239
1264
|
onDownload=${requestDownload}
|
|
1240
1265
|
onDelete=${requestDelete}
|
|
1241
1266
|
onClose=${closeContextMenu}
|
|
@@ -146,6 +146,7 @@ export const FileViewer = ({
|
|
|
146
146
|
editorLineNumbers=${derived.editorLineNumbers}
|
|
147
147
|
editorLineNumbersRef=${refs.editorLineNumbersRef}
|
|
148
148
|
editorLineNumberRowRefs=${refs.editorLineNumberRowRefs}
|
|
149
|
+
shouldUseHighlightedEditor=${derived.shouldUseHighlightedEditor}
|
|
149
150
|
highlightedEditorLines=${derived.highlightedEditorLines}
|
|
150
151
|
editorHighlightRef=${refs.editorHighlightRef}
|
|
151
152
|
editorHighlightLineRefs=${refs.editorHighlightLineRefs}
|
|
@@ -12,6 +12,7 @@ export const MarkdownSplitView = ({
|
|
|
12
12
|
editorLineNumbers,
|
|
13
13
|
editorLineNumbersRef,
|
|
14
14
|
editorLineNumberRowRefs,
|
|
15
|
+
shouldUseHighlightedEditor,
|
|
15
16
|
highlightedEditorLines,
|
|
16
17
|
editorHighlightRef,
|
|
17
18
|
editorHighlightLineRefs,
|
|
@@ -37,7 +38,7 @@ export const MarkdownSplitView = ({
|
|
|
37
38
|
editorLineNumbers=${editorLineNumbers}
|
|
38
39
|
editorLineNumbersRef=${editorLineNumbersRef}
|
|
39
40
|
editorLineNumberRowRefs=${editorLineNumberRowRefs}
|
|
40
|
-
shouldUseHighlightedEditor=${
|
|
41
|
+
shouldUseHighlightedEditor=${shouldUseHighlightedEditor}
|
|
41
42
|
highlightedEditorLines=${highlightedEditorLines}
|
|
42
43
|
editorHighlightRef=${editorHighlightRef}
|
|
43
44
|
editorHighlightLineRefs=${editorHighlightLineRefs}
|
|
@@ -18,9 +18,14 @@ import {
|
|
|
18
18
|
normalizeBrowsePolicyPath,
|
|
19
19
|
} from "../../lib/browse-file-policies.js";
|
|
20
20
|
import { showToast } from "../toast.js";
|
|
21
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
kFileViewerModeStorageKey,
|
|
23
|
+
kLargeFileSimpleEditorCharThreshold,
|
|
24
|
+
kLargeFileSimpleEditorLineThreshold,
|
|
25
|
+
kLoadingIndicatorDelayMs,
|
|
26
|
+
} from "./constants.js";
|
|
22
27
|
import { readStoredFileViewerMode, writeStoredEditorSelection } from "./storage.js";
|
|
23
|
-
import { parsePathSegments } from "./utils.js";
|
|
28
|
+
import { countTextLines, parsePathSegments, shouldUseSimpleEditorMode } from "./utils.js";
|
|
24
29
|
import { useScrollSync } from "./scroll-sync.js";
|
|
25
30
|
import { useFileLoader } from "./use-file-loader.js";
|
|
26
31
|
import { useFileDiff } from "./use-file-diff.js";
|
|
@@ -149,7 +154,19 @@ export const useFileViewer = ({
|
|
|
149
154
|
!isDeleteBlocked;
|
|
150
155
|
const syntaxKind = useMemo(() => getFileSyntaxKind(normalizedPath), [normalizedPath]);
|
|
151
156
|
const isMarkdownFile = syntaxKind === "markdown";
|
|
152
|
-
const
|
|
157
|
+
const editorLineCount = useMemo(() => countTextLines(renderContent), [renderContent]);
|
|
158
|
+
const useSimpleEditor = useMemo(
|
|
159
|
+
() =>
|
|
160
|
+
shouldUseSimpleEditorMode({
|
|
161
|
+
contentLength: renderContent.length,
|
|
162
|
+
lineCount: editorLineCount,
|
|
163
|
+
charThreshold: kLargeFileSimpleEditorCharThreshold,
|
|
164
|
+
lineThreshold: kLargeFileSimpleEditorLineThreshold,
|
|
165
|
+
}),
|
|
166
|
+
[renderContent, editorLineCount],
|
|
167
|
+
);
|
|
168
|
+
const shouldUseHighlightedEditor = syntaxKind !== "plain" && !useSimpleEditor;
|
|
169
|
+
const shouldRenderLineNumbers = !useSimpleEditor;
|
|
153
170
|
const parsedFrontmatter = useMemo(
|
|
154
171
|
() => (isMarkdownFile ? parseFrontmatter(renderContent) : { entries: [], body: renderContent }),
|
|
155
172
|
[renderContent, isMarkdownFile],
|
|
@@ -159,9 +176,9 @@ export const useFileViewer = ({
|
|
|
159
176
|
[renderContent, shouldUseHighlightedEditor, syntaxKind],
|
|
160
177
|
);
|
|
161
178
|
const editorLineNumbers = useMemo(() => {
|
|
162
|
-
|
|
163
|
-
return Array.from({ length:
|
|
164
|
-
}, [
|
|
179
|
+
if (!shouldRenderLineNumbers) return [];
|
|
180
|
+
return Array.from({ length: editorLineCount }, (_, index) => index + 1);
|
|
181
|
+
}, [editorLineCount, shouldRenderLineNumbers]);
|
|
165
182
|
const previewHtml = useMemo(
|
|
166
183
|
() =>
|
|
167
184
|
isMarkdownFile
|
|
@@ -475,6 +492,7 @@ export const useFileViewer = ({
|
|
|
475
492
|
isProtectedFile,
|
|
476
493
|
isProtectedLocked,
|
|
477
494
|
shouldUseHighlightedEditor,
|
|
495
|
+
shouldRenderLineNumbers,
|
|
478
496
|
parsedFrontmatter,
|
|
479
497
|
highlightedEditorLines,
|
|
480
498
|
editorLineNumbers,
|
|
@@ -9,3 +9,22 @@ export const clampSelectionIndex = (value, maxValue) => {
|
|
|
9
9
|
if (!Number.isFinite(numericValue)) return 0;
|
|
10
10
|
return Math.max(0, Math.min(maxValue, numericValue));
|
|
11
11
|
};
|
|
12
|
+
|
|
13
|
+
export const countTextLines = (content) => {
|
|
14
|
+
const text = String(content || "");
|
|
15
|
+
if (!text) return 1;
|
|
16
|
+
let lineCount = 1;
|
|
17
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
18
|
+
if (text.charCodeAt(index) === 10) lineCount += 1;
|
|
19
|
+
}
|
|
20
|
+
return lineCount;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const shouldUseSimpleEditorMode = ({
|
|
24
|
+
contentLength = 0,
|
|
25
|
+
lineCount = 1,
|
|
26
|
+
charThreshold = 250000,
|
|
27
|
+
lineThreshold = 5000,
|
|
28
|
+
}) =>
|
|
29
|
+
Number(contentLength) > Number(charThreshold) ||
|
|
30
|
+
Number(lineCount) > Number(lineThreshold);
|
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
import { h } from "https://esm.sh/preact";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
useCallback,
|
|
4
|
+
useEffect,
|
|
5
|
+
useMemo,
|
|
6
|
+
useState,
|
|
7
|
+
} from "https://esm.sh/preact/hooks";
|
|
3
8
|
import htm from "https://esm.sh/htm";
|
|
4
9
|
import { ModalShell } from "../modal-shell.js";
|
|
5
10
|
import { PageHeader } from "../page-header.js";
|
|
6
11
|
import { CloseIcon } from "../icons.js";
|
|
7
12
|
import { ActionButton } from "../action-button.js";
|
|
13
|
+
import { SessionSelectField } from "../session-select-field.js";
|
|
8
14
|
import { sendAgentMessage } from "../../lib/api.js";
|
|
9
15
|
import { showToast } from "../toast.js";
|
|
10
16
|
import { useAgentSessions } from "../../hooks/useAgentSessions.js";
|
|
17
|
+
import {
|
|
18
|
+
kDestinationSessionFilter,
|
|
19
|
+
kNoDestinationSessionValue,
|
|
20
|
+
useDestinationSessionSelection,
|
|
21
|
+
} from "../../hooks/use-destination-session-selection.js";
|
|
11
22
|
|
|
12
23
|
const html = htm.bind(h);
|
|
13
24
|
|
|
@@ -44,12 +55,7 @@ const kStepTitles = [
|
|
|
44
55
|
"Build with your Agent",
|
|
45
56
|
];
|
|
46
57
|
const kTotalSteps = kStepTitles.length;
|
|
47
|
-
const kNoSessionSelectedValue =
|
|
48
|
-
|
|
49
|
-
const kDirectOrGroupFilter = (sessionRow) => {
|
|
50
|
-
const key = String(sessionRow?.key || "").toLowerCase();
|
|
51
|
-
return key.includes(":direct:") || key.includes(":group:");
|
|
52
|
-
};
|
|
58
|
+
const kNoSessionSelectedValue = kNoDestinationSessionValue;
|
|
53
59
|
|
|
54
60
|
const renderCommandBlock = (command = "", onCopy = () => {}) => html`
|
|
55
61
|
<div class="rounded-lg border border-border bg-black/30 p-3">
|
|
@@ -89,12 +95,23 @@ export const GmailSetupWizard = ({
|
|
|
89
95
|
const [agentMessageSent, setAgentMessageSent] = useState(false);
|
|
90
96
|
|
|
91
97
|
const {
|
|
92
|
-
sessions: selectableAgentSessions,
|
|
93
98
|
selectedSessionKey,
|
|
94
99
|
setSelectedSessionKey,
|
|
95
100
|
loading: loadingAgentSessions,
|
|
96
101
|
error: agentSessionsError,
|
|
97
|
-
} = useAgentSessions({
|
|
102
|
+
} = useAgentSessions({
|
|
103
|
+
enabled: visible,
|
|
104
|
+
filter: kDestinationSessionFilter,
|
|
105
|
+
});
|
|
106
|
+
const {
|
|
107
|
+
sessions: selectableAgentSessions,
|
|
108
|
+
destinationSessionKey,
|
|
109
|
+
setDestinationSessionKey,
|
|
110
|
+
selectedDestination,
|
|
111
|
+
} = useDestinationSessionSelection({
|
|
112
|
+
enabled: visible,
|
|
113
|
+
resetKey: String(account?.id || ""),
|
|
114
|
+
});
|
|
98
115
|
|
|
99
116
|
useEffect(() => {
|
|
100
117
|
if (!visible) return;
|
|
@@ -118,6 +135,9 @@ export const GmailSetupWizard = ({
|
|
|
118
135
|
String(projectIdInput || "").trim() ||
|
|
119
136
|
String(clientConfig?.projectId || "").trim() ||
|
|
120
137
|
"<project-id>";
|
|
138
|
+
const hasExistingWebhookSetup = Boolean(
|
|
139
|
+
clientConfig?.configured && clientConfig?.transformExists,
|
|
140
|
+
);
|
|
121
141
|
const client =
|
|
122
142
|
String(account?.client || clientConfig?.client || "default").trim() ||
|
|
123
143
|
"default";
|
|
@@ -151,6 +171,7 @@ export const GmailSetupWizard = ({
|
|
|
151
171
|
await onFinish({
|
|
152
172
|
client,
|
|
153
173
|
projectId: String(projectIdInput || "").trim(),
|
|
174
|
+
destination: selectedDestination,
|
|
154
175
|
});
|
|
155
176
|
setWatchEnabled(true);
|
|
156
177
|
setStep((prev) => Math.min(prev + 1, kTotalSteps - 1));
|
|
@@ -184,7 +205,8 @@ export const GmailSetupWizard = ({
|
|
|
184
205
|
if (sendingToAgent || agentMessageSent) return;
|
|
185
206
|
try {
|
|
186
207
|
setSendingToAgent(true);
|
|
187
|
-
const accountEmail =
|
|
208
|
+
const accountEmail =
|
|
209
|
+
String(account?.email || "this account").trim() || "this account";
|
|
188
210
|
const message =
|
|
189
211
|
`I just enabled Gmail watch for "${accountEmail}", set up the webhook, ` +
|
|
190
212
|
`and created the transform file. Help me set up what I want to do ` +
|
|
@@ -242,7 +264,9 @@ export const GmailSetupWizard = ({
|
|
|
242
264
|
class="rounded-lg border border-border bg-black/20 p-3 space-y-2"
|
|
243
265
|
>
|
|
244
266
|
<div class="text-sm">
|
|
245
|
-
${editingProjectId
|
|
267
|
+
${editingProjectId
|
|
268
|
+
? "Change project ID"
|
|
269
|
+
: "Project ID required"}
|
|
246
270
|
</div>
|
|
247
271
|
<div class="text-xs text-gray-500">
|
|
248
272
|
Find it in the${" "}
|
|
@@ -320,9 +344,37 @@ export const GmailSetupWizard = ({
|
|
|
320
344
|
}
|
|
321
345
|
${
|
|
322
346
|
!needsProjectId && step === 3
|
|
323
|
-
?
|
|
324
|
-
|
|
325
|
-
|
|
347
|
+
? html`
|
|
348
|
+
${renderCommandBlock(commands?.createSubscription || "", () =>
|
|
349
|
+
handleCopy(commands?.createSubscription || ""),
|
|
350
|
+
)}
|
|
351
|
+
<div
|
|
352
|
+
class="rounded-lg border border-border bg-black/20 p-3 space-y-2"
|
|
353
|
+
>
|
|
354
|
+
<${SessionSelectField}
|
|
355
|
+
label="Deliver to"
|
|
356
|
+
sessions=${selectableAgentSessions}
|
|
357
|
+
selectedSessionKey=${destinationSessionKey}
|
|
358
|
+
onChangeSessionKey=${setDestinationSessionKey}
|
|
359
|
+
disabled=${hasExistingWebhookSetup ||
|
|
360
|
+
loadingAgentSessions ||
|
|
361
|
+
saving}
|
|
362
|
+
loading=${loadingAgentSessions}
|
|
363
|
+
error=${agentSessionsError}
|
|
364
|
+
allowNone=${true}
|
|
365
|
+
noneValue=${kNoSessionSelectedValue}
|
|
366
|
+
noneLabel="Default"
|
|
367
|
+
loadingLabel="Loading sessions..."
|
|
368
|
+
helperText=${hasExistingWebhookSetup
|
|
369
|
+
? "This Gmail webhook has already been created. To edit delivery routing, ask your agent."
|
|
370
|
+
: null}
|
|
371
|
+
selectClassName="w-full bg-black/30 border border-border rounded-lg px-2.5 py-2 text-xs font-mono focus:border-gray-500 focus:outline-none disabled:opacity-50 disabled:cursor-not-allowed"
|
|
372
|
+
helperClassName="text-xs text-gray-500"
|
|
373
|
+
statusClassName="text-[11px] text-gray-500"
|
|
374
|
+
errorClassName="text-[11px] text-red-400"
|
|
375
|
+
/>
|
|
376
|
+
</div>
|
|
377
|
+
`
|
|
326
378
|
: null
|
|
327
379
|
}
|
|
328
380
|
${
|
|
@@ -338,21 +390,29 @@ export const GmailSetupWizard = ({
|
|
|
338
390
|
incoming email to continue the setup.
|
|
339
391
|
</div>
|
|
340
392
|
<div class="pt-2 space-y-2">
|
|
341
|
-
<div class="text-[11px] text-gray-500">
|
|
393
|
+
<div class="text-[11px] text-gray-500">
|
|
394
|
+
Send this to session
|
|
395
|
+
</div>
|
|
342
396
|
<div class="flex items-center gap-2">
|
|
343
397
|
<select
|
|
344
398
|
value=${selectedSessionKey || kNoSessionSelectedValue}
|
|
345
399
|
oninput=${(event) => {
|
|
346
400
|
const nextValue = String(event.target.value || "");
|
|
347
401
|
setSelectedSessionKey(
|
|
348
|
-
nextValue === kNoSessionSelectedValue
|
|
402
|
+
nextValue === kNoSessionSelectedValue
|
|
403
|
+
? ""
|
|
404
|
+
: nextValue,
|
|
349
405
|
);
|
|
350
406
|
}}
|
|
351
|
-
disabled=${loadingAgentSessions ||
|
|
407
|
+
disabled=${loadingAgentSessions ||
|
|
408
|
+
sendingToAgent ||
|
|
409
|
+
agentMessageSent}
|
|
352
410
|
class="flex-1 min-w-0 bg-black/30 border border-border rounded-lg px-2.5 py-2 text-xs font-mono focus:border-gray-500 focus:outline-none disabled:opacity-50 disabled:cursor-not-allowed"
|
|
353
411
|
>
|
|
354
412
|
${!selectedSessionKey
|
|
355
|
-
? html`<option value=${kNoSessionSelectedValue}>
|
|
413
|
+
? html`<option value=${kNoSessionSelectedValue}>
|
|
414
|
+
Select a session...
|
|
415
|
+
</option>`
|
|
356
416
|
: null}
|
|
357
417
|
${selectableAgentSessions.map(
|
|
358
418
|
(sessionRow) => html`
|
|
@@ -366,7 +426,6 @@ export const GmailSetupWizard = ({
|
|
|
366
426
|
onClick=${handleSendToAgent}
|
|
367
427
|
disabled=${!selectedSessionKey || agentMessageSent}
|
|
368
428
|
loading=${sendingToAgent}
|
|
369
|
-
loadingMode="inline"
|
|
370
429
|
idleLabel=${agentMessageSent ? "Sent" : "Send to Agent"}
|
|
371
430
|
loadingLabel="Sending..."
|
|
372
431
|
tone="primary"
|
|
@@ -375,10 +434,14 @@ export const GmailSetupWizard = ({
|
|
|
375
434
|
/>
|
|
376
435
|
</div>
|
|
377
436
|
${loadingAgentSessions
|
|
378
|
-
? html`<div class="text-[11px] text-gray-500">
|
|
437
|
+
? html`<div class="text-[11px] text-gray-500">
|
|
438
|
+
Loading sessions...
|
|
439
|
+
</div>`
|
|
379
440
|
: null}
|
|
380
441
|
${agentSessionsError
|
|
381
|
-
? html`<div class="text-[11px] text-red-400"
|
|
442
|
+
? html`<div class="text-[11px] text-red-400">
|
|
443
|
+
${agentSessionsError}
|
|
444
|
+
</div>`
|
|
382
445
|
: null}
|
|
383
446
|
</div>
|
|
384
447
|
</div>
|
|
@@ -387,24 +450,26 @@ export const GmailSetupWizard = ({
|
|
|
387
450
|
: null
|
|
388
451
|
}
|
|
389
452
|
<div class="grid grid-cols-2 gap-2 pt-2">
|
|
390
|
-
${
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
453
|
+
${
|
|
454
|
+
step === 0
|
|
455
|
+
? html`${!needsProjectId
|
|
456
|
+
? html`<button
|
|
457
|
+
type="button"
|
|
458
|
+
onclick=${handleChangeProjectId}
|
|
459
|
+
class="justify-self-start text-xs px-2 py-1 rounded-lg ac-btn-ghost"
|
|
460
|
+
>
|
|
461
|
+
Change project ID
|
|
462
|
+
</button>`
|
|
463
|
+
: html`<div></div>`}`
|
|
464
|
+
: html`<${ActionButton}
|
|
465
|
+
onClick=${() => setStep((prev) => Math.max(prev - 1, 0))}
|
|
466
|
+
disabled=${saving}
|
|
467
|
+
idleLabel="Back"
|
|
468
|
+
tone="secondary"
|
|
469
|
+
size="md"
|
|
470
|
+
className="w-full justify-center"
|
|
471
|
+
/>`
|
|
472
|
+
}
|
|
408
473
|
${
|
|
409
474
|
step < kTotalSteps - 2
|
|
410
475
|
? html`<${ActionButton}
|
|
@@ -417,23 +482,25 @@ export const GmailSetupWizard = ({
|
|
|
417
482
|
/>`
|
|
418
483
|
: step === kTotalSteps - 2
|
|
419
484
|
? html`<${ActionButton}
|
|
420
|
-
onClick=${handleFinish}
|
|
485
|
+
onClick=${hasExistingWebhookSetup ? handleNext : handleFinish}
|
|
421
486
|
disabled=${false}
|
|
422
487
|
loading=${saving}
|
|
423
|
-
idleLabel
|
|
424
|
-
loadingLabel
|
|
488
|
+
idleLabel=${hasExistingWebhookSetup ? "Next" : "Enable watch"}
|
|
489
|
+
loadingLabel=${hasExistingWebhookSetup
|
|
490
|
+
? "Loading..."
|
|
491
|
+
: "Enabling..."}
|
|
425
492
|
tone="primary"
|
|
426
493
|
size="md"
|
|
427
494
|
className="w-full justify-center"
|
|
428
495
|
/>`
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
496
|
+
: html`<${ActionButton}
|
|
497
|
+
onClick=${onClose}
|
|
498
|
+
disabled=${saving || sendingToAgent}
|
|
499
|
+
idleLabel="Done"
|
|
500
|
+
tone="secondary"
|
|
501
|
+
size="md"
|
|
502
|
+
className="w-full justify-center"
|
|
503
|
+
/>`
|
|
437
504
|
}
|
|
438
505
|
</div>
|
|
439
506
|
</${ModalShell}>
|
|
@@ -16,7 +16,6 @@ import { getDefaultScopes, toggleScopeLogic } from "../scope-picker.js";
|
|
|
16
16
|
import { CredentialsModal } from "../credentials-modal.js";
|
|
17
17
|
import { ConfirmDialog } from "../confirm-dialog.js";
|
|
18
18
|
import { showToast } from "../toast.js";
|
|
19
|
-
import { PageHeader } from "../page-header.js";
|
|
20
19
|
import { ActionButton } from "../action-button.js";
|
|
21
20
|
import { GoogleAccountRow } from "./account-row.js";
|
|
22
21
|
import { AddGoogleAccountModal } from "./add-account-modal.js";
|
|
@@ -397,7 +396,11 @@ export const Google = ({
|
|
|
397
396
|
}
|
|
398
397
|
};
|
|
399
398
|
|
|
400
|
-
const handleFinishGmailSetupWizard = async ({
|
|
399
|
+
const handleFinishGmailSetupWizard = async ({
|
|
400
|
+
client,
|
|
401
|
+
projectId,
|
|
402
|
+
destination = null,
|
|
403
|
+
}) => {
|
|
401
404
|
const accountId = String(gmailWizardState.accountId || "").trim();
|
|
402
405
|
if (!accountId) return;
|
|
403
406
|
await saveClientSetup({
|
|
@@ -405,7 +408,7 @@ export const Google = ({
|
|
|
405
408
|
projectId,
|
|
406
409
|
regeneratePushToken: false,
|
|
407
410
|
});
|
|
408
|
-
await startWatchForAccount(accountId);
|
|
411
|
+
await startWatchForAccount(accountId, { destination });
|
|
409
412
|
showToast("Gmail setup complete and watch enabled", "success");
|
|
410
413
|
};
|
|
411
414
|
|
|
@@ -447,48 +450,46 @@ export const Google = ({
|
|
|
447
450
|
|
|
448
451
|
return html`
|
|
449
452
|
<div class="bg-surface border border-border rounded-xl p-4">
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
<
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
453
|
+
<div class="flex items-center justify-between gap-3">
|
|
454
|
+
<h2 class="card-label">Google Accounts</h2>
|
|
455
|
+
${accounts.length
|
|
456
|
+
? html`
|
|
457
|
+
<div class="relative">
|
|
458
|
+
<button
|
|
459
|
+
type="button"
|
|
460
|
+
onclick=${() => setAddMenuOpen((prev) => !prev)}
|
|
461
|
+
class="text-xs font-medium px-3 py-1.5 rounded-lg ac-btn-secondary"
|
|
462
|
+
>
|
|
463
|
+
+ Add Account
|
|
464
|
+
</button>
|
|
465
|
+
${addMenuOpen
|
|
466
|
+
? html`
|
|
467
|
+
<div
|
|
468
|
+
class="absolute right-0 top-full mt-2 min-w-[210px] rounded-lg border border-border bg-modal p-1 z-20"
|
|
469
|
+
>
|
|
470
|
+
<button
|
|
471
|
+
type="button"
|
|
472
|
+
onclick=${handleAddCompanyClick}
|
|
473
|
+
class="w-full text-left px-2.5 py-1.5 text-xs rounded-md hover:bg-black/30"
|
|
467
474
|
>
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
: null}
|
|
487
|
-
</div>
|
|
488
|
-
`
|
|
489
|
-
: null}
|
|
490
|
-
`}
|
|
491
|
-
/>
|
|
475
|
+
Company account
|
|
476
|
+
</button>
|
|
477
|
+
${!hasPersonalAccount
|
|
478
|
+
? html`<button
|
|
479
|
+
type="button"
|
|
480
|
+
onclick=${handleAddPersonalClick}
|
|
481
|
+
class="w-full text-left px-2.5 py-1.5 text-xs rounded-md hover:bg-black/30"
|
|
482
|
+
>
|
|
483
|
+
Personal account
|
|
484
|
+
</button>`
|
|
485
|
+
: null}
|
|
486
|
+
</div>
|
|
487
|
+
`
|
|
488
|
+
: null}
|
|
489
|
+
</div>
|
|
490
|
+
`
|
|
491
|
+
: null}
|
|
492
|
+
</div>
|
|
492
493
|
${loading
|
|
493
494
|
? html`<div class="text-gray-500 text-sm text-center py-2">
|
|
494
495
|
Loading...
|