@alpaca-editor/core 1.0.4057 → 1.0.4061

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 (125) hide show
  1. package/dist/components/ui/badge.js.map +1 -1
  2. package/dist/components/ui/button.js.map +1 -1
  3. package/dist/components/ui/checkbox.js +1 -1
  4. package/dist/components/ui/checkbox.js.map +1 -1
  5. package/dist/components/ui/tooltip.js +2 -2
  6. package/dist/components/ui/tooltip.js.map +1 -1
  7. package/dist/config/config.js +7 -3
  8. package/dist/config/config.js.map +1 -1
  9. package/dist/config/types.d.ts +1 -0
  10. package/dist/editor/FieldListField.js +3 -2
  11. package/dist/editor/FieldListField.js.map +1 -1
  12. package/dist/editor/ai/AgentTerminal.js +0 -3
  13. package/dist/editor/ai/AgentTerminal.js.map +1 -1
  14. package/dist/editor/client/EditorClient.js +20 -6
  15. package/dist/editor/client/EditorClient.js.map +1 -1
  16. package/dist/editor/client/fieldModificationStore.d.ts +1 -0
  17. package/dist/editor/client/fieldModificationStore.js +19 -18
  18. package/dist/editor/client/fieldModificationStore.js.map +1 -1
  19. package/dist/editor/client/operations.js +1 -2
  20. package/dist/editor/client/operations.js.map +1 -1
  21. package/dist/editor/control-center/IndexOverview.js +278 -18
  22. package/dist/editor/control-center/IndexOverview.js.map +1 -1
  23. package/dist/editor/control-center/Status.js +1 -1
  24. package/dist/editor/control-center/Status.js.map +1 -1
  25. package/dist/editor/field-types/CheckboxEditor.js +1 -1
  26. package/dist/editor/field-types/CheckboxEditor.js.map +1 -1
  27. package/dist/editor/media-selector/AiImageSearch.js +2 -1
  28. package/dist/editor/media-selector/AiImageSearch.js.map +1 -1
  29. package/dist/editor/media-selector/TreeSelector.js +1 -1
  30. package/dist/editor/media-selector/TreeSelector.js.map +1 -1
  31. package/dist/editor/menubar/PageSelector.js +1 -1
  32. package/dist/editor/menubar/PageSelector.js.map +1 -1
  33. package/dist/editor/page-editor-chrome/useInlineAICompletion.js +1 -1
  34. package/dist/editor/page-editor-chrome/useInlineAICompletion.js.map +1 -1
  35. package/dist/editor/reviews/Comment.d.ts +5 -1
  36. package/dist/editor/reviews/Comment.js +64 -92
  37. package/dist/editor/reviews/Comment.js.map +1 -1
  38. package/dist/editor/reviews/CommentDisplayPopover.js +55 -49
  39. package/dist/editor/reviews/CommentDisplayPopover.js.map +1 -1
  40. package/dist/editor/reviews/CommentEditor.d.ts +20 -0
  41. package/dist/editor/reviews/CommentEditor.js +57 -0
  42. package/dist/editor/reviews/CommentEditor.js.map +1 -0
  43. package/dist/editor/reviews/CommentPopover.js +34 -43
  44. package/dist/editor/reviews/CommentPopover.js.map +1 -1
  45. package/dist/editor/reviews/CommentView.d.ts +19 -0
  46. package/dist/editor/reviews/CommentView.js +46 -0
  47. package/dist/editor/reviews/CommentView.js.map +1 -0
  48. package/dist/editor/reviews/Comments.js +28 -1
  49. package/dist/editor/reviews/Comments.js.map +1 -1
  50. package/dist/editor/reviews/SuggestionDisplayPopover.js +1 -1
  51. package/dist/editor/reviews/SuggestionDisplayPopover.js.map +1 -1
  52. package/dist/editor/services/aiService.d.ts +0 -8
  53. package/dist/editor/services/aiService.js +1 -24
  54. package/dist/editor/services/aiService.js.map +1 -1
  55. package/dist/editor/services/indexService.d.ts +12 -6
  56. package/dist/editor/services/indexService.js +33 -11
  57. package/dist/editor/services/indexService.js.map +1 -1
  58. package/dist/editor/services/reviewsService.d.ts +5 -1
  59. package/dist/editor/services/reviewsService.js +15 -0
  60. package/dist/editor/services/reviewsService.js.map +1 -1
  61. package/dist/editor/services/searchService.d.ts +17 -0
  62. package/dist/editor/services/searchService.js +25 -0
  63. package/dist/editor/services/searchService.js.map +1 -0
  64. package/dist/editor/sidebar/ViewSelector.js +7 -6
  65. package/dist/editor/sidebar/ViewSelector.js.map +1 -1
  66. package/dist/editor/ui/CenteredMessage.js +1 -1
  67. package/dist/editor/ui/CenteredMessage.js.map +1 -1
  68. package/dist/editor/ui/ItemSearch.js +1 -1
  69. package/dist/editor/ui/ItemSearch.js.map +1 -1
  70. package/dist/editor/ui/SimpleToolbar.js +1 -1
  71. package/dist/editor/ui/SimpleToolbar.js.map +1 -1
  72. package/dist/editor/ui/Spinner.d.ts +2 -1
  73. package/dist/editor/ui/Spinner.js +3 -2
  74. package/dist/editor/ui/Spinner.js.map +1 -1
  75. package/dist/editor/utils/keyboardNavigation.js +3 -1
  76. package/dist/editor/utils/keyboardNavigation.js.map +1 -1
  77. package/dist/page-wizard/steps/ImagesStep.js +2 -1
  78. package/dist/page-wizard/steps/ImagesStep.js.map +1 -1
  79. package/dist/revision.d.ts +2 -2
  80. package/dist/revision.js +2 -2
  81. package/dist/styles.css +76 -12
  82. package/dist/types.d.ts +61 -19
  83. package/package.json +1 -1
  84. package/src/components/ui/badge.tsx +1 -1
  85. package/src/components/ui/button.tsx +1 -1
  86. package/src/components/ui/checkbox.tsx +1 -1
  87. package/src/components/ui/tooltip.tsx +5 -3
  88. package/src/config/config.tsx +9 -3
  89. package/src/config/types.ts +1 -0
  90. package/src/editor/FieldListField.tsx +51 -32
  91. package/src/editor/ai/AgentTerminal.tsx +0 -6
  92. package/src/editor/client/EditorClient.tsx +47 -15
  93. package/src/editor/client/fieldModificationStore.ts +19 -19
  94. package/src/editor/client/operations.ts +1 -3
  95. package/src/editor/control-center/IndexOverview.tsx +590 -36
  96. package/src/editor/control-center/Status.tsx +1 -1
  97. package/src/editor/field-types/CheckboxEditor.tsx +1 -0
  98. package/src/editor/media-selector/AiImageSearch.tsx +2 -1
  99. package/src/editor/media-selector/TreeSelector.tsx +1 -1
  100. package/src/editor/menubar/PageSelector.tsx +1 -1
  101. package/src/editor/page-editor-chrome/useInlineAICompletion.tsx +1 -1
  102. package/src/editor/reviews/Comment.tsx +105 -244
  103. package/src/editor/reviews/CommentDisplayPopover.tsx +90 -219
  104. package/src/editor/reviews/CommentEditor.tsx +153 -0
  105. package/src/editor/reviews/CommentPopover.tsx +42 -70
  106. package/src/editor/reviews/CommentView.tsx +229 -0
  107. package/src/editor/reviews/Comments.tsx +33 -1
  108. package/src/editor/reviews/SuggestionDisplayPopover.tsx +1 -1
  109. package/src/editor/services/aiService.ts +1 -39
  110. package/src/editor/services/indexService.ts +58 -12
  111. package/src/editor/services/reviewsService.ts +34 -1
  112. package/src/editor/services/searchService.ts +45 -0
  113. package/src/editor/sidebar/ViewSelector.tsx +40 -27
  114. package/src/editor/ui/CenteredMessage.tsx +1 -1
  115. package/src/editor/ui/ItemSearch.tsx +1 -1
  116. package/src/editor/ui/SimpleToolbar.tsx +1 -1
  117. package/src/editor/ui/Spinner.tsx +8 -1
  118. package/src/editor/utils/keyboardNavigation.ts +3 -1
  119. package/src/page-wizard/steps/ImagesStep.tsx +2 -1
  120. package/src/revision.ts +2 -2
  121. package/src/types.ts +74 -20
  122. package/dist/editor/control-center/IndexSettings.d.ts +0 -5
  123. package/dist/editor/control-center/IndexSettings.js +0 -104
  124. package/dist/editor/control-center/IndexSettings.js.map +0 -1
  125. package/src/editor/control-center/IndexSettings.tsx +0 -266
