@alpaca-editor/core 1.0.4184 → 1.0.4186
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/AgentCard.d.ts +12 -0
- package/dist/agents-view/AgentCard.js +30 -0
- package/dist/agents-view/AgentCard.js.map +1 -0
- package/dist/agents-view/AgentsView.d.ts +2 -2
- package/dist/agents-view/AgentsView.js +102 -85
- package/dist/agents-view/AgentsView.js.map +1 -1
- package/dist/agents-view/ProfileAgentsGroup.d.ts +17 -0
- package/dist/agents-view/ProfileAgentsGroup.js +13 -0
- package/dist/agents-view/ProfileAgentsGroup.js.map +1 -0
- package/dist/components/ui/popover.d.ts +3 -3
- package/dist/config/config.js +8 -1
- package/dist/config/config.js.map +1 -1
- package/dist/editor/ConfirmationDialog.js.map +1 -1
- package/dist/editor/ImageEditButton.js.map +1 -1
- package/dist/editor/ai/AgentProfilesOverview.js +1 -1
- package/dist/editor/ai/AgentProfilesOverview.js.map +1 -1
- package/dist/editor/ai/Agents.js +6 -2
- package/dist/editor/ai/Agents.js.map +1 -1
- package/dist/editor/client/EditorShell.js +17 -0
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/ui/EditorChrome.js +1 -0
- package/dist/editor/client/ui/EditorChrome.js.map +1 -1
- package/dist/editor/commands/componentCommands.js +19 -1
- package/dist/editor/commands/componentCommands.js.map +1 -1
- package/dist/editor/field-types/DateTimeFieldEditor.js +1 -1
- package/dist/editor/field-types/DateTimeFieldEditor.js.map +1 -1
- package/dist/editor/page-editor-chrome/FrameMenu.js +7 -3
- package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +7 -28
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/reviews/Comment.js +56 -4
- package/dist/editor/reviews/Comment.js.map +1 -1
- package/dist/editor/reviews/CommentDisplayPopover.js.map +1 -1
- package/dist/editor/reviews/CommentPopover.js +1 -1
- package/dist/editor/reviews/CommentPopover.js.map +1 -1
- package/dist/editor/reviews/SuggestionDisplayPopover.js.map +1 -1
- package/dist/editor/services/agentService.d.ts +19 -0
- package/dist/editor/services/agentService.js +39 -0
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/aiService.d.ts +2 -0
- package/dist/editor/services/aiService.js.map +1 -1
- package/dist/editor/services/serviceHelper.d.ts +1 -0
- package/dist/editor/services/serviceHelper.js +58 -4
- package/dist/editor/services/serviceHelper.js.map +1 -1
- package/dist/editor/views/ParheliaView.d.ts +5 -0
- package/dist/editor/views/ParheliaView.js +136 -0
- package/dist/editor/views/ParheliaView.js.map +1 -0
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/styles.css +8 -6
- package/dist/tour/default-tour.js +24 -9
- package/dist/tour/default-tour.js.map +1 -1
- package/package.json +12 -8
- package/src/agents-view/AgentCard.tsx +162 -0
- package/src/agents-view/AgentsView.tsx +218 -253
- package/src/agents-view/ProfileAgentsGroup.tsx +123 -0
- package/src/config/config.tsx +10 -1
- package/src/editor/ConfirmationDialog.tsx +1 -1
- package/src/editor/ImageEditButton.tsx +4 -2
- package/src/editor/ai/AgentProfilesOverview.tsx +1 -2
- package/src/editor/ai/Agents.tsx +7 -2
- package/src/editor/client/EditorShell.tsx +18 -0
- package/src/editor/client/ui/EditorChrome.tsx +1 -0
- package/src/editor/commands/componentCommands.tsx +19 -1
- package/src/editor/field-types/DateTimeFieldEditor.tsx +5 -4
- package/src/editor/page-editor-chrome/FrameMenu.tsx +9 -3
- package/src/editor/page-viewer/PageViewerFrame.tsx +7 -36
- package/src/editor/reviews/Comment.tsx +85 -4
- package/src/editor/reviews/CommentDisplayPopover.tsx +2 -2
- package/src/editor/reviews/CommentPopover.tsx +2 -2
- package/src/editor/reviews/SuggestionDisplayPopover.tsx +1 -1
- package/src/editor/services/agentService.ts +77 -0
- package/src/editor/services/aiService.ts +4 -0
- package/src/editor/services/serviceHelper.ts +92 -28
- package/src/editor/views/ParheliaView.tsx +207 -0
- package/src/revision.ts +2 -2
- package/src/tour/default-tour.tsx +63 -48
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import {
|
|
3
|
+
Agent,
|
|
4
|
+
ProfileAgentsGroup as ProfileGroup,
|
|
5
|
+
} from "../editor/services/agentService";
|
|
6
|
+
import { ChevronDown, ChevronUp } from "lucide-react";
|
|
7
|
+
import { AgentCard } from "./AgentCard";
|
|
8
|
+
import { SecretAgentIcon } from "../editor/ui/Icons";
|
|
9
|
+
|
|
10
|
+
interface ProfileAgentsGroupProps {
|
|
11
|
+
profileGroup: ProfileGroup;
|
|
12
|
+
isExpanded: boolean;
|
|
13
|
+
isLoadingMore: boolean;
|
|
14
|
+
hasMore: boolean;
|
|
15
|
+
onToggle: () => void;
|
|
16
|
+
onLoadMore: () => void;
|
|
17
|
+
onAgentClick: (agent: Agent) => void;
|
|
18
|
+
onResumeAgent: (agent: Agent) => void;
|
|
19
|
+
onCloseAgent: (agentId: string, agentName: string) => void;
|
|
20
|
+
onDeleteAgent: (
|
|
21
|
+
agentId: string,
|
|
22
|
+
agentName: string,
|
|
23
|
+
event: React.MouseEvent,
|
|
24
|
+
) => void;
|
|
25
|
+
formatDateTime: (dateString: string) => string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function ProfileAgentsGroup({
|
|
29
|
+
profileGroup,
|
|
30
|
+
isExpanded,
|
|
31
|
+
isLoadingMore,
|
|
32
|
+
hasMore,
|
|
33
|
+
onToggle,
|
|
34
|
+
onLoadMore,
|
|
35
|
+
onAgentClick,
|
|
36
|
+
onResumeAgent,
|
|
37
|
+
onCloseAgent,
|
|
38
|
+
onDeleteAgent,
|
|
39
|
+
formatDateTime,
|
|
40
|
+
}: ProfileAgentsGroupProps) {
|
|
41
|
+
return (
|
|
42
|
+
<div className="rounded-lg border border-gray-200 bg-white shadow-sm">
|
|
43
|
+
{/* Group Header */}
|
|
44
|
+
<button
|
|
45
|
+
onClick={onToggle}
|
|
46
|
+
className="flex w-full items-center gap-3 bg-gray-50 p-3 text-left transition-colors hover:bg-gray-100"
|
|
47
|
+
>
|
|
48
|
+
{/* Profile Icon */}
|
|
49
|
+
<div className="flex-shrink-0">
|
|
50
|
+
{profileGroup.profileSvgIcon ? (
|
|
51
|
+
<div
|
|
52
|
+
className="flex h-6 w-6 items-center justify-center text-gray-500 [&>svg]:h-full [&>svg]:w-full"
|
|
53
|
+
dangerouslySetInnerHTML={{
|
|
54
|
+
__html: profileGroup.profileSvgIcon,
|
|
55
|
+
}}
|
|
56
|
+
/>
|
|
57
|
+
) : (
|
|
58
|
+
<SecretAgentIcon
|
|
59
|
+
size={24}
|
|
60
|
+
strokeWidth={1}
|
|
61
|
+
className="text-gray-500"
|
|
62
|
+
/>
|
|
63
|
+
)}
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
{/* Profile Name */}
|
|
67
|
+
<div className="min-w-0 flex-1">
|
|
68
|
+
<h3 className="truncate font-medium text-gray-900">
|
|
69
|
+
{profileGroup.profileName}
|
|
70
|
+
</h3>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
{/* Closed Agents Count Badge */}
|
|
74
|
+
<div className="flex-shrink-0 rounded-full bg-gray-200 px-3 py-1 text-xs font-medium text-gray-700">
|
|
75
|
+
{profileGroup.totalClosedCount} closed agent
|
|
76
|
+
{profileGroup.totalClosedCount !== 1 ? "s" : ""}
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
{/* Chevron Icon */}
|
|
80
|
+
<div className="flex-shrink-0 text-gray-500">
|
|
81
|
+
{isExpanded ? (
|
|
82
|
+
<ChevronUp className="size-5" strokeWidth={1} />
|
|
83
|
+
) : (
|
|
84
|
+
<ChevronDown className="size-5" strokeWidth={1} />
|
|
85
|
+
)}
|
|
86
|
+
</div>
|
|
87
|
+
</button>
|
|
88
|
+
|
|
89
|
+
{/* Expandable Content */}
|
|
90
|
+
{isExpanded && (
|
|
91
|
+
<div className="space-y-2 p-3">
|
|
92
|
+
{profileGroup.agents.map((agent) => (
|
|
93
|
+
<AgentCard
|
|
94
|
+
key={agent.id}
|
|
95
|
+
agent={agent}
|
|
96
|
+
onClick={onAgentClick}
|
|
97
|
+
onResume={onResumeAgent}
|
|
98
|
+
onClose={onCloseAgent}
|
|
99
|
+
onDelete={onDeleteAgent}
|
|
100
|
+
formatDateTime={formatDateTime}
|
|
101
|
+
/>
|
|
102
|
+
))}
|
|
103
|
+
|
|
104
|
+
{/* Load More Button */}
|
|
105
|
+
{hasMore && (
|
|
106
|
+
<div className="flex justify-center pt-2">
|
|
107
|
+
<button
|
|
108
|
+
onClick={(e) => {
|
|
109
|
+
e.stopPropagation();
|
|
110
|
+
onLoadMore();
|
|
111
|
+
}}
|
|
112
|
+
disabled={isLoadingMore}
|
|
113
|
+
className="rounded-lg border border-gray-300 bg-white px-6 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:opacity-50"
|
|
114
|
+
>
|
|
115
|
+
{isLoadingMore ? "Loading..." : "Load More"}
|
|
116
|
+
</button>
|
|
117
|
+
</div>
|
|
118
|
+
)}
|
|
119
|
+
</div>
|
|
120
|
+
)}
|
|
121
|
+
</div>
|
|
122
|
+
);
|
|
123
|
+
}
|
package/src/config/config.tsx
CHANGED
|
@@ -71,6 +71,8 @@ import { loadInsertOptions } from "../editor/services/editService";
|
|
|
71
71
|
import { getDefaultTourSteps } from "../tour/default-tour";
|
|
72
72
|
import { Translation } from "../editor/sidebar/Translations";
|
|
73
73
|
import { EditView } from "../editor/views/EditView";
|
|
74
|
+
import { ParheliaView } from "../editor/views/ParheliaView";
|
|
75
|
+
import { AnimatedSunIcon } from "../editor/ui/Icons";
|
|
74
76
|
import { InsertMenuTemplate } from "../editor/context-menu/InsertMenu";
|
|
75
77
|
|
|
76
78
|
import { Status } from "../editor/control-center/Status";
|
|
@@ -733,8 +735,15 @@ export const getConfiguration = (): EditorConfiguration => {
|
|
|
733
735
|
expandTreeNode: "bafb88a1-506a-4671-b47b-1947730d25f6",
|
|
734
736
|
},
|
|
735
737
|
},
|
|
736
|
-
defaultPinnedViews: ["ai", "content-editor"],
|
|
738
|
+
defaultPinnedViews: ["parhelia", "ai", "content-editor"],
|
|
737
739
|
views: [
|
|
740
|
+
// {
|
|
741
|
+
// name: "parhelia",
|
|
742
|
+
// title: "Parhelia",
|
|
743
|
+
// icon: <AnimatedSunIcon strokeWidth={1} />,
|
|
744
|
+
// defaultCenterPanelView: <ParheliaView />,
|
|
745
|
+
// hideViewSelector: false,
|
|
746
|
+
// },
|
|
738
747
|
{
|
|
739
748
|
name: "splash-screen",
|
|
740
749
|
title: "Splash Screen",
|
|
@@ -68,7 +68,7 @@ const ConfirmationDialog = forwardRef<
|
|
|
68
68
|
>
|
|
69
69
|
<DialogHeader className="space-y-0 px-6 pt-3 pb-2">
|
|
70
70
|
<DialogTitle className="text-lg font-semibold">
|
|
71
|
-
{props?.header || "Confirmation"}
|
|
71
|
+
{props?.header || ("Confirmation" as any)}
|
|
72
72
|
</DialogTitle>
|
|
73
73
|
</DialogHeader>
|
|
74
74
|
<div className="px-6 py-4">
|
|
@@ -85,7 +85,9 @@ export function ImageEditButton({
|
|
|
85
85
|
return (
|
|
86
86
|
<DropdownMenu open={showMenu} onOpenChange={setShowMenu}>
|
|
87
87
|
{triggerButton ? (
|
|
88
|
-
<DropdownMenuTrigger asChild>
|
|
88
|
+
<DropdownMenuTrigger asChild>
|
|
89
|
+
{triggerButton as any}
|
|
90
|
+
</DropdownMenuTrigger>
|
|
89
91
|
) : (
|
|
90
92
|
defaultTriggerButton
|
|
91
93
|
)}
|
|
@@ -99,7 +101,7 @@ export function ImageEditButton({
|
|
|
99
101
|
setShowMenu(false);
|
|
100
102
|
}}
|
|
101
103
|
>
|
|
102
|
-
{action.icon}
|
|
104
|
+
{action.icon as any}
|
|
103
105
|
{action.label}
|
|
104
106
|
</DropdownMenuItem>
|
|
105
107
|
))}
|
|
@@ -42,7 +42,7 @@ export const AgentProfilesOverview: React.FC<AgentProfilesOverviewProps> = ({
|
|
|
42
42
|
<button
|
|
43
43
|
key={profile.id}
|
|
44
44
|
onClick={() => onSelectProfile(profile.id)}
|
|
45
|
-
className="group flex flex-col gap-3 rounded-lg border border-gray-200 bg-white p-4 text-left transition-all hover:border-blue-300 hover:shadow-md
|
|
45
|
+
className="group flex flex-col gap-3 rounded-lg border border-gray-200 bg-white p-4 text-left transition-all hover:border-blue-300 hover:shadow-md"
|
|
46
46
|
data-testid="agent-profile-card"
|
|
47
47
|
data-profile-id={profile.id}
|
|
48
48
|
>
|
|
@@ -78,4 +78,3 @@ export const AgentProfilesOverview: React.FC<AgentProfilesOverviewProps> = ({
|
|
|
78
78
|
</div>
|
|
79
79
|
);
|
|
80
80
|
};
|
|
81
|
-
|
package/src/editor/ai/Agents.tsx
CHANGED
|
@@ -289,7 +289,7 @@ export const Agents = React.memo(function Agents({
|
|
|
289
289
|
}
|
|
290
290
|
}
|
|
291
291
|
if (message.type === "agent:run:start") {
|
|
292
|
-
const { agentId, agentName } = message.payload;
|
|
292
|
+
const { agentId, agentName, autoSelect } = message.payload;
|
|
293
293
|
|
|
294
294
|
if (!agentId || !agentName) {
|
|
295
295
|
console.warn(
|
|
@@ -320,7 +320,7 @@ export const Agents = React.memo(function Agents({
|
|
|
320
320
|
};
|
|
321
321
|
return updatedAgents;
|
|
322
322
|
} else {
|
|
323
|
-
// Add new agent to the array
|
|
323
|
+
// Add new agent to the array
|
|
324
324
|
const newAgent: Agent = {
|
|
325
325
|
id: agentId,
|
|
326
326
|
name: agentName,
|
|
@@ -332,6 +332,11 @@ export const Agents = React.memo(function Agents({
|
|
|
332
332
|
return [...prevAgents, newAgent];
|
|
333
333
|
}
|
|
334
334
|
});
|
|
335
|
+
|
|
336
|
+
// Auto-switch to the spawned agent if requested
|
|
337
|
+
if (autoSelect === true) {
|
|
338
|
+
setActiveAgentIdWithStorage(agentId);
|
|
339
|
+
}
|
|
335
340
|
} else if (message.type === "agent:info:updated") {
|
|
336
341
|
const { agentId, agentName, agentDescription } =
|
|
337
342
|
message.payload || {};
|
|
@@ -1518,6 +1518,24 @@ export function EditorShell({
|
|
|
1518
1518
|
switchView();
|
|
1519
1519
|
};
|
|
1520
1520
|
|
|
1521
|
+
// Listen for switch-view commands from agents via websocket
|
|
1522
|
+
useEffect(() => {
|
|
1523
|
+
const handleSwitchView = (message: { type: string; payload: any }) => {
|
|
1524
|
+
if (message.type === "switch-view" && message.payload?.viewName) {
|
|
1525
|
+
try {
|
|
1526
|
+
switchView(message.payload.viewName);
|
|
1527
|
+
} catch (error) {
|
|
1528
|
+
console.error("Error switching view:", error);
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
};
|
|
1532
|
+
|
|
1533
|
+
const unsubscribe = addSocketMessageListener(handleSwitchView);
|
|
1534
|
+
return () => {
|
|
1535
|
+
unsubscribe();
|
|
1536
|
+
};
|
|
1537
|
+
}, [addSocketMessageListener, switchView]);
|
|
1538
|
+
|
|
1521
1539
|
const [dialog, setDialog] = useState<ReactNode>(null);
|
|
1522
1540
|
|
|
1523
1541
|
const openDialog: OpenDialog = useCallback(
|
|
@@ -95,6 +95,9 @@ function getInsertCommand(
|
|
|
95
95
|
if (!item) return null;
|
|
96
96
|
if (!item.placeholders || item.placeholders.length === 0) return null;
|
|
97
97
|
if (editContext.mode === "suggestions") return null;
|
|
98
|
+
// Don't show insert for layout components when showLayoutComponents is disabled
|
|
99
|
+
if (item.layoutId && !editContext.showLayoutComponents) return null;
|
|
100
|
+
|
|
98
101
|
return {
|
|
99
102
|
id: "insert",
|
|
100
103
|
icon: <Plus size={defaultIconSize} />,
|
|
@@ -114,6 +117,10 @@ function getDuplicateCommand(
|
|
|
114
117
|
if (components.length !== 1) return null;
|
|
115
118
|
if (editContext.mode === "suggestions") return null;
|
|
116
119
|
|
|
120
|
+
const component = components[0];
|
|
121
|
+
// Don't show duplicate for layout components when showLayoutComponents is disabled
|
|
122
|
+
if (component.layoutId && !editContext.showLayoutComponents) return null;
|
|
123
|
+
|
|
117
124
|
return {
|
|
118
125
|
id: "duplicate",
|
|
119
126
|
icon: <Copy size={defaultIconSize} />,
|
|
@@ -205,6 +212,9 @@ async function getDesignCommand(
|
|
|
205
212
|
if (components.length !== 1 || isPlaceholder(components[0])) return null;
|
|
206
213
|
const component = components[0];
|
|
207
214
|
if (!component || !component.datasourceItem) return null;
|
|
215
|
+
// Don't show design for layout components when showLayoutComponents is disabled
|
|
216
|
+
if (component.layoutId && !editContext.showLayoutComponents) return null;
|
|
217
|
+
|
|
208
218
|
const item = await editContext.itemsRepository.getItem(
|
|
209
219
|
component.datasourceItem,
|
|
210
220
|
);
|
|
@@ -243,6 +253,9 @@ async function getLinkToMasterCommand(
|
|
|
243
253
|
): Promise<ComponentCommand | null> {
|
|
244
254
|
if (!components.length) return null;
|
|
245
255
|
if (editContext.page?.item?.masterLanguages?.length === 0) return null;
|
|
256
|
+
// Don't show for layout components when showLayoutComponents is disabled
|
|
257
|
+
if (components.some((c) => c.layoutId && !editContext.showLayoutComponents))
|
|
258
|
+
return null;
|
|
246
259
|
|
|
247
260
|
return getCheckboxCommand(
|
|
248
261
|
components,
|
|
@@ -304,6 +317,9 @@ async function getInheritChildrenFromMasterCommand(
|
|
|
304
317
|
if (editContext.page?.item?.masterLanguages?.length === 0) return null;
|
|
305
318
|
if (components.find((x) => !x.placeholders || x.placeholders.length === 0))
|
|
306
319
|
return null;
|
|
320
|
+
// Don't show for layout components when showLayoutComponents is disabled
|
|
321
|
+
if (components.some((c) => c.layoutId && !editContext.showLayoutComponents))
|
|
322
|
+
return null;
|
|
307
323
|
|
|
308
324
|
return getCheckboxCommand(
|
|
309
325
|
components,
|
|
@@ -345,7 +361,9 @@ function getDeleteCommand(
|
|
|
345
361
|
((!isPlaceholder(c) && !c.layoutId) ||
|
|
346
362
|
c.layoutId === editContext.page?.item.id) &&
|
|
347
363
|
!isLocked(c, editContext) &&
|
|
348
|
-
editContext.page?.item.canWriteItem
|
|
364
|
+
editContext.page?.item.canWriteItem &&
|
|
365
|
+
// When showLayoutComponents is disabled, layout components should not be editable
|
|
366
|
+
(editContext.showLayoutComponents || !c.layoutId),
|
|
349
367
|
);
|
|
350
368
|
|
|
351
369
|
if (applicableComponents.length === 0) return null;
|
|
@@ -177,9 +177,10 @@ export function DateTimeFieldEditor({
|
|
|
177
177
|
<PopoverTrigger asChild>
|
|
178
178
|
<Button
|
|
179
179
|
variant="outline"
|
|
180
|
+
size="sm"
|
|
180
181
|
data-empty={!date}
|
|
181
182
|
className={cn(
|
|
182
|
-
"bg-gray-5 justify-start
|
|
183
|
+
"bg-gray-5 justify-start px-2 text-left text-xs font-normal",
|
|
183
184
|
!date && "text-muted-foreground",
|
|
184
185
|
)}
|
|
185
186
|
disabled={readOnly}
|
|
@@ -205,7 +206,7 @@ export function DateTimeFieldEditor({
|
|
|
205
206
|
|
|
206
207
|
<div
|
|
207
208
|
className={cn(
|
|
208
|
-
"bg-gray-5 flex items-center justify-start gap-1 px-2 text-left text-xs font-normal",
|
|
209
|
+
"bg-gray-5 flex h-8 items-center justify-start gap-1 rounded-sm px-2 text-left text-xs font-normal",
|
|
209
210
|
!date && "text-muted-foreground",
|
|
210
211
|
)}
|
|
211
212
|
>
|
|
@@ -216,7 +217,7 @@ export function DateTimeFieldEditor({
|
|
|
216
217
|
<PopoverTrigger asChild>
|
|
217
218
|
<Button
|
|
218
219
|
variant="ghost"
|
|
219
|
-
className="bg-gray-5 h-8 w-12 p-
|
|
220
|
+
className="bg-gray-5 h-8 w-12 p-0 text-xs"
|
|
220
221
|
disabled={readOnly || !date}
|
|
221
222
|
>
|
|
222
223
|
{hours.toString().padStart(2, "0")}
|
|
@@ -249,7 +250,7 @@ export function DateTimeFieldEditor({
|
|
|
249
250
|
<PopoverTrigger asChild>
|
|
250
251
|
<Button
|
|
251
252
|
variant="ghost"
|
|
252
|
-
className="bg-gray-5 h-
|
|
253
|
+
className="bg-gray-5 h-8 w-12 p-0 text-xs"
|
|
253
254
|
disabled={readOnly || !date}
|
|
254
255
|
>
|
|
255
256
|
{minutes.toString().padStart(2, "0")}
|
|
@@ -186,7 +186,10 @@ export function FrameMenu({
|
|
|
186
186
|
loadCommands();
|
|
187
187
|
}, [component]);
|
|
188
188
|
|
|
189
|
-
|
|
189
|
+
// Determine if draggable - layout components should not be draggable when showLayoutComponents is disabled
|
|
190
|
+
const isLayoutReadonlyCheck =
|
|
191
|
+
component.layoutId && !editContext.showLayoutComponents;
|
|
192
|
+
const isDraggable = component.canBeMoved && !isLayoutReadonlyCheck;
|
|
190
193
|
|
|
191
194
|
const commandButtons = commands
|
|
192
195
|
.filter(
|
|
@@ -257,11 +260,14 @@ export function FrameMenu({
|
|
|
257
260
|
}
|
|
258
261
|
|
|
259
262
|
const isShared = component.isShared;
|
|
260
|
-
const isReadonly = editContext.mode === "preview" || compareView;
|
|
261
263
|
const isLayout = component.layoutId;
|
|
264
|
+
// Layout components should be read-only when showLayoutComponents is disabled
|
|
265
|
+
const isLayoutReadonly = isLayout && !editContext.showLayoutComponents;
|
|
266
|
+
const isReadonly =
|
|
267
|
+
editContext.mode === "preview" || compareView || isLayoutReadonly;
|
|
262
268
|
|
|
263
269
|
function getColor() {
|
|
264
|
-
if (isReadonly) return "readonly";
|
|
270
|
+
if (isReadonly && !isLayoutReadonly) return "readonly";
|
|
265
271
|
if (editContext?.mode === "suggestions") return "suggestions";
|
|
266
272
|
if (isLayout) return "layout";
|
|
267
273
|
if (isShared) return "shared";
|
|
@@ -487,18 +487,8 @@ export function PageViewerFrame({
|
|
|
487
487
|
|
|
488
488
|
let componentId = findNearestEditableComponentId(target as HTMLElement);
|
|
489
489
|
|
|
490
|
-
//
|
|
491
|
-
|
|
492
|
-
componentId &&
|
|
493
|
-
editContextRef.current &&
|
|
494
|
-
editContextRef.current.page &&
|
|
495
|
-
editContextRef.current.showLayoutComponents === false
|
|
496
|
-
) {
|
|
497
|
-
const comp = getComponentById(componentId, editContextRef.current.page);
|
|
498
|
-
if (comp?.layoutId) {
|
|
499
|
-
componentId = undefined;
|
|
500
|
-
}
|
|
501
|
-
}
|
|
490
|
+
// Layout components can still be selected even when showLayoutComponents is false
|
|
491
|
+
// They will be displayed in read-only mode
|
|
502
492
|
const currentOverlayName = editContextRef.current?.currentOverlay;
|
|
503
493
|
const isGeneratorOverlay = !!(
|
|
504
494
|
currentOverlayName &&
|
|
@@ -530,12 +520,7 @@ export function PageViewerFrame({
|
|
|
530
520
|
for (const el of all) {
|
|
531
521
|
const id = el.getAttribute("data-component-id");
|
|
532
522
|
if (!id) continue;
|
|
533
|
-
//
|
|
534
|
-
if (
|
|
535
|
-
editContextRef.current?.showLayoutComponents === false &&
|
|
536
|
-
getComponentById(id, page)?.layoutId
|
|
537
|
-
)
|
|
538
|
-
continue;
|
|
523
|
+
// Layout components are now selectable even when showLayoutComponents is false
|
|
539
524
|
orderedIds.push(id);
|
|
540
525
|
}
|
|
541
526
|
}
|
|
@@ -688,17 +673,8 @@ export function PageViewerFrame({
|
|
|
688
673
|
|
|
689
674
|
let componentId = findNearestEditableComponentId(target as HTMLElement);
|
|
690
675
|
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
editContextRef.current &&
|
|
694
|
-
editContextRef.current.page &&
|
|
695
|
-
editContextRef.current.showLayoutComponents === false
|
|
696
|
-
) {
|
|
697
|
-
const comp = getComponentById(componentId, editContextRef.current.page);
|
|
698
|
-
if (comp?.layoutId) {
|
|
699
|
-
componentId = undefined;
|
|
700
|
-
}
|
|
701
|
-
}
|
|
676
|
+
// Layout components can now be right-clicked even when showLayoutComponents is false
|
|
677
|
+
// Context menu will show limited/read-only actions
|
|
702
678
|
|
|
703
679
|
if (componentId) {
|
|
704
680
|
// Only change selection if right-clicking on a component that's not in the current selection
|
|
@@ -721,13 +697,8 @@ export function PageViewerFrame({
|
|
|
721
697
|
.map((id) => getComponentById(id, pageViewContextRef.current!.page!))
|
|
722
698
|
.filter((x) => x) as Component[];
|
|
723
699
|
|
|
724
|
-
//
|
|
725
|
-
|
|
726
|
-
editContextRef.current?.showLayoutComponents === false &&
|
|
727
|
-
selectedComponents.some((c) => c.layoutId)
|
|
728
|
-
) {
|
|
729
|
-
return;
|
|
730
|
-
}
|
|
700
|
+
// Context menu will now show for layout components even when showLayoutComponents is false
|
|
701
|
+
// Commands will be appropriately filtered/disabled
|
|
731
702
|
|
|
732
703
|
const iframeRect = iframe.getBoundingClientRect();
|
|
733
704
|
const adjustedEvent = new MouseEvent("contextmenu", {
|
|
@@ -12,6 +12,7 @@ import { openAiAgentForComment } from "./commentAi";
|
|
|
12
12
|
import { useDebouncedCallback } from "use-debounce";
|
|
13
13
|
import { CommentView } from "./CommentView";
|
|
14
14
|
import { CommentEditor } from "./CommentEditor";
|
|
15
|
+
import { toast } from "sonner";
|
|
15
16
|
|
|
16
17
|
export function Comment({
|
|
17
18
|
comment,
|
|
@@ -71,8 +72,28 @@ export function Comment({
|
|
|
71
72
|
)?.rawValue;
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
await createOrUpdateComment(comment);
|
|
75
|
+
const result = await createOrUpdateComment(comment);
|
|
76
|
+
|
|
77
|
+
if (result.type === "error" || result.type === "unauthorized") {
|
|
78
|
+
console.error("Failed to save comment:", result);
|
|
79
|
+
if (result.rawDetails) {
|
|
80
|
+
console.error(
|
|
81
|
+
"Full error details (including stack trace):\n",
|
|
82
|
+
result.rawDetails,
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
toast.error(
|
|
86
|
+
result.details || result.summary || "Failed to save comment",
|
|
87
|
+
);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
75
91
|
setIsEditing(false);
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.error("Failed to save comment:", error);
|
|
94
|
+
toast.error(
|
|
95
|
+
error instanceof Error ? error.message : "Failed to save comment",
|
|
96
|
+
);
|
|
76
97
|
} finally {
|
|
77
98
|
setIsSaving(false);
|
|
78
99
|
}
|
|
@@ -91,15 +112,75 @@ export function Comment({
|
|
|
91
112
|
};
|
|
92
113
|
|
|
93
114
|
const handleDelete = async () => {
|
|
94
|
-
|
|
115
|
+
try {
|
|
116
|
+
const result = await deleteComment(comment);
|
|
117
|
+
|
|
118
|
+
if (result.type === "error" || result.type === "unauthorized") {
|
|
119
|
+
console.error("Failed to delete comment:", result);
|
|
120
|
+
if (result.rawDetails) {
|
|
121
|
+
console.error(
|
|
122
|
+
"Full error details (including stack trace):\n",
|
|
123
|
+
result.rawDetails,
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
toast.error(
|
|
127
|
+
result.details || result.summary || "Failed to delete comment",
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.error("Failed to delete comment:", error);
|
|
132
|
+
toast.error(
|
|
133
|
+
error instanceof Error ? error.message : "Failed to delete comment",
|
|
134
|
+
);
|
|
135
|
+
}
|
|
95
136
|
};
|
|
96
137
|
|
|
97
138
|
const handleResolve = async () => {
|
|
98
|
-
|
|
139
|
+
try {
|
|
140
|
+
const result = await resolveComment(comment);
|
|
141
|
+
|
|
142
|
+
if (result.type === "error" || result.type === "unauthorized") {
|
|
143
|
+
console.error("Failed to resolve comment:", result);
|
|
144
|
+
if (result.rawDetails) {
|
|
145
|
+
console.error(
|
|
146
|
+
"Full error details (including stack trace):\n",
|
|
147
|
+
result.rawDetails,
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
toast.error(
|
|
151
|
+
result.details || result.summary || "Failed to resolve comment",
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
} catch (error) {
|
|
155
|
+
console.error("Failed to resolve comment:", error);
|
|
156
|
+
toast.error(
|
|
157
|
+
error instanceof Error ? error.message : "Failed to resolve comment",
|
|
158
|
+
);
|
|
159
|
+
}
|
|
99
160
|
};
|
|
100
161
|
|
|
101
162
|
const handleUnresolve = async () => {
|
|
102
|
-
|
|
163
|
+
try {
|
|
164
|
+
const result = await unresolveComment(comment);
|
|
165
|
+
|
|
166
|
+
if (result.type === "error" || result.type === "unauthorized") {
|
|
167
|
+
console.error("Failed to unresolve comment:", result);
|
|
168
|
+
if (result.rawDetails) {
|
|
169
|
+
console.error(
|
|
170
|
+
"Full error details (including stack trace):\n",
|
|
171
|
+
result.rawDetails,
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
toast.error(
|
|
175
|
+
result.details || result.summary || "Failed to unresolve comment",
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
} catch (error) {
|
|
179
|
+
console.error("Failed to unresolve comment:", error);
|
|
180
|
+
toast.error(
|
|
181
|
+
error instanceof Error ? error.message : "Failed to unresolve comment",
|
|
182
|
+
);
|
|
183
|
+
}
|
|
103
184
|
};
|
|
104
185
|
|
|
105
186
|
const handleAiAction = async () =>
|
|
@@ -109,9 +109,9 @@ export function CommentDisplayPopover({
|
|
|
109
109
|
}}
|
|
110
110
|
enableIframeClickDetection={true}
|
|
111
111
|
>
|
|
112
|
-
<PopoverTrigger asChild>{children}</PopoverTrigger>
|
|
112
|
+
<PopoverTrigger asChild>{children as any}</PopoverTrigger>
|
|
113
113
|
<PopoverContent
|
|
114
|
-
ref={contentRef}
|
|
114
|
+
ref={contentRef as any}
|
|
115
115
|
tabIndex={-1}
|
|
116
116
|
className="w-96 p-4"
|
|
117
117
|
side="bottom"
|
|
@@ -163,11 +163,11 @@ export function CommentPopover({
|
|
|
163
163
|
)}
|
|
164
164
|
{!position && (
|
|
165
165
|
<PopoverTrigger asChild>
|
|
166
|
-
{children ?? <MessageCirclePlus size={16} strokeWidth={1} />}
|
|
166
|
+
{(children ?? <MessageCirclePlus size={16} strokeWidth={1} />) as any}
|
|
167
167
|
</PopoverTrigger>
|
|
168
168
|
)}
|
|
169
169
|
<PopoverContent
|
|
170
|
-
ref={contentRef}
|
|
170
|
+
ref={contentRef as any}
|
|
171
171
|
tabIndex={-1}
|
|
172
172
|
className="w-96 p-4"
|
|
173
173
|
data-testid="add-comment-popover"
|
|
@@ -265,7 +265,7 @@ export function SuggestionDisplayPopover({
|
|
|
265
265
|
}}
|
|
266
266
|
enableIframeClickDetection={true}
|
|
267
267
|
>
|
|
268
|
-
<PopoverTrigger asChild>{children}</PopoverTrigger>
|
|
268
|
+
<PopoverTrigger asChild>{children as any}</PopoverTrigger>
|
|
269
269
|
<PopoverContent className="w-96 p-4" side="bottom" align="start">
|
|
270
270
|
<div className="space-y-3">
|
|
271
271
|
{/* Header */}
|