@alpaca-editor/core 1.0.4093 → 1.0.4095

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/dist/components/ui/input.js +1 -1
  2. package/dist/components/ui/popover.d.ts +3 -1
  3. package/dist/components/ui/popover.js +1 -1
  4. package/dist/components/ui/popover.js.map +1 -1
  5. package/dist/components/ui/select.js +5 -3
  6. package/dist/components/ui/select.js.map +1 -1
  7. package/dist/config/config.js +1 -9
  8. package/dist/config/config.js.map +1 -1
  9. package/dist/editor/Editor.js +1 -1
  10. package/dist/editor/Editor.js.map +1 -1
  11. package/dist/editor/FieldList.js +1 -1
  12. package/dist/editor/FieldList.js.map +1 -1
  13. package/dist/editor/FieldListField.js +9 -3
  14. package/dist/editor/FieldListField.js.map +1 -1
  15. package/dist/editor/ItemInfo.js +1 -1
  16. package/dist/editor/ItemInfo.js.map +1 -1
  17. package/dist/editor/LinkEditorDialog.js +6 -6
  18. package/dist/editor/LinkEditorDialog.js.map +1 -1
  19. package/dist/editor/ai/AgentTerminal.js +32 -3
  20. package/dist/editor/ai/AgentTerminal.js.map +1 -1
  21. package/dist/editor/ai/AiResponseMessage.js +2 -2
  22. package/dist/editor/ai/AiResponseMessage.js.map +1 -1
  23. package/dist/editor/control-center/setup-steps/AiSetupStep.js +251 -7
  24. package/dist/editor/control-center/setup-steps/AiSetupStep.js.map +1 -1
  25. package/dist/editor/field-types/DateFieldEditor.js +1 -1
  26. package/dist/editor/field-types/DateFieldEditor.js.map +1 -1
  27. package/dist/editor/field-types/DateTimeFieldEditor.js +1 -1
  28. package/dist/editor/field-types/DateTimeFieldEditor.js.map +1 -1
  29. package/dist/editor/field-types/DropLinkEditor.js +1 -1
  30. package/dist/editor/field-types/DropLinkEditor.js.map +1 -1
  31. package/dist/editor/field-types/DropListEditor.js +1 -1
  32. package/dist/editor/field-types/DropListEditor.js.map +1 -1
  33. package/dist/editor/field-types/InternalLinkFieldEditor.js +1 -1
  34. package/dist/editor/field-types/InternalLinkFieldEditor.js.map +1 -1
  35. package/dist/editor/field-types/LinkFieldEditor.js +2 -1
  36. package/dist/editor/field-types/LinkFieldEditor.js.map +1 -1
  37. package/dist/editor/field-types/TreeListEditor.js +75 -70
  38. package/dist/editor/field-types/TreeListEditor.js.map +1 -1
  39. package/dist/editor/menubar/PageSelector.js +2 -1
  40. package/dist/editor/menubar/PageSelector.js.map +1 -1
  41. package/dist/editor/page-editor-chrome/FrameMenu.js +2 -2
  42. package/dist/editor/page-editor-chrome/InlineEditor.js +8 -0
  43. package/dist/editor/page-editor-chrome/InlineEditor.js.map +1 -1
  44. package/dist/editor/page-editor-chrome/PictureEditorOverlay.js +8 -0
  45. package/dist/editor/page-editor-chrome/PictureEditorOverlay.js.map +1 -1
  46. package/dist/editor/page-viewer/DeviceToolbar.js +2 -1
  47. package/dist/editor/page-viewer/DeviceToolbar.js.map +1 -1
  48. package/dist/editor/page-viewer/EditorForm.js +1 -5
  49. package/dist/editor/page-viewer/EditorForm.js.map +1 -1
  50. package/dist/editor/page-viewer/PageViewerFrame.js +17 -0
  51. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  52. package/dist/editor/pageModel.d.ts +1 -0
  53. package/dist/editor/services/aiService.d.ts +1 -0
  54. package/dist/editor/services/aiService.js.map +1 -1
  55. package/dist/editor/ui/Splitter.d.ts +1 -0
  56. package/dist/editor/ui/Splitter.js +9 -4
  57. package/dist/editor/ui/Splitter.js.map +1 -1
  58. package/dist/page-wizard/steps/ComponentTypesSelector.js +1 -1
  59. package/dist/page-wizard/steps/ComponentTypesSelector.js.map +1 -1
  60. package/dist/page-wizard/steps/ContentStep.js +81 -69
  61. package/dist/page-wizard/steps/ContentStep.js.map +1 -1
  62. package/dist/page-wizard/utils/dataAccessor.js +11 -5
  63. package/dist/page-wizard/utils/dataAccessor.js.map +1 -1
  64. package/dist/revision.d.ts +2 -2
  65. package/dist/revision.js +2 -2
  66. package/dist/styles.css +12 -3
  67. package/package.json +1 -1
  68. package/src/components/ui/input.tsx +1 -1
  69. package/src/components/ui/popover.tsx +22 -15
  70. package/src/components/ui/select.tsx +44 -29
  71. package/src/config/config.tsx +0 -12
  72. package/src/editor/Editor.tsx +1 -1
  73. package/src/editor/FieldList.tsx +4 -1
  74. package/src/editor/FieldListField.tsx +10 -4
  75. package/src/editor/ItemInfo.tsx +1 -1
  76. package/src/editor/LinkEditorDialog.tsx +25 -19
  77. package/src/editor/ai/AgentTerminal.tsx +58 -28
  78. package/src/editor/ai/AiResponseMessage.tsx +4 -4
  79. package/src/editor/control-center/setup-steps/AiSetupStep.tsx +362 -40
  80. package/src/editor/field-types/DateFieldEditor.tsx +2 -1
  81. package/src/editor/field-types/DateTimeFieldEditor.tsx +1 -1
  82. package/src/editor/field-types/DropLinkEditor.tsx +8 -6
  83. package/src/editor/field-types/DropListEditor.tsx +11 -9
  84. package/src/editor/field-types/InternalLinkFieldEditor.tsx +1 -1
  85. package/src/editor/field-types/LinkFieldEditor.tsx +2 -1
  86. package/src/editor/field-types/TreeListEditor.tsx +178 -178
  87. package/src/editor/menubar/PageSelector.tsx +3 -3
  88. package/src/editor/page-editor-chrome/FrameMenu.tsx +1 -1
  89. package/src/editor/page-editor-chrome/InlineEditor.tsx +10 -0
  90. package/src/editor/page-editor-chrome/PictureEditorOverlay.tsx +11 -0
  91. package/src/editor/page-viewer/DeviceToolbar.tsx +9 -2
  92. package/src/editor/page-viewer/EditorForm.tsx +1 -6
  93. package/src/editor/page-viewer/PageViewerFrame.tsx +28 -0
  94. package/src/editor/pageModel.ts +1 -0
  95. package/src/editor/services/aiService.ts +2 -0
  96. package/src/editor/ui/Splitter.tsx +26 -2
  97. package/src/page-wizard/steps/ComponentTypesSelector.tsx +1 -1
  98. package/src/page-wizard/steps/ContentStep.tsx +129 -106
  99. package/src/page-wizard/utils/dataAccessor.ts +13 -5
  100. package/src/revision.ts +2 -2