@@ -375,7 +375,7 @@ ONLY provide the completion text (what comes after the user's text), never repea
375
375
  content: contentUpToCursor,
376
376
  },
377
377
  },
378
- { model: "gpt-4.1-nano" },
378
+ { model: "gpt-4.1-nano", sessionId: editContext.sessionId },
379
379
  { signal },
380
380
  );
381
381
 
@@ -7,25 +7,20 @@ import {
7
7
  resolveComment,
8
8
  unresolveComment,
9
9
  } from "../services/reviewsService";
10
- import { Button } from "../../components/ui/button";
11
- import { formatDate } from "../utils";
12
- import { SimpleIconButton } from "../ui/SimpleIconButton";
13
- import {
14
- Popover,
15
- PopoverContent,
16
- PopoverTrigger,
17
- } from "../../components/ui/popover";
18
- import { ProgressSpinner } from "primereact/progressspinner";
19
10
  import { useDebouncedCallback } from "use-debounce";
20
- import { ActionButton } from "../../components/ActionButton";
21
-
22
- export function Comment({ comment }: { comment: CommentType }) {
11
+ import { CommentView } from "./CommentView";
12
+ import { CommentEditor } from "./CommentEditor";
13
+
14
+ export function Comment({
15
+ comment,
16
+ availableTags = [],
17
+ }: {
18
+ comment: CommentType;
19
+ availableTags?: { label: string; color: string }[];
20
+ }) {
23
21
  const editContext = useEditContext();
24
- const [commentText, setCommentText] = useState(comment.text);
25
22
  const [isEditing, setIsEditing] = useState(false);
26
23
  const [isSaving, setIsSaving] = useState(false);
27
- const [deletePopoverOpen, setDeletePopoverOpen] = useState(false);
28
- const [resolvePopoverOpen, setResolvePopoverOpen] = useState(false);
29
24
  const ref = useRef<HTMLDivElement>(null);
30
25
 
31
26
  useEffect(() => {
@@ -35,38 +30,11 @@ export function Comment({ comment }: { comment: CommentType }) {
35
30
  const isSelected = comment.id === editContext?.selectedComment?.id;
36
31
 
37
32
  useEffect(() => {
38
- if (isSelected) {
39
- if (ref.current) {
40
- ref.current.scrollIntoView({ behavior: "smooth", block: "nearest" });
41
- }
33
+ if (isSelected && ref.current) {
34
+ ref.current.scrollIntoView({ behavior: "smooth", block: "nearest" });
42
35
  }
43
36
  }, [isSelected]);
44
37
 
45
- const renderContextInfo = () => {
46
- const showItemName =
47
- comment.itemId && comment.mainItemId !== comment.itemId;
48
-
49
- const showFieldName = comment.fieldId;
50
-
51
- if (!showItemName && !showFieldName) return null;
52
-
53
- return (
54
- <div className="mt-3 flex items-center border-t pt-3 text-xs">
55
- {showItemName && (
56
- <div className="text-2xs text-gray-500">{comment.itemName}</div>
57
- )}
58
-
59
- {showFieldName && showItemName && (
60
- <div className="text-2xs mx-2 text-gray-500">&gt;</div>
61
- )}
62
-
63
- {showFieldName && (
64
- <div className="text-2xs text-gray-500">{comment.fieldName}</div>
65
- )}
66
- </div>
67
- );
68
- };
69
-
70
38
  const canDelete =
71
39
  !comment.isNew && comment.author === editContext?.user?.name;
72
40
 
@@ -77,138 +45,95 @@ export function Comment({ comment }: { comment: CommentType }) {
77
45
 
78
46
  const canResolve = !comment.isNew && !editContext?.readonly;
79
47
 
80
- const getHiddenSystemPrompt = (comment: CommentType) => {
81
- let prompt =
82
- "Please make suggestions how to resolve a review comment. Ask the user whether you should apply the suggested changes.";
83
- if (comment.itemId) {
84
- prompt += "\n\nItemId: " + comment.itemId;
85
- }
86
- if (comment.itemName) {
87
- prompt += "\n\nItem name: " + comment.itemName;
88
- }
89
- if (comment.itemId) {
90
- prompt += "\n\nItemId: " + comment.itemId;
48
+ const setCommentsDebounced = useDebouncedCallback(() => {
49
+ if (!editContext?.setComments) return;
50
+ editContext.setComments([...editContext.comments]);
51
+ }, 300);
52
+
53
+ const handleSave = async (text: string, tags: string[]) => {
54
+ comment.text = text;
55
+ comment.tags = tags.join(",");
56
+ setIsSaving(true);
57
+
58
+ try {
59
+ const item = await editContext?.itemsRepository?.getItem({
60
+ id: comment.itemId,
61
+ language: comment.language,
62
+ version: comment.version,
63
+ });
64
+
65
+ if (item && comment.fieldId) {
66
+ comment.fieldValue = item.fields.find(
67
+ (f) => f.id === comment.fieldId,
68
+ )?.rawValue;
69
+ }
70
+
71
+ await createOrUpdateComment(comment);
72
+ setIsEditing(false);
73
+ } finally {
74
+ setIsSaving(false);
91
75
  }
92
- if (comment.fieldName) {
93
- prompt += "\n\nField name: " + comment.fieldName;
76
+ };
77
+
78
+ const handleCancel = () => {
79
+ if (comment.isNew) {
80
+ if (editContext?.setComments) {
81
+ editContext.setComments([
82
+ ...editContext.comments.filter((c) => c.id !== comment.id),
83
+ ]);
84
+ }
85
+ } else {
86
+ setIsEditing(false);
94
87
  }
95
- return prompt;
96
88
  };
97
89
 
98
- const renderHeader = () => {
99
- return (
100
- <>
101
- <div className="mb-3 flex items-start justify-between">
102
- <div>
103
- <div
104
- className="text-xs font-bold text-gray-900"
105
- title={comment.author}
106
- >
107
- {comment.authorDisplayName}
108
- </div>
109
- <div className="text-xs text-gray-500">
110
- {comment.created ? formatDate(new Date(comment.created)) : ""}
111
- </div>
112
- </div>
113
- <div className="text-xs text-gray-500">
114
- {!isEditing && canEdit && (
115
- <SimpleIconButton
116
- icon="pi pi-pencil"
117
- label="Edit"
118
- onClick={() => setIsEditing(true)}
119
- />
120
- )}
121
- {canDelete && (
122
- <Popover
123
- open={deletePopoverOpen}
124
- onOpenChange={setDeletePopoverOpen}
125
- >
126
- <PopoverTrigger asChild>
127
- <button
128
- className="pi pi-trash hover:bg-gray-5 cursor-pointer rounded-full p-[6px] text-xs"
129
- title="Delete"
130
- />
131
- </PopoverTrigger>
132
- <PopoverContent className="w-auto p-2" align="end">
133
- <Button
134
- variant="outline"
135
- onClick={async () => {
136
- await deleteComment(comment);
137
- setDeletePopoverOpen(false);
138
- }}
139
- >
140
- Delete
141
- </Button>
142
- </PopoverContent>
143
- </Popover>
144
- )}
145
- {canResolve && !comment.isResolved && (
146
- <SimpleIconButton
147
- icon="pi pi-check"
148
- label="Resolve"
149
- onClick={async () => {
150
- await resolveComment(comment);
151
- }}
152
- />
153
- )}
154
- {comment.isResolved && (
155
- <Popover
156
- open={resolvePopoverOpen}
157
- onOpenChange={setResolvePopoverOpen}
158
- >
159
- <PopoverTrigger asChild>
160
- <i
161
- className="pi pi-check cursor-pointer px-1 text-xs text-green-500"
162
- style={{ fontWeight: "bold" }}
163
- title={
164
- "Resolved by " +
165
- comment.resolvedBy +
166
- " (" +
167
- formatDate(new Date(comment.resolvedDate!)) +
168
- ")"
169
- }
170
- />
171
- </PopoverTrigger>
172
- <PopoverContent className="w-auto p-2" align="end">
173
- <Button
174
- variant="outline"
175
- onClick={async () => {
176
- await unresolveComment(comment);
177
- setResolvePopoverOpen(false);
178
- }}
179
- >
180
- Unresolve
181
- </Button>
182
- </PopoverContent>
183
- </Popover>
184
- )}
185
- {canResolve && !comment.isResolved && (
186
- <SimpleIconButton
187
- icon="pi pi-sparkles"
188
- label="AI"
189
- onClick={async (event) => {
190
- // editContext?.showAiPopup(event as any, {
191
- // initialPrompt:
192
- // 'Please help me resolve this comment: "' +
193
- // comment.text +
194
- // '"',
195
- // hiddenSystemPrompt: getHiddenSystemPrompt(comment),
196
- // });
197
- }}
198
- />
199
- )}
200
- </div>
201
- </div>
202
- </>
203
- );
90
+ const handleDelete = async () => {
91
+ await deleteComment(comment);
204
92
  };
205
93
 
206
- const setCommentsDebounced = useDebouncedCallback(() => {
207
- if (!editContext?.setComments) return;
208
- editContext.setComments([...editContext.comments]);
209
- }, 300);
94
+ const handleResolve = async () => {
95
+ await resolveComment(comment);
96
+ };
210
97
 
211
- return !isEditing ? (
98
+ const handleUnresolve = async () => {
99
+ await unresolveComment(comment);
100
+ };
101
+
102
+ const handleAiAction = () => {
103
+ // TODO: Implement AI action
104
+ // editContext?.showAiPopup(event as any, {
105
+ // initialPrompt:
106
+ // 'Please help me resolve this comment: "' +
107
+ // comment.text +
108
+ // '"',
109
+ // hiddenSystemPrompt: getHiddenSystemPrompt(comment),
110
+ // });
111
+ };
112
+
113
+ if (isEditing) {
114
+ return (
115
+ <div ref={ref} className="mb-3 rounded-lg bg-white p-3 shadow-sm">
116
+ <CommentEditor
117
+ initialText={comment.text}
118
+ onSave={handleSave}
119
+ onCancel={handleCancel}
120
+ isSaving={isSaving}
121
+ availableTags={availableTags}
122
+ selectedTags={
123
+ comment.tags
124
+ ?.split(",")
125
+ .map((t) => t.trim())
126
+ .filter(Boolean) || []
127
+ }
128
+ placeholder="Add a comment..."
129
+ submitLabel={comment.isNew ? "Comment" : "Save"}
130
+ showTagSelector={false} // Tags not shown in sidebar editor for now
131
+ />
132
+ </div>
133
+ );
134
+ }
135
+
136
+ return (
212
137
  <div
213
138
  ref={ref}
214
139
  key={comment.id}
@@ -235,82 +160,18 @@ export function Comment({ comment }: { comment: CommentType }) {
235
160
  }
236
161
  }}
237
162
  >
238
- {renderHeader()}
239
- <div className="text-sm whitespace-pre-wrap text-gray-700">
240
- {comment.text}
241
- </div>
242
- {renderContextInfo()}
243
- </div>
244
- ) : (
245
- <div key="new-comment" className="mb-3 rounded-lg bg-white p-3 shadow-sm">
246
- {renderHeader()}
247
- <textarea
248
- className="mt-2 min-h-[100px] w-full rounded border border-gray-200 p-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
249
- placeholder="Add a comment..."
250
- value={commentText}
251
- onChange={async (e) => {
252
- if (!editContext) return;
253
- setCommentText(e.target.value);
254
-
255
- setCommentsDebounced();
256
- }}
257
- autoFocus
163
+ <CommentView
164
+ comment={comment}
165
+ canEdit={canEdit}
166
+ canDelete={canDelete}
167
+ canResolve={canResolve}
168
+ availableTags={availableTags}
169
+ onEdit={() => setIsEditing(true)}
170
+ onDelete={handleDelete}
171
+ onResolve={handleResolve}
172
+ onUnresolve={handleUnresolve}
173
+ onAiAction={handleAiAction}
258
174
  />
259
- {isSaving && (
260
- <div className="flex-wra mt-1 flex justify-end gap-2">
261
- <div className="flex items-center gap-2 text-xs text-gray-500">
262
- <ProgressSpinner className="h-4 w-4" />
263
- Saving...
264
- </div>
265
- </div>
266
- )}
267
- {!isSaving && (
268
- <div className="mt-1 flex flex-wrap justify-end gap-2">
269
- <ActionButton
270
- variant="outline"
271
- onClick={() => {
272
- if (comment.isNew) {
273
- if (editContext?.setComments) {
274
- editContext.setComments([
275
- ...editContext.comments.filter((c) => c.id !== comment.id),
276
- ]);
277
- }
278
- } else {
279
- setIsEditing(false);
280
- }
281
- }}
282
- >
283
- Cancel
284
- </ActionButton>
285
-
286
- <ActionButton
287
- className="tour-submit-comment-button"
288
- onClick={async () => {
289
- comment.text = commentText;
290
- setIsSaving(true);
291
- const item = await editContext?.itemsRepository?.getItem({
292
- id: comment.itemId,
293
- language: comment.language,
294
- version: comment.version,
295
- });
296
-
297
- if (item) {
298
- comment.fieldValue = item.fields.find(
299
- (f) => f.id === comment.fieldId,
300
- )?.rawValue;
301
- }
302
-
303
- await createOrUpdateComment(comment);
304
-
305
- setIsSaving(false);
306
- setIsEditing(false);
307
- }}
308
- >
309
- {comment.isNew ? "Comment" : "Save"}
310
- </ActionButton>
311
- </div>
312
- )}
313
- {renderContextInfo()}
314
175
  </div>
315
176
  );
316
177
  }