@alpaca-editor/core 1.0.4174 → 1.0.4177
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/agents-view/AgentsView.js +0 -20
- package/dist/agents-view/AgentsView.js.map +1 -1
- package/dist/editor/QuickItemSwitcher.js +5 -1
- package/dist/editor/QuickItemSwitcher.js.map +1 -1
- package/dist/editor/ai/AgentTerminal.js +47 -83
- package/dist/editor/ai/AgentTerminal.js.map +1 -1
- package/dist/editor/ai/Agents.js +7 -5
- package/dist/editor/ai/Agents.js.map +1 -1
- package/dist/editor/ai/AiResponseMessage.js +1 -1
- package/dist/editor/ai/AiResponseMessage.js.map +1 -1
- package/dist/editor/ai/ContextInfoBar.js +30 -64
- package/dist/editor/ai/ContextInfoBar.js.map +1 -1
- package/dist/editor/ai/useAgentStatus.js +81 -2
- package/dist/editor/ai/useAgentStatus.js.map +1 -1
- package/dist/editor/client/EditorShell.js +44 -7
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/operations.js +30 -3
- package/dist/editor/client/operations.js.map +1 -1
- package/dist/editor/control-center/WebSocketMessages.js +0 -1
- package/dist/editor/control-center/WebSocketMessages.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +14 -3
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/reviews/commentAi.js +43 -32
- package/dist/editor/reviews/commentAi.js.map +1 -1
- package/dist/editor/services/agentService.d.ts +8 -4
- package/dist/editor/services/agentService.js +30 -53
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/aiService.d.ts +19 -1
- package/dist/editor/services/aiService.js +78 -2
- package/dist/editor/services/aiService.js.map +1 -1
- package/dist/page-wizard/steps/ContentStep.js +35 -57
- package/dist/page-wizard/steps/ContentStep.js.map +1 -1
- package/dist/page-wizard/steps/MetaDataStep.js +14 -23
- package/dist/page-wizard/steps/MetaDataStep.js.map +1 -1
- package/dist/page-wizard/steps/SelectStep.js +12 -42
- package/dist/page-wizard/steps/SelectStep.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/styles.css +0 -8
- package/package.json +1 -1
- package/src/agents-view/AgentsView.tsx +1 -21
- package/src/editor/QuickItemSwitcher.tsx +23 -19
- package/src/editor/ai/AgentTerminal.tsx +83 -142
- package/src/editor/ai/Agents.tsx +9 -6
- package/src/editor/ai/AiResponseMessage.tsx +5 -1
- package/src/editor/ai/ContextInfoBar.tsx +34 -75
- package/src/editor/ai/useAgentStatus.ts +82 -4
- package/src/editor/client/EditorShell.tsx +62 -9
- package/src/editor/client/operations.ts +42 -4
- package/src/editor/control-center/WebSocketMessages.tsx +5 -1
- package/src/editor/page-viewer/PageViewerFrame.tsx +15 -2
- package/src/editor/reviews/commentAi.ts +48 -36
- package/src/editor/services/agentService.ts +38 -55
- package/src/editor/services/aiService.ts +110 -3
- package/src/page-wizard/steps/ContentStep.tsx +51 -81
- package/src/page-wizard/steps/MetaDataStep.tsx +52 -60
- package/src/page-wizard/steps/SelectStep.tsx +13 -51
- package/src/revision.ts +2 -2
|
@@ -42,7 +42,7 @@ export function ContextInfoBar({
|
|
|
42
42
|
|
|
43
43
|
const removeContextKey = useCallback(
|
|
44
44
|
async (
|
|
45
|
-
key: "items" | "
|
|
45
|
+
key: "items" | "components" | "field" | "comment",
|
|
46
46
|
index?: number,
|
|
47
47
|
) => {
|
|
48
48
|
if (!agent?.id) return;
|
|
@@ -54,7 +54,7 @@ export function ContextInfoBar({
|
|
|
54
54
|
next.items.splice(index, 1);
|
|
55
55
|
if (next.items.length === 0) delete next.items;
|
|
56
56
|
} else if (
|
|
57
|
-
|
|
57
|
+
key === "components" &&
|
|
58
58
|
typeof index === "number" &&
|
|
59
59
|
next.components
|
|
60
60
|
) {
|
|
@@ -137,7 +137,7 @@ export function ContextInfoBar({
|
|
|
137
137
|
const current = agentMetadata || {};
|
|
138
138
|
const currentComponents = current.components || [];
|
|
139
139
|
|
|
140
|
-
const existingIds = new Set(currentComponents.map(c => c.componentId));
|
|
140
|
+
const existingIds = new Set(currentComponents.map((c) => c.componentId));
|
|
141
141
|
const newComponentIds = editContext.selection.filter(
|
|
142
142
|
(id) => !existingIds.has(id),
|
|
143
143
|
);
|
|
@@ -145,16 +145,18 @@ export function ContextInfoBar({
|
|
|
145
145
|
if (newComponentIds.length === 0) return;
|
|
146
146
|
|
|
147
147
|
// Get page item descriptor from edit context
|
|
148
|
-
const pageItem = editContext.currentItemDescriptor
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
148
|
+
const pageItem = editContext.currentItemDescriptor
|
|
149
|
+
? {
|
|
150
|
+
id: editContext.currentItemDescriptor.id,
|
|
151
|
+
language: editContext.currentItemDescriptor.language,
|
|
152
|
+
version: editContext.currentItemDescriptor.version,
|
|
153
|
+
name: editContext.contentEditorItem?.name,
|
|
154
|
+
path: undefined,
|
|
155
|
+
}
|
|
156
|
+
: undefined;
|
|
155
157
|
|
|
156
158
|
// Build new components with page info
|
|
157
|
-
const newComponents = newComponentIds.map(componentId => ({
|
|
159
|
+
const newComponents = newComponentIds.map((componentId) => ({
|
|
158
160
|
componentId,
|
|
159
161
|
pageItem: pageItem!,
|
|
160
162
|
}));
|
|
@@ -185,21 +187,23 @@ export function ContextInfoBar({
|
|
|
185
187
|
const current = agentMetadata || {};
|
|
186
188
|
const currentComponents = current.components || [];
|
|
187
189
|
|
|
188
|
-
const existingIds = new Set(currentComponents.map(c => c.componentId));
|
|
190
|
+
const existingIds = new Set(currentComponents.map((c) => c.componentId));
|
|
189
191
|
const newComponentIds = ids.filter((id) => !!id && !existingIds.has(id));
|
|
190
192
|
if (newComponentIds.length === 0) return;
|
|
191
193
|
|
|
192
194
|
// Get page item descriptor from edit context
|
|
193
|
-
const pageItem = editContext?.currentItemDescriptor
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
195
|
+
const pageItem = editContext?.currentItemDescriptor
|
|
196
|
+
? {
|
|
197
|
+
id: editContext.currentItemDescriptor.id,
|
|
198
|
+
language: editContext.currentItemDescriptor.language,
|
|
199
|
+
version: editContext.currentItemDescriptor.version,
|
|
200
|
+
name: editContext.contentEditorItem?.name,
|
|
201
|
+
path: undefined,
|
|
202
|
+
}
|
|
203
|
+
: undefined;
|
|
200
204
|
|
|
201
205
|
// Build new components with page info
|
|
202
|
-
const newComponents = newComponentIds.map(componentId => ({
|
|
206
|
+
const newComponents = newComponentIds.map((componentId) => ({
|
|
203
207
|
componentId,
|
|
204
208
|
pageItem: pageItem!,
|
|
205
209
|
}));
|
|
@@ -351,7 +355,7 @@ export function ContextInfoBar({
|
|
|
351
355
|
const ctx = agentMetadata;
|
|
352
356
|
|
|
353
357
|
const hasContext =
|
|
354
|
-
ctx && (ctx.items?.length || ctx.components?.length || ctx.
|
|
358
|
+
ctx && (ctx.items?.length || ctx.components?.length || ctx.field);
|
|
355
359
|
|
|
356
360
|
const currentPageAlreadyAdded =
|
|
357
361
|
editContext?.currentItemDescriptor &&
|
|
@@ -365,8 +369,7 @@ export function ContextInfoBar({
|
|
|
365
369
|
const selectedComponentsAlreadyAdded =
|
|
366
370
|
!!editContext?.selection?.length &&
|
|
367
371
|
!!editContext.selection?.every((selectedId) =>
|
|
368
|
-
ctx?.components?.some(c => c.componentId === selectedId)
|
|
369
|
-
ctx?.componentIds?.includes(selectedId),
|
|
372
|
+
ctx?.components?.some((c) => c.componentId === selectedId),
|
|
370
373
|
);
|
|
371
374
|
|
|
372
375
|
const canAddPage =
|
|
@@ -404,10 +407,7 @@ export function ContextInfoBar({
|
|
|
404
407
|
|
|
405
408
|
if (ctx?.items && ctx.items.length > 0) {
|
|
406
409
|
ctx.items.forEach((page, index) => {
|
|
407
|
-
const pageLabelName =
|
|
408
|
-
page.name ||
|
|
409
|
-
resolvedPageName ||
|
|
410
|
-
undefined;
|
|
410
|
+
const pageLabelName = page.name || resolvedPageName || undefined;
|
|
411
411
|
const pageLabel = `${pageLabelName || page.path || page.id} (${page.language}/${page.version})`;
|
|
412
412
|
chips.push(
|
|
413
413
|
<Chip
|
|
@@ -432,12 +432,12 @@ export function ContextInfoBar({
|
|
|
432
432
|
compLabel = (comp?.name as string) || componentId;
|
|
433
433
|
} catch {}
|
|
434
434
|
}
|
|
435
|
-
|
|
435
|
+
|
|
436
436
|
// Include page info in the label
|
|
437
|
-
const pageInfo = component.pageItem
|
|
437
|
+
const pageInfo = component.pageItem
|
|
438
438
|
? ` on ${component.pageItem.name || component.pageItem.path || component.pageItem.id}`
|
|
439
|
-
:
|
|
440
|
-
|
|
439
|
+
: "";
|
|
440
|
+
|
|
441
441
|
chips.push(
|
|
442
442
|
<Chip
|
|
443
443
|
key={`component-${index}`}
|
|
@@ -447,34 +447,10 @@ export function ContextInfoBar({
|
|
|
447
447
|
/>,
|
|
448
448
|
);
|
|
449
449
|
});
|
|
450
|
-
} else if (ctx?.componentIds && ctx.componentIds.length > 0) {
|
|
451
|
-
// Legacy support for componentIds without page info
|
|
452
|
-
ctx.componentIds.forEach((componentId, index) => {
|
|
453
|
-
let compLabel: string = componentId as string;
|
|
454
|
-
if (index === 0 && resolvedComponentName) {
|
|
455
|
-
compLabel = resolvedComponentName as string;
|
|
456
|
-
} else if (editContext?.page) {
|
|
457
|
-
try {
|
|
458
|
-
const comp = getComponentById(
|
|
459
|
-
componentId as string,
|
|
460
|
-
editContext.page,
|
|
461
|
-
);
|
|
462
|
-
compLabel = (comp?.name as string) || (componentId as string);
|
|
463
|
-
} catch {}
|
|
464
|
-
}
|
|
465
|
-
chips.push(
|
|
466
|
-
<Chip
|
|
467
|
-
key={`component-${index}`}
|
|
468
|
-
icon={<Puzzle className="h-3 w-3 text-gray-500" strokeWidth={1} />}
|
|
469
|
-
label={`Component: ${compLabel}`}
|
|
470
|
-
onRemove={() => removeContextKey("componentIds", index)}
|
|
471
|
-
/>,
|
|
472
|
-
);
|
|
473
|
-
});
|
|
474
450
|
}
|
|
475
451
|
|
|
476
452
|
if (ctx?.field) {
|
|
477
|
-
const fieldLabel = `${ctx.field.
|
|
453
|
+
const fieldLabel = `${ctx.field.fieldName || resolvedFieldName || ctx.field.fieldId}`;
|
|
478
454
|
chips.push(
|
|
479
455
|
<Chip
|
|
480
456
|
key="field"
|
|
@@ -489,10 +465,7 @@ export function ContextInfoBar({
|
|
|
489
465
|
const summaryParts: string[] = [];
|
|
490
466
|
if (ctx?.items && ctx.items.length > 0) {
|
|
491
467
|
const first = ctx.items[0]!;
|
|
492
|
-
const pageLabelName =
|
|
493
|
-
first.name ||
|
|
494
|
-
resolvedPageName ||
|
|
495
|
-
undefined;
|
|
468
|
+
const pageLabelName = first.name || resolvedPageName || undefined;
|
|
496
469
|
const pageText = pageLabelName || first.path || first.id;
|
|
497
470
|
const more = ctx.items.length > 1 ? ` (+${ctx.items.length - 1})` : "";
|
|
498
471
|
summaryParts.push(`Item: ${pageText}${more}`);
|
|
@@ -511,24 +484,10 @@ export function ContextInfoBar({
|
|
|
511
484
|
const more =
|
|
512
485
|
ctx.components.length > 1 ? ` (+${ctx.components.length - 1})` : "";
|
|
513
486
|
summaryParts.push(`Component: ${compLabel}${more}`);
|
|
514
|
-
} else if (ctx?.componentIds && ctx.componentIds.length > 0) {
|
|
515
|
-
// Legacy support for componentIds
|
|
516
|
-
const firstId = ctx.componentIds[0]!;
|
|
517
|
-
let compLabel: string = firstId as string;
|
|
518
|
-
if (resolvedComponentName) compLabel = resolvedComponentName as string;
|
|
519
|
-
else if (editContext?.page) {
|
|
520
|
-
try {
|
|
521
|
-
const comp = getComponentById(firstId as string, editContext.page);
|
|
522
|
-
compLabel = (comp?.name as string) || (firstId as string);
|
|
523
|
-
} catch {}
|
|
524
|
-
}
|
|
525
|
-
const more =
|
|
526
|
-
ctx.componentIds.length > 1 ? ` (+${ctx.componentIds.length - 1})` : "";
|
|
527
|
-
summaryParts.push(`Component: ${compLabel}${more}`);
|
|
528
487
|
}
|
|
529
488
|
if (ctx?.field) {
|
|
530
489
|
summaryParts.push(
|
|
531
|
-
`Field: ${ctx.field.
|
|
490
|
+
`Field: ${ctx.field.fieldName || resolvedFieldName || ctx.field.fieldId}`,
|
|
532
491
|
);
|
|
533
492
|
}
|
|
534
493
|
if ((ctx as any)?.comment?.selectedText) {
|
|
@@ -53,10 +53,7 @@ export function useAgentStatus(): AgentStatusSummary {
|
|
|
53
53
|
|
|
54
54
|
// Subscribe to WebSocket messages for agent status updates
|
|
55
55
|
const handleMessage = (message: { type: string; payload: any }) => {
|
|
56
|
-
if (
|
|
57
|
-
message.type === "agent:status:changed" ||
|
|
58
|
-
message.type === "agent:run:start"
|
|
59
|
-
) {
|
|
56
|
+
if (message.type === "agent:run:start") {
|
|
60
57
|
// Update agent status in real-time from WebSocket message
|
|
61
58
|
const { agentId, status, name, agentName } = message.payload || {};
|
|
62
59
|
if (!agentId) return;
|
|
@@ -111,6 +108,87 @@ export function useAgentStatus(): AgentStatusSummary {
|
|
|
111
108
|
|
|
112
109
|
return prevAgents;
|
|
113
110
|
});
|
|
111
|
+
} else if (message.type === "agent:run:status") {
|
|
112
|
+
// Unified status updates with data.state
|
|
113
|
+
const { agentId, data } = message.payload || {};
|
|
114
|
+
if (!agentId) return;
|
|
115
|
+
|
|
116
|
+
const rawState = (data?.state as string | undefined) || undefined;
|
|
117
|
+
const mappedStatus = ((): Agent["status"] | undefined => {
|
|
118
|
+
if (!rawState) return undefined;
|
|
119
|
+
switch (rawState) {
|
|
120
|
+
case "Running":
|
|
121
|
+
return "running" as const;
|
|
122
|
+
case "WaitingForApproval":
|
|
123
|
+
return "waitingForApproval" as const;
|
|
124
|
+
case "Completed":
|
|
125
|
+
return "completed" as const;
|
|
126
|
+
case "Closed":
|
|
127
|
+
return "closed" as const;
|
|
128
|
+
case "Error":
|
|
129
|
+
return "error" as const;
|
|
130
|
+
case "Idle":
|
|
131
|
+
return "idle" as const;
|
|
132
|
+
case "CostLimitReached":
|
|
133
|
+
return "costLimitReached" as const;
|
|
134
|
+
case "Queued":
|
|
135
|
+
return undefined; // do not show queued in badge
|
|
136
|
+
default:
|
|
137
|
+
// allow already-lowercased strings
|
|
138
|
+
return rawState as any;
|
|
139
|
+
}
|
|
140
|
+
})();
|
|
141
|
+
|
|
142
|
+
if (!mappedStatus) return;
|
|
143
|
+
|
|
144
|
+
setAgents((prevAgents) => {
|
|
145
|
+
const existingIndex = prevAgents.findIndex((a) => a.id === agentId);
|
|
146
|
+
const isTerminal =
|
|
147
|
+
mappedStatus === "completed" ||
|
|
148
|
+
mappedStatus === "error" ||
|
|
149
|
+
mappedStatus === "closed";
|
|
150
|
+
|
|
151
|
+
if (existingIndex !== -1) {
|
|
152
|
+
if (isTerminal) {
|
|
153
|
+
// Remove terminal states from active list
|
|
154
|
+
return prevAgents.filter((a) => a.id !== agentId);
|
|
155
|
+
}
|
|
156
|
+
const updated = [...prevAgents];
|
|
157
|
+
updated[existingIndex] = {
|
|
158
|
+
...updated[existingIndex]!,
|
|
159
|
+
status: mappedStatus,
|
|
160
|
+
updatedDate: new Date().toISOString(),
|
|
161
|
+
};
|
|
162
|
+
return updated;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Add new if active state
|
|
166
|
+
if (
|
|
167
|
+
mappedStatus === "running" ||
|
|
168
|
+
mappedStatus === "waitingForApproval" ||
|
|
169
|
+
mappedStatus === "costLimitReached" ||
|
|
170
|
+
mappedStatus === "idle"
|
|
171
|
+
) {
|
|
172
|
+
const newAgent: Agent = {
|
|
173
|
+
id: agentId,
|
|
174
|
+
name: (data?.name as string) || "Agent",
|
|
175
|
+
userId: "",
|
|
176
|
+
status: mappedStatus,
|
|
177
|
+
updatedDate: new Date().toISOString(),
|
|
178
|
+
};
|
|
179
|
+
return [...prevAgents, newAgent];
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return prevAgents;
|
|
183
|
+
});
|
|
184
|
+
} else if (message.type === "agent:run:complete") {
|
|
185
|
+
const { agentId } = message.payload || {};
|
|
186
|
+
if (!agentId) return;
|
|
187
|
+
setAgents((prevAgents) => prevAgents.filter((a) => a.id !== agentId));
|
|
188
|
+
} else if (message.type === "agent:run:error") {
|
|
189
|
+
const { agentId } = message.payload || {};
|
|
190
|
+
if (!agentId) return;
|
|
191
|
+
setAgents((prevAgents) => prevAgents.filter((a) => a.id !== agentId));
|
|
114
192
|
} else if (message.type === "agent:run:closed") {
|
|
115
193
|
// Remove agent from list when it's closed
|
|
116
194
|
const { agentId } = message.payload || {};
|
|
@@ -1229,7 +1229,11 @@ export function EditorShell({
|
|
|
1229
1229
|
const loadItem = useCallback(
|
|
1230
1230
|
async (
|
|
1231
1231
|
itemToLoad: ItemDescriptor | string,
|
|
1232
|
-
options?: {
|
|
1232
|
+
options?: {
|
|
1233
|
+
addToBrowseHistory?: boolean;
|
|
1234
|
+
skipViewChange?: boolean;
|
|
1235
|
+
skipNavigationHistory?: boolean;
|
|
1236
|
+
},
|
|
1233
1237
|
): Promise<FullItem | undefined> => {
|
|
1234
1238
|
if (typeof itemToLoad === "string")
|
|
1235
1239
|
itemToLoad = {
|
|
@@ -1271,8 +1275,10 @@ export function EditorShell({
|
|
|
1271
1275
|
options?.addToBrowseHistory === undefined
|
|
1272
1276
|
) {
|
|
1273
1277
|
addToBrowseHistory(item);
|
|
1274
|
-
// Also add to navigation history with current view
|
|
1275
|
-
|
|
1278
|
+
// Also add to navigation history with current view (unless skipped)
|
|
1279
|
+
if (!options?.skipNavigationHistory) {
|
|
1280
|
+
addNavigationEntry(viewName, item);
|
|
1281
|
+
}
|
|
1276
1282
|
}
|
|
1277
1283
|
|
|
1278
1284
|
return item;
|
|
@@ -1483,7 +1489,7 @@ export function EditorShell({
|
|
|
1483
1489
|
|
|
1484
1490
|
const switchView = (
|
|
1485
1491
|
viewName: string,
|
|
1486
|
-
options?: { skipConfirmation?: boolean },
|
|
1492
|
+
options?: { skipConfirmation?: boolean; skipNavigationHistory?: boolean },
|
|
1487
1493
|
) => {
|
|
1488
1494
|
async function switchView() {
|
|
1489
1495
|
if (currentView?.beforeClose && !options?.skipConfirmation) {
|
|
@@ -1494,8 +1500,10 @@ export function EditorShell({
|
|
|
1494
1500
|
// Track previous view name before switching
|
|
1495
1501
|
setPreviousViewName(editContext.viewName);
|
|
1496
1502
|
|
|
1497
|
-
// Add to navigation history with current item
|
|
1498
|
-
|
|
1503
|
+
// Add to navigation history with current item (unless explicitly skipped)
|
|
1504
|
+
if (!options?.skipNavigationHistory) {
|
|
1505
|
+
addNavigationEntry(viewName, contentEditorItem);
|
|
1506
|
+
}
|
|
1499
1507
|
|
|
1500
1508
|
if (typeof document.startViewTransition === "function") {
|
|
1501
1509
|
document.startViewTransition(() => {
|
|
@@ -1572,6 +1580,20 @@ export function EditorShell({
|
|
|
1572
1580
|
field: FieldDescriptor | undefined,
|
|
1573
1581
|
requestLock: boolean,
|
|
1574
1582
|
): Promise<boolean> => {
|
|
1583
|
+
console.log("[setFocusedFieldWithLock] Called with:", {
|
|
1584
|
+
field: field
|
|
1585
|
+
? {
|
|
1586
|
+
fieldId: field.fieldId,
|
|
1587
|
+
itemId: field.item?.id,
|
|
1588
|
+
language: field.item?.language,
|
|
1589
|
+
version: field.item?.version,
|
|
1590
|
+
}
|
|
1591
|
+
: undefined,
|
|
1592
|
+
requestLock,
|
|
1593
|
+
ignoreBlur,
|
|
1594
|
+
timestamp: new Date().toISOString(),
|
|
1595
|
+
});
|
|
1596
|
+
|
|
1575
1597
|
if (field) {
|
|
1576
1598
|
setIgnoreBlur(true);
|
|
1577
1599
|
setTimeout(() => {
|
|
@@ -1579,11 +1601,26 @@ export function EditorShell({
|
|
|
1579
1601
|
}, 20);
|
|
1580
1602
|
setFocusedField({ ...field });
|
|
1581
1603
|
if (requestLock) {
|
|
1582
|
-
|
|
1604
|
+
console.log(
|
|
1605
|
+
"[setFocusedFieldWithLock] Calling operations.ensureLock for field:",
|
|
1606
|
+
field.fieldId,
|
|
1607
|
+
);
|
|
1608
|
+
const lockResult = (await operations.ensureLock(field)) || false;
|
|
1609
|
+
console.log(
|
|
1610
|
+
"[setFocusedFieldWithLock] ensureLock result:",
|
|
1611
|
+
lockResult,
|
|
1612
|
+
);
|
|
1613
|
+
return lockResult;
|
|
1583
1614
|
}
|
|
1584
1615
|
} else {
|
|
1616
|
+
console.log(
|
|
1617
|
+
"[setFocusedFieldWithLock] Clearing focused field, ignoreBlur:",
|
|
1618
|
+
ignoreBlur,
|
|
1619
|
+
);
|
|
1585
1620
|
if (!ignoreBlur) {
|
|
1586
1621
|
setFocusedField(undefined);
|
|
1622
|
+
console.log("[setFocusedFieldWithLock] Clearing lockedField state");
|
|
1623
|
+
setLockedField(undefined); // Clear client-side lock state
|
|
1587
1624
|
releaseFieldLocks(sessionId);
|
|
1588
1625
|
}
|
|
1589
1626
|
}
|
|
@@ -1684,7 +1721,12 @@ export function EditorShell({
|
|
|
1684
1721
|
|
|
1685
1722
|
// First switch view
|
|
1686
1723
|
if (selectedEntry.viewName !== viewName) {
|
|
1687
|
-
|
|
1724
|
+
// Avoid inserting a duplicate navigation entry; we'll explicitly move the
|
|
1725
|
+
// selected one to the front below
|
|
1726
|
+
switchView(selectedEntry.viewName, {
|
|
1727
|
+
skipConfirmation: true,
|
|
1728
|
+
skipNavigationHistory: true,
|
|
1729
|
+
});
|
|
1688
1730
|
}
|
|
1689
1731
|
|
|
1690
1732
|
// Then load item if it exists and is different from current
|
|
@@ -1706,7 +1748,12 @@ export function EditorShell({
|
|
|
1706
1748
|
language: selectedEntry.item.language,
|
|
1707
1749
|
version: selectedEntry.item.version,
|
|
1708
1750
|
},
|
|
1709
|
-
{
|
|
1751
|
+
{
|
|
1752
|
+
addToBrowseHistory: false,
|
|
1753
|
+
skipViewChange: true,
|
|
1754
|
+
// Avoid inserting an extra nav entry; we move the selected one below
|
|
1755
|
+
skipNavigationHistory: true,
|
|
1756
|
+
},
|
|
1710
1757
|
);
|
|
1711
1758
|
} else {
|
|
1712
1759
|
console.log(`[QuickSwitcher] Same item, skipping reload`);
|
|
@@ -2400,6 +2447,8 @@ export function EditorShell({
|
|
|
2400
2447
|
isRefreshing,
|
|
2401
2448
|
activeSessions,
|
|
2402
2449
|
unlockField: async () => {
|
|
2450
|
+
console.log("[EditContext.unlockField] Clearing lockedField state");
|
|
2451
|
+
setLockedField(undefined); // Clear client-side lock state
|
|
2403
2452
|
await releaseFieldLocks(sessionId);
|
|
2404
2453
|
},
|
|
2405
2454
|
isCommandDisabled: <T extends CommandData>({
|
|
@@ -2705,6 +2754,10 @@ export function EditorShell({
|
|
|
2705
2754
|
focusedField,
|
|
2706
2755
|
setFocusedField: setFocusedFieldWithLock,
|
|
2707
2756
|
unlockField: async () => {
|
|
2757
|
+
console.log(
|
|
2758
|
+
"[FieldsEditContext.unlockField] Clearing lockedField state",
|
|
2759
|
+
);
|
|
2760
|
+
setLockedField(undefined); // Clear client-side lock state
|
|
2708
2761
|
await releaseFieldLocks(sessionId);
|
|
2709
2762
|
},
|
|
2710
2763
|
inlineEditingFieldElement,
|
|
@@ -241,27 +241,65 @@ export function getOperationsContext(
|
|
|
241
241
|
|
|
242
242
|
const ensureLock = useCallback(
|
|
243
243
|
async (field: FieldDescriptor): Promise<boolean> => {
|
|
244
|
-
|
|
245
|
-
|
|
244
|
+
console.log("[ensureLock] Called with field:", {
|
|
245
|
+
fieldId: field?.fieldId,
|
|
246
|
+
itemId: field?.item?.id,
|
|
247
|
+
language: field?.item?.language,
|
|
248
|
+
version: field?.item?.version,
|
|
249
|
+
currentLockedField: state.lockedField
|
|
250
|
+
? {
|
|
251
|
+
fieldId: state.lockedField.fieldId,
|
|
252
|
+
itemId: state.lockedField.item.id,
|
|
253
|
+
language: state.lockedField.item.language,
|
|
254
|
+
version: state.lockedField.item.version,
|
|
255
|
+
}
|
|
256
|
+
: null,
|
|
257
|
+
timestamp: new Date().toISOString(),
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
if (!field || !field.item) {
|
|
261
|
+
console.log(
|
|
262
|
+
"[ensureLock] Early return: field or field.item is missing",
|
|
263
|
+
);
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const isAlreadyLocked =
|
|
246
268
|
state.lockedField?.fieldId === field.fieldId &&
|
|
247
269
|
state.lockedField?.item.id === field.item.id &&
|
|
248
270
|
state.lockedField?.item.language === field.item.language &&
|
|
249
|
-
state.lockedField?.item.version === field.item.version
|
|
250
|
-
|
|
271
|
+
state.lockedField?.item.version === field.item.version;
|
|
272
|
+
|
|
273
|
+
if (isAlreadyLocked) {
|
|
274
|
+
console.log(
|
|
275
|
+
"[ensureLock] Field is already locked, returning true without lockField call",
|
|
276
|
+
);
|
|
251
277
|
return true;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
console.log(
|
|
281
|
+
"[ensureLock] Field is NOT locked, calling lockField service",
|
|
282
|
+
);
|
|
252
283
|
const result = await lockField(
|
|
253
284
|
field.item,
|
|
254
285
|
field.fieldId,
|
|
255
286
|
state.sessionId,
|
|
256
287
|
);
|
|
288
|
+
console.log("[ensureLock] lockField service returned:", {
|
|
289
|
+
resultType: result.type,
|
|
290
|
+
success: result.type === "success" ? result.data?.success : undefined,
|
|
291
|
+
});
|
|
292
|
+
|
|
257
293
|
if (result.type == "error") {
|
|
258
294
|
console.log("error locking field", result);
|
|
259
295
|
}
|
|
260
296
|
if (handleErrorResult(result, ui, state)) return false;
|
|
261
297
|
if (result.type == "success" && result.data.success) {
|
|
262
298
|
state.setLockedField(field);
|
|
299
|
+
console.log("[ensureLock] Successfully locked field, returning true");
|
|
263
300
|
return true;
|
|
264
301
|
}
|
|
302
|
+
console.log("[ensureLock] Failed to lock field, returning false");
|
|
265
303
|
return false;
|
|
266
304
|
},
|
|
267
305
|
[state, ui],
|
|
@@ -54,7 +54,7 @@ export function WebSocketMessages() {
|
|
|
54
54
|
"suggested-edit-updated": "bg-indigo-100 text-indigo-800",
|
|
55
55
|
"suggested-edit-deleted": "bg-red-100 text-red-800",
|
|
56
56
|
"update-quota": "bg-gray-100 text-gray-800",
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
"agent:run:closed": "bg-red-100 text-red-800",
|
|
59
59
|
"agent:run:start": "bg-green-100 text-green-800",
|
|
60
60
|
"agent:name:updated": "bg-blue-100 text-blue-800",
|
|
@@ -158,3 +158,7 @@ export function WebSocketMessages() {
|
|
|
158
158
|
</div>
|
|
159
159
|
);
|
|
160
160
|
}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
|
|
@@ -608,6 +608,14 @@ export function PageViewerFrame({
|
|
|
608
608
|
|
|
609
609
|
blockBlurEventRef.current = Date.now() + 500;
|
|
610
610
|
|
|
611
|
+
console.log("[PageViewerFrame] Attempting to focus field:", {
|
|
612
|
+
fieldId: fieldElement.getAttribute("data-fieldid"),
|
|
613
|
+
itemId: fieldElement.getAttribute("data-itemid"),
|
|
614
|
+
mode: editContextRef.current?.mode,
|
|
615
|
+
currentlyFocusedField: fieldsContextRef.current?.focusedField,
|
|
616
|
+
timestamp: new Date().toISOString(),
|
|
617
|
+
});
|
|
618
|
+
|
|
611
619
|
const hasLock =
|
|
612
620
|
editContextRef.current?.mode === "suggestions" ||
|
|
613
621
|
(await fieldsContextRef.current?.setFocusedField(
|
|
@@ -615,6 +623,11 @@ export function PageViewerFrame({
|
|
|
615
623
|
true,
|
|
616
624
|
));
|
|
617
625
|
|
|
626
|
+
console.log("[PageViewerFrame] Focus field result:", {
|
|
627
|
+
hasLock,
|
|
628
|
+
fieldId: fieldElement.getAttribute("data-fieldid"),
|
|
629
|
+
});
|
|
630
|
+
|
|
618
631
|
if (
|
|
619
632
|
hasLock &&
|
|
620
633
|
fieldsContextRef.current?.inlineEditingFieldElement !== fieldElement
|
|
@@ -629,8 +642,8 @@ export function PageViewerFrame({
|
|
|
629
642
|
fieldsContextRef.current?.setFocusedField(undefined, false);
|
|
630
643
|
fieldsContextRef.current?.setInlineEditingFieldElement(undefined);
|
|
631
644
|
// Release field locks when unfocusing field
|
|
632
|
-
if (editContextRef.current?.
|
|
633
|
-
|
|
645
|
+
if (editContextRef.current?.unlockField) {
|
|
646
|
+
editContextRef.current.unlockField(undefined as any);
|
|
634
647
|
}
|
|
635
648
|
}
|
|
636
649
|
}
|
|
@@ -52,49 +52,61 @@ export function openAiAgentForComment(
|
|
|
52
52
|
editContext.setShowAgentsPanel(true);
|
|
53
53
|
|
|
54
54
|
const initialMetadata: AgentMetadata = {
|
|
55
|
+
items: [
|
|
56
|
+
{
|
|
57
|
+
id:
|
|
58
|
+
(comment as any).mainItemId ||
|
|
59
|
+
editContext.currentItemDescriptor?.id!,
|
|
60
|
+
language: comment.language,
|
|
61
|
+
version: comment.version,
|
|
62
|
+
name: editContext.contentEditorItem?.name,
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
components:
|
|
66
|
+
editContext.selection && editContext.selection.length
|
|
67
|
+
? editContext.selection.map((componentId) => ({
|
|
68
|
+
componentId,
|
|
69
|
+
pageItem: {
|
|
70
|
+
id:
|
|
71
|
+
(comment as any).mainItemId ||
|
|
72
|
+
editContext.currentItemDescriptor?.id!,
|
|
73
|
+
language: comment.language,
|
|
74
|
+
version: comment.version,
|
|
75
|
+
name: editContext.contentEditorItem?.name,
|
|
76
|
+
},
|
|
77
|
+
}))
|
|
78
|
+
: undefined,
|
|
79
|
+
field:
|
|
80
|
+
comment.fieldId && comment.itemId
|
|
81
|
+
? {
|
|
82
|
+
fieldId: comment.fieldId,
|
|
83
|
+
fieldName: comment.fieldName,
|
|
84
|
+
item: {
|
|
85
|
+
id: comment.itemId,
|
|
86
|
+
language: comment.language,
|
|
87
|
+
version: comment.version,
|
|
88
|
+
name: comment.itemName,
|
|
89
|
+
},
|
|
90
|
+
}
|
|
91
|
+
: undefined,
|
|
92
|
+
comment: {
|
|
93
|
+
id: comment.id,
|
|
94
|
+
text: comment.text,
|
|
95
|
+
fieldName: comment.fieldName,
|
|
96
|
+
itemName: comment.itemName,
|
|
97
|
+
author: comment.author,
|
|
98
|
+
selectedText: selectedText,
|
|
99
|
+
rangeStart: comment.rangeStart,
|
|
100
|
+
rangeEnd: comment.rangeEnd,
|
|
101
|
+
},
|
|
55
102
|
additionalData: {
|
|
56
103
|
initialPrompt,
|
|
57
|
-
context: {
|
|
58
|
-
pages: [
|
|
59
|
-
{
|
|
60
|
-
id:
|
|
61
|
-
(comment as any).mainItemId ||
|
|
62
|
-
editContext.currentItemDescriptor?.id!,
|
|
63
|
-
language: comment.language,
|
|
64
|
-
version: comment.version,
|
|
65
|
-
name: editContext.contentEditorItem?.name,
|
|
66
|
-
} as any,
|
|
67
|
-
],
|
|
68
|
-
componentIds:
|
|
69
|
-
editContext.selection && editContext.selection.length
|
|
70
|
-
? editContext.selection
|
|
71
|
-
: undefined,
|
|
72
|
-
field:
|
|
73
|
-
comment.fieldId && comment.itemId
|
|
74
|
-
? {
|
|
75
|
-
fieldId: comment.fieldId,
|
|
76
|
-
itemId: comment.itemId,
|
|
77
|
-
name: comment.fieldName,
|
|
78
|
-
}
|
|
79
|
-
: undefined,
|
|
80
|
-
comment: {
|
|
81
|
-
id: comment.id,
|
|
82
|
-
text: comment.text,
|
|
83
|
-
fieldName: comment.fieldName,
|
|
84
|
-
itemName: comment.itemName,
|
|
85
|
-
author: comment.author,
|
|
86
|
-
selectedText: selectedText,
|
|
87
|
-
rangeStart: comment.rangeStart,
|
|
88
|
-
rangeEnd: comment.rangeEnd,
|
|
89
|
-
},
|
|
90
|
-
},
|
|
91
|
-
// Seed profile from editor settings if available
|
|
92
104
|
profileId:
|
|
93
105
|
editContext.editorSettings?.commentResolveProfileId || undefined,
|
|
94
106
|
profileName:
|
|
95
107
|
editContext.editorSettings?.commentResolveProfileName || undefined,
|
|
96
108
|
},
|
|
97
|
-
}
|
|
109
|
+
};
|
|
98
110
|
|
|
99
111
|
// Ask Agents UI to open a new terminal seeded with this metadata
|
|
100
112
|
try {
|