@@ -7,7 +7,12 @@ import { useEditContext } from "../../client/editContext";
7
7
  import { ItemDescriptor } from "../../pageModel";
8
8
  import { getChildren } from "../../services/contentService";
9
9
  import type { ItemTreeNodeData } from "../../services/contentService";
10
- import { CheckCircle, RefreshCw, SparklesIcon, AlertCircle } from "lucide-react";
10
+ import {
11
+ CheckCircle,
12
+ RefreshCw,
13
+ SparklesIcon,
14
+ AlertCircle,
15
+ } from "lucide-react";
11
16
  import { contentItemId } from "../../../config/config";
12
17
 
13
18
  type StepState = "idle" | "checking" | "success" | "error";
@@ -32,20 +37,36 @@ export function AiSetupStep() {
32
37
  const [aiError, setAiError] = useState<string | null>(null);
33
38
  const [apiKey, setApiKey] = useState<string>("");
34
39
 
35
- const [editorSettingsItem, setEditorSettingsItem] = useState<ItemDescriptor | null>(null);
40
+ const [editorSettingsItem, setEditorSettingsItem] =
41
+ useState<ItemDescriptor | null>(null);
36
42
  const [containersError, setContainersError] = useState<string | null>(null);
37
43
  const requiredContainers = useMemo(
38
44
  () => [
39
45
  { name: "Ai Models", templateId: "e5f6a7b8-9c0d-1e2f-3a4b-5c6d7e8f9a0b" },
40
- { name: "Ai Endpoints", templateId: "4592f2e0-06e4-470e-9820-7fd4ea148e00" },
41
- { name: "Ai Profiles", templateId: "4298ab78-2aaa-4d5f-bb3a-0bd321b86063" },
42
- { name: "Ai Schemas", templateId: "5214a52b-6c45-4671-97f2-703fe24e3d09" },
46
+ {
47
+ name: "Ai Endpoints",
48
+ templateId: "4592f2e0-06e4-470e-9820-7fd4ea148e00",
49
+ },
50
+ {
51
+ name: "Ai Profiles",
52
+ templateId: "4298ab78-2aaa-4d5f-bb3a-0bd321b86063",
53
+ },
54
+ {
55
+ name: "Ai Schemas",
56
+ templateId: "5214a52b-6c45-4671-97f2-703fe24e3d09",
57
+ },
43
58
  { name: "Ai Quotas", templateId: "7a08ff28-70ed-459b-a7f2-db2a78d88f46" },
44
- { name: "AI Generators", templateId: "9430a3e9-7397-4598-9a55-2b263c927497" },
59
+ {
60
+ name: "AI Generators",
61
+ templateId: "9430a3e9-7397-4598-9a55-2b263c927497",
62
+ },
63
+ { name: "AI Tools", templateId: "7e3f9d9d-8e84-4e57-b12e-6e9c99d4fd11" },
45
64
  ],
46
65
  [],
47
66
  );
48
- const [containerStates, setContainerStates] = useState<Record<string, StepState>>({});
67
+ const [containerStates, setContainerStates] = useState<
68
+ Record<string, StepState>
69
+ >({});
49
70
  const [busyMap, setBusyMap] = useState<Record<string, boolean>>({});
50
71
 
51
72
  const userLang = editContext?.contentEditorItem?.language || "en";
@@ -85,6 +106,270 @@ export function AiSetupStep() {
85
106
  [editContext?.sessionId, userLang],
86
107
  );
87
108
 
109
+ // IDs for tool templates/fields
110
+ const AI_TOOLS_TEMPLATE_ID = "7e3f9d9d-8e84-4e57-b12e-6e9c99d4fd11"; // container
111
+ const AI_TOOL_TEMPLATE_ID = "a2e8a0d9-7b1f-4d1a-a2d8-8f3ea6d6f0b1"; // item template
112
+ const FIELD_FUNCTION_NAME_ID = "3d9f2b1a-9d44-4d26-8a1b-92f0fb4d3a2c";
113
+ const FIELD_LABEL_ID = "5a19f5a5-1d21-4b6a-9f83-6f3fc0b34b2e";
114
+ const FIELD_DESCRIPTION_ID = "6b2e4b8e-8a9f-4d8f-9f6e-1a2b3c4d5e6f";
115
+
116
+ const [toolsBusy, setToolsBusy] = useState(false);
117
+ const [toolsError, setToolsError] = useState<string | null>(null);
118
+
119
+ const ensureAiToolsAndGenerate = useCallback(async () => {
120
+ if (!editContext) return;
121
+ try {
122
+ setToolsBusy(true);
123
+ setToolsError(null);
124
+
125
+ // Resolve /Settings/Editor
126
+ const settingsItem = await resolvePathUnderContent([
127
+ "Settings",
128
+ "Editor",
129
+ ]);
130
+ if (!settingsItem)
131
+ throw new Error("Editor settings item not found. Create it first.");
132
+
133
+ // Ensure AI Tools container exists
134
+ const editorChildren = (await getChildren(
135
+ settingsItem.id,
136
+ editContext.sessionId!,
137
+ [],
138
+ false,
139
+ userLang,
140
+ "path",
141
+ )) as unknown as ItemTreeNodeData[];
142
+
143
+ let aiToolsParent = findByName(editorChildren, "AI Tools");
144
+ if (!aiToolsParent) {
145
+ const created = await editContext.operations.createItem(
146
+ settingsItem,
147
+ AI_TOOLS_TEMPLATE_ID,
148
+ "AI Tools",
149
+ );
150
+ if (!created) throw new Error("Failed to create 'AI Tools' container");
151
+ aiToolsParent = {
152
+ id: created.id,
153
+ name: "AI Tools",
154
+ displayName: "AI Tools",
155
+ thumbUrl: "",
156
+ previewUrl: "",
157
+ templateId: "",
158
+ icon: "",
159
+ hasChildren: false,
160
+ isComponent: false,
161
+ language: userLang,
162
+ version: 0,
163
+ hasLayout: false,
164
+ } as unknown as ItemTreeNodeData;
165
+ }
166
+
167
+ // Get existing tool items under AI Tools
168
+ const toolChildren = (await getChildren(
169
+ aiToolsParent.id,
170
+ editContext.sessionId!,
171
+ [],
172
+ false,
173
+ userLang,
174
+ "path",
175
+ )) as unknown as ItemTreeNodeData[];
176
+
177
+ const findChildByLabel = (label: string) =>
178
+ findByName(toolChildren, label);
179
+
180
+ // Known tool functions (aligned with backend function names)
181
+ const tools: {
182
+ functionName: string;
183
+ label: string;
184
+ description?: string;
185
+ }[] = [
186
+ {
187
+ functionName: "get-content",
188
+ label: "Get Content",
189
+ description: "Returns page content or selected components",
190
+ },
191
+ {
192
+ functionName: "edit-field",
193
+ label: "Edit Field",
194
+ description: "Edits a field on the page or datasource",
195
+ },
196
+ {
197
+ functionName: "suggest-field-edit",
198
+ label: "Suggest Field Edit",
199
+ description: "Suggests changes to a field's content",
200
+ },
201
+ {
202
+ functionName: "create-item",
203
+ label: "Create Item",
204
+ description: "Creates a new item using a template",
205
+ },
206
+ {
207
+ functionName: "load-item",
208
+ label: "Load Item",
209
+ description: "Loads an item for context",
210
+ },
211
+ {
212
+ functionName: "get-items",
213
+ label: "Get Items",
214
+ description: "Finds items by criteria",
215
+ },
216
+ {
217
+ functionName: "get-children",
218
+ label: "Get Children",
219
+ description: "Lists child items under a parent",
220
+ },
221
+ {
222
+ functionName: "get-insertoptions",
223
+ label: "Get Insert Options",
224
+ description: "Lists available insert templates for an item",
225
+ },
226
+ {
227
+ functionName: "add-component",
228
+ label: "Add Component",
229
+ description: "Adds a component to a placeholder",
230
+ },
231
+ {
232
+ functionName: "remove-component",
233
+ label: "Remove Component",
234
+ description: "Removes a component from the page",
235
+ },
236
+ {
237
+ functionName: "move-components",
238
+ label: "Move Components",
239
+ description: "Moves components between placeholders",
240
+ },
241
+ {
242
+ functionName: "get-placeholders",
243
+ label: "Get Placeholders",
244
+ description: "Lists placeholders for a component",
245
+ },
246
+ {
247
+ functionName: "get-component-props-and-placeholders",
248
+ label: "Get Component Props and Placeholders",
249
+ description: "Returns component prop schema and placeholders",
250
+ },
251
+ {
252
+ functionName: "search-content",
253
+ label: "Search Content",
254
+ description: "Searches content across the index",
255
+ },
256
+ {
257
+ functionName: "search-images",
258
+ label: "Search Images",
259
+ description: "Searches images for use in content",
260
+ },
261
+ {
262
+ functionName: "google-search",
263
+ label: "Google Search",
264
+ description: "Performs a web search",
265
+ },
266
+ {
267
+ functionName: "scrape-webpage",
268
+ label: "Scrape Webpage",
269
+ description: "Fetches a webpage and extracts content",
270
+ },
271
+ {
272
+ functionName: "edit-image",
273
+ label: "Edit Image",
274
+ description: "Uses AI to modify an image",
275
+ },
276
+ {
277
+ functionName: "get-picture-description",
278
+ label: "Get Picture Description",
279
+ description: "Describes an image",
280
+ },
281
+ {
282
+ functionName: "add-comment",
283
+ label: "Add Comment",
284
+ description: "Adds a comment to the page",
285
+ },
286
+ {
287
+ functionName: "get-comments",
288
+ label: "Get Comments",
289
+ description: "Lists comments on the page",
290
+ },
291
+ {
292
+ functionName: "get-suggestions",
293
+ label: "Get Suggestions",
294
+ description: "Provides AI suggestions",
295
+ },
296
+ ];
297
+
298
+ // Create or update tool items
299
+ for (const t of tools) {
300
+ let node = findChildByLabel(t.label);
301
+ if (!node) {
302
+ const created = await editContext.operations.createItem(
303
+ {
304
+ id: aiToolsParent.id,
305
+ language: userLang,
306
+ version: 0,
307
+ } as ItemDescriptor,
308
+ AI_TOOL_TEMPLATE_ID,
309
+ t.label,
310
+ );
311
+ if (!created) throw new Error(`Failed to create tool '${t.label}'`);
312
+ node = {
313
+ id: created.id,
314
+ name: t.label,
315
+ displayName: t.label,
316
+ thumbUrl: "",
317
+ previewUrl: "",
318
+ templateId: "",
319
+ icon: "",
320
+ hasChildren: false,
321
+ isComponent: false,
322
+ language: userLang,
323
+ version: 0,
324
+ hasLayout: false,
325
+ } as unknown as ItemTreeNodeData;
326
+ }
327
+
328
+ // Set Function Name
329
+ await editContext.operations.editField({
330
+ field: {
331
+ fieldId: FIELD_FUNCTION_NAME_ID,
332
+ item: { id: node.id, language: userLang, version: 0 },
333
+ },
334
+ value: t.functionName,
335
+ rawValue: t.functionName,
336
+ refresh: "delayed",
337
+ });
338
+
339
+ // Set Label
340
+ await editContext.operations.editField({
341
+ field: {
342
+ fieldId: FIELD_LABEL_ID,
343
+ item: { id: node.id, language: userLang, version: 0 },
344
+ },
345
+ value: t.label,
346
+ rawValue: t.label,
347
+ refresh: "delayed",
348
+ });
349
+
350
+ // Set Description
351
+ if (t.description) {
352
+ await editContext.operations.editField({
353
+ field: {
354
+ fieldId: FIELD_DESCRIPTION_ID,
355
+ item: { id: node.id, language: userLang, version: 0 },
356
+ },
357
+ value: t.description,
358
+ rawValue: t.description,
359
+ refresh: "delayed",
360
+ });
361
+ }
362
+ }
363
+
364
+ setAiState("success");
365
+ editContext.requestRefresh?.("immediate");
366
+ } catch (e: any) {
367
+ setToolsError(e?.message || "Failed to generate AI tools");
368
+ } finally {
369
+ setToolsBusy(false);
370
+ }
371
+ }, [editContext, resolvePathUnderContent, userLang]);
372
+
88
373
  const createAiEndpoint = useCallback(async () => {
89
374
  if (!aiProvider || !editContext) return;
90
375
  try {
@@ -243,7 +528,8 @@ export function AiSetupStep() {
243
528
  modelTemplateId,
244
529
  modelName,
245
530
  );
246
- if (!createdModel) throw new Error(`Failed to create model '${modelName}'`);
531
+ if (!createdModel)
532
+ throw new Error(`Failed to create model '${modelName}'`);
247
533
  modelNode = {
248
534
  id: createdModel.id,
249
535
  name: modelName,
@@ -300,7 +586,10 @@ export function AiSetupStep() {
300
586
  for (const rc of requiredContainers) initialStates[rc.name] = "checking";
301
587
  setContainerStates(initialStates);
302
588
 
303
- const settingsItem = await resolvePathUnderContent(["Settings", "Editor"]);
589
+ const settingsItem = await resolvePathUnderContent([
590
+ "Settings",
591
+ "Editor",
592
+ ]);
304
593
  if (!settingsItem) {
305
594
  setEditorSettingsItem(null);
306
595
  const errorMsg = "Editor settings item not found. Create it first.";
@@ -374,39 +663,54 @@ export function AiSetupStep() {
374
663
  {requiredContainers
375
664
  .filter((rc) => containerStates[rc.name] === "error")
376
665
  .map((rc) => (
377
- <div key={rc.name} className="flex items-center justify-between gap-2">
378
- <div className="flex items-center gap-2">
379
- {containerStates[rc.name] === "checking" ? (
380
- <RefreshCw strokeWidth={1} className="h-4 w-4 animate-spin text-amber-600" />
381
- ) : containerStates[rc.name] === "success" ? (
382
- <CheckCircle strokeWidth={1} className="h-4 w-4 text-green-600" />
383
- ) : (
384
- <AlertCircle strokeWidth={1} className="h-4 w-4 text-red-600" />
385
- )}
386
- <span className="text-sm text-gray-700">
387
- {containerStates[rc.name] === "checking"
388
- ? `Checking ${rc.name}...`
389
- : containerStates[rc.name] === "success"
390
- ? `${rc.name} present`
391
- : `${rc.name} missing`}
392
- </span>
393
- </div>
394
- {containerStates[rc.name] !== "success" && (
395
- <Button
396
- size="sm"
397
- onClick={() => createContainer(rc.name, rc.templateId)}
398
- disabled={!editorSettingsItem || !!busyMap[rc.name]}
399
- >
400
- {busyMap[rc.name] ? (
401
- <RefreshCw strokeWidth={1} className="h-4 w-4 animate-spin" />
666
+ <div
667
+ key={rc.name}
668
+ className="flex items-center justify-between gap-2"
669
+ >
670
+ <div className="flex items-center gap-2">
671
+ {containerStates[rc.name] === "checking" ? (
672
+ <RefreshCw
673
+ strokeWidth={1}
674
+ className="h-4 w-4 animate-spin text-amber-600"
675
+ />
676
+ ) : containerStates[rc.name] === "success" ? (
677
+ <CheckCircle
678
+ strokeWidth={1}
679
+ className="h-4 w-4 text-green-600"
680
+ />
402
681
  ) : (
403
- <CheckCircle strokeWidth={1} className="h-4 w-4" />
682
+ <AlertCircle
683
+ strokeWidth={1}
684
+ className="h-4 w-4 text-red-600"
685
+ />
404
686
  )}
405
- Fix
406
- </Button>
407
- )}
408
- </div>
409
- ))}
687
+ <span className="text-sm text-gray-700">
688
+ {containerStates[rc.name] === "checking"
689
+ ? `Checking ${rc.name}...`
690
+ : containerStates[rc.name] === "success"
691
+ ? `${rc.name} present`
692
+ : `${rc.name} missing`}
693
+ </span>
694
+ </div>
695
+ {containerStates[rc.name] !== "success" && (
696
+ <Button
697
+ size="sm"
698
+ onClick={() => createContainer(rc.name, rc.templateId)}
699
+ disabled={!editorSettingsItem || !!busyMap[rc.name]}
700
+ >
701
+ {busyMap[rc.name] ? (
702
+ <RefreshCw
703
+ strokeWidth={1}
704
+ className="h-4 w-4 animate-spin"
705
+ />
706
+ ) : (
707
+ <CheckCircle strokeWidth={1} className="h-4 w-4" />
708
+ )}
709
+ Fix
710
+ </Button>
711
+ )}
712
+ </div>
713
+ ))}
410
714
  </div>
411
715
  {containersError && (
412
716
  <div className="mt-2 rounded border border-yellow-200 bg-yellow-50 p-2 text-xs whitespace-pre-wrap text-yellow-800">
@@ -450,6 +754,24 @@ export function AiSetupStep() {
450
754
  Add endpoint
451
755
  </Button>
452
756
  </div>
757
+ <div className="mt-4 flex items-center gap-2">
758
+ <Button
759
+ size="sm"
760
+ variant="outline"
761
+ disabled={toolsBusy}
762
+ onClick={ensureAiToolsAndGenerate}
763
+ >
764
+ {toolsBusy ? (
765
+ <RefreshCw strokeWidth={1} className="h-4 w-4 animate-spin" />
766
+ ) : (
767
+ <CheckCircle strokeWidth={1} className="h-4 w-4" />
768
+ )}
769
+ Generate AI tool items
770
+ </Button>
771
+ {toolsError && (
772
+ <span className="text-xs text-red-600">{toolsError}</span>
773
+ )}
774
+ </div>
453
775
  {aiError && (
454
776
  <div className="mt-2 rounded border border-red-200 bg-red-50 p-2 text-xs whitespace-pre-wrap text-red-700">
455
777
  {aiError}
@@ -114,8 +114,9 @@ export function DateFieldEditor({
114
114
  <Button
115
115
  variant="outline"
116
116
  data-empty={!date}
117
+ size="sm"
117
118
  className={cn(
118
- "bg-gray-5 justify-start p-1 text-left text-xs font-normal",
119
+ "bg-gray-5 h-7.5 justify-start p-0 text-left text-xs font-normal",
119
120
  !date && "text-muted-foreground",
120
121
  )}
121
122
  disabled={readOnly}
@@ -250,7 +250,7 @@ export function DateTimeFieldEditor({
250
250
  <PopoverTrigger asChild>
251
251
  <Button
252
252
  variant="ghost"
253
- className="bg-gray-5 h-8 w-12 p-1 text-xs"
253
+ className="bg-gray-5 h-7.5 w-12 text-xs"
254
254
  disabled={readOnly || !date}
255
255
  >
256
256
  {minutes.toString().padStart(2, "0")}
@@ -42,11 +42,13 @@ export function DropLinkEditor({
42
42
  }, [field, editContext.sessionId]);
43
43
 
44
44
  // Convert ItemIdAndName[] to SelectOption[] - memoized to prevent recreation
45
- const selectOptions: SelectOption[] = useMemo(() =>
46
- lazyItems.map((item) => ({
47
- value: item.id,
48
- label: item.name,
49
- })), [lazyItems]
45
+ const selectOptions: SelectOption[] = useMemo(
46
+ () =>
47
+ lazyItems.map((item) => ({
48
+ value: item.id,
49
+ label: item.name,
50
+ })),
51
+ [lazyItems],
50
52
  );
51
53
 
52
54
  return (
@@ -61,7 +63,7 @@ export function DropLinkEditor({
61
63
  options={selectOptions}
62
64
  placeholder="Select"
63
65
  disabled={readOnly}
64
- className="md:w-14rem w-full"
66
+ className="md:w-14rem w-full rounded-sm"
65
67
  loading={lazyLoading}
66
68
  onLazyLoad={onLazyLoad}
67
69
  emptyMessage="No options available"
@@ -43,17 +43,19 @@ export function DropListEditor({
43
43
  }, [field, editContext.sessionId]);
44
44
 
45
45
  // Convert ItemIdAndName[] to SelectOption[] using name for both value and label - memoized
46
- const selectOptions: SelectOption[] = useMemo(() =>
47
- lazyItems.map((item) => ({
48
- value: item.name,
49
- label: item.name,
50
- })), [lazyItems]
46
+ const selectOptions: SelectOption[] = useMemo(
47
+ () =>
48
+ lazyItems.map((item) => ({
49
+ value: item.name,
50
+ label: item.name,
51
+ })),
52
+ [lazyItems],
51
53
  );
52
54
 
53
55
  // Find the current value or show unknown value - memoized
54
- const currentValue = useMemo(() =>
55
- lazyItems.find((o) => o.name === field.value)?.name || field.value,
56
- [lazyItems, field.value]
56
+ const currentValue = useMemo(
57
+ () => lazyItems.find((o) => o.name === field.value)?.name || field.value,
58
+ [lazyItems, field.value],
57
59
  );
58
60
 
59
61
  return (
@@ -68,7 +70,7 @@ export function DropListEditor({
68
70
  options={selectOptions}
69
71
  placeholder="Select"
70
72
  disabled={readOnly}
71
- className="md:w-14rem w-full"
73
+ className="md:w-14rem w-full rounded-sm"
72
74
  loading={lazyLoading}
73
75
  onLazyLoad={onLazyLoad}
74
76
  emptyMessage="No options available"
@@ -121,7 +121,7 @@ export function InternalLinkFieldEditor({
121
121
  <PopoverTrigger asChild disabled={readOnly}>
122
122
  <div
123
123
  className={classNames(
124
- "justiy-between focus-shadow bg-gray-5 flex cursor-pointer justify-between border p-1.5 text-xs",
124
+ "justiy-between focus-shadow bg-gray-5 flex cursor-pointer justify-between rounded-sm border p-1.5 text-xs",
125
125
  readOnly ? "cursor-default bg-gray-100" : "",
126
126
  )}
127
127
  >
@@ -6,6 +6,7 @@ import { Link, LinkEditorDialog } from "../LinkEditorDialog";
6
6
  import { useEditContext } from "../client/editContext";
7
7
  import { LinkField } from "../fieldTypes";
8
8
  import { classNames } from "primereact/utils";
9
+ import { Link as LinkIcon } from "lucide-react";
9
10
 
10
11
  export function LinkFieldEditor({
11
12
  field,
@@ -44,7 +45,7 @@ export function LinkFieldEditor({
44
45
  }}
45
46
  >
46
47
  <div>{field.value.url}</div>
47
- <i className="pi pi-link"></i>
48
+ <LinkIcon className="h-4 w-4" strokeWidth={1} />
48
49
  </div>
49
50
  {showDialog && (
50
51
  <LinkEditorDialog