@alpaca-editor/core 1.0.4104 → 1.0.4106
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/config/config.js +7 -0
- package/dist/config/config.js.map +1 -1
- package/dist/editor/MainLayout.js +1 -1
- package/dist/editor/MainLayout.js.map +1 -1
- package/dist/editor/Terminal.js +2 -2
- package/dist/editor/Terminal.js.map +1 -1
- package/dist/editor/ai/AgentTerminal.js +5 -3
- package/dist/editor/ai/AgentTerminal.js.map +1 -1
- package/dist/editor/ai/Agents.js +9 -1
- package/dist/editor/ai/Agents.js.map +1 -1
- package/dist/editor/ai/AiResponseMessage.js +4 -2
- package/dist/editor/ai/AiResponseMessage.js.map +1 -1
- package/dist/editor/client/EditorShell.js +2 -0
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/control-center/IndexOverview.js +51 -32
- package/dist/editor/control-center/IndexOverview.js.map +1 -1
- package/dist/editor/control-center/LatestFeedback.d.ts +1 -0
- package/dist/editor/control-center/LatestFeedback.js +134 -0
- package/dist/editor/control-center/LatestFeedback.js.map +1 -0
- package/dist/editor/control-center/WebSocketMessages.js +3 -3
- package/dist/editor/control-center/WebSocketMessages.js.map +1 -1
- package/dist/editor/field-types/richtext/contextMenuFactory.js +11 -0
- package/dist/editor/field-types/richtext/contextMenuFactory.js.map +1 -1
- package/dist/editor/media-selector/MediaFolderBrowser.js +2 -2
- package/dist/editor/media-selector/MediaFolderBrowser.js.map +1 -1
- package/dist/editor/menubar/ActiveUsers.js +3 -2
- package/dist/editor/menubar/ActiveUsers.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/EditControls.js +1 -2
- package/dist/editor/menubar/toolbar-sections/EditControls.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/ViewportControls.js +3 -2
- package/dist/editor/menubar/toolbar-sections/ViewportControls.js.map +1 -1
- package/dist/editor/reviews/Comment.js +12 -2
- package/dist/editor/reviews/Comment.js.map +1 -1
- package/dist/editor/reviews/CommentView.d.ts +3 -1
- package/dist/editor/reviews/CommentView.js +9 -6
- package/dist/editor/reviews/CommentView.js.map +1 -1
- package/dist/editor/reviews/Comments.js +64 -76
- package/dist/editor/reviews/Comments.js.map +1 -1
- package/dist/editor/reviews/SuggestedEdit.js +8 -6
- package/dist/editor/reviews/SuggestedEdit.js.map +1 -1
- package/dist/editor/reviews/SuggestionDisplayPopover.js +7 -5
- package/dist/editor/reviews/SuggestionDisplayPopover.js.map +1 -1
- package/dist/editor/services/reviewsService.d.ts +1 -0
- package/dist/editor/services/reviewsService.js +8 -0
- package/dist/editor/services/reviewsService.js.map +1 -1
- package/dist/editor/services/suggestedEditsService.d.ts +1 -0
- package/dist/editor/services/suggestedEditsService.js +8 -0
- package/dist/editor/services/suggestedEditsService.js.map +1 -1
- package/dist/editor/sidebar/Completions.js +2 -1
- package/dist/editor/sidebar/Completions.js.map +1 -1
- package/dist/editor/ui/Icons.d.ts +2 -1
- package/dist/editor/ui/Icons.js +2 -2
- package/dist/editor/ui/Icons.js.map +1 -1
- package/dist/editor/ui/SimpleTable.js +1 -1
- package/dist/editor/ui/SimpleTable.js.map +1 -1
- package/dist/editor/utils.d.ts +12 -1
- package/dist/editor/utils.js +60 -12
- package/dist/editor/utils.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/types.d.ts +4 -0
- package/package.json +1 -1
- package/src/config/config.tsx +7 -0
- package/src/editor/MainLayout.tsx +1 -1
- package/src/editor/Terminal.tsx +2 -2
- package/src/editor/ai/AgentTerminal.tsx +8 -20
- package/src/editor/ai/Agents.tsx +14 -2
- package/src/editor/ai/AiResponseMessage.tsx +7 -5
- package/src/editor/client/EditorShell.tsx +2 -0
- package/src/editor/control-center/IndexOverview.tsx +70 -35
- package/src/editor/control-center/LatestFeedback.tsx +198 -0
- package/src/editor/control-center/WebSocketMessages.tsx +3 -5
- package/src/editor/field-types/richtext/contextMenuFactory.tsx +14 -0
- package/src/editor/media-selector/MediaFolderBrowser.tsx +2 -2
- package/src/editor/menubar/ActiveUsers.tsx +4 -3
- package/src/editor/menubar/toolbar-sections/EditControls.tsx +2 -3
- package/src/editor/menubar/toolbar-sections/ViewportControls.tsx +19 -1
- package/src/editor/reviews/Comment.tsx +16 -1
- package/src/editor/reviews/CommentView.tsx +24 -24
- package/src/editor/reviews/Comments.tsx +122 -145
- package/src/editor/reviews/SuggestedEdit.tsx +16 -10
- package/src/editor/reviews/SuggestionDisplayPopover.tsx +14 -9
- package/src/editor/services/reviewsService.ts +10 -0
- package/src/editor/services/suggestedEditsService.ts +10 -0
- package/src/editor/sidebar/Completions.tsx +2 -1
- package/src/editor/ui/Icons.tsx +3 -0
- package/src/editor/ui/SimpleTable.tsx +2 -2
- package/src/editor/utils.ts +73 -15
- package/src/revision.ts +2 -2
- package/src/types.ts +4 -0
|
@@ -11,14 +11,16 @@ import {
|
|
|
11
11
|
PopoverContent,
|
|
12
12
|
PopoverTrigger,
|
|
13
13
|
} from "../../components/ui/popover";
|
|
14
|
+
import {
|
|
15
|
+
Tooltip,
|
|
16
|
+
TooltipContent,
|
|
17
|
+
TooltipTrigger,
|
|
18
|
+
} from "../../components/ui/tooltip";
|
|
14
19
|
import {
|
|
15
20
|
FileDiff,
|
|
16
|
-
SquarePen,
|
|
17
21
|
CheckCircle,
|
|
18
22
|
CheckCircle2,
|
|
19
|
-
MessageSquareMore,
|
|
20
23
|
Plus,
|
|
21
|
-
GitBranch,
|
|
22
24
|
Tags,
|
|
23
25
|
Lightbulb,
|
|
24
26
|
} from "lucide-react";
|
|
@@ -42,67 +44,70 @@ export function Comments() {
|
|
|
42
44
|
return [];
|
|
43
45
|
}
|
|
44
46
|
});
|
|
45
|
-
const [scope, setScope] = useState<"all" | "itemOnly">(() => {
|
|
46
|
-
try {
|
|
47
|
-
const raw =
|
|
48
|
-
typeof window !== "undefined"
|
|
49
|
-
? localStorage.getItem("editor.comments.scope")
|
|
50
|
-
: null;
|
|
51
|
-
return raw === "itemOnly" ? "itemOnly" : "all";
|
|
52
|
-
} catch {
|
|
53
|
-
return "all";
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
47
|
const availableTags = editContext?.availableCommentTags || [];
|
|
57
48
|
|
|
58
49
|
useEffect(() => {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
|
|
50
|
+
let cancelled = false;
|
|
51
|
+
|
|
52
|
+
const load = async () => {
|
|
53
|
+
// Base lists from context
|
|
54
|
+
const mainComments: CommentType[] = editContext?.comments || [];
|
|
55
|
+
const suggestedEdits: SuggestedEdit[] = editContext?.suggestedEdits || [];
|
|
56
|
+
|
|
57
|
+
// Filter out applied suggestions if hideAppliedSuggestions is true
|
|
58
|
+
const filteredSuggestedEdits = hideAppliedSuggestions
|
|
59
|
+
? suggestedEdits.filter((edit) => edit.status !== "applied")
|
|
60
|
+
: suggestedEdits;
|
|
63
61
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
? suggestedEdits.filter((edit) => edit.status !== "applied")
|
|
67
|
-
: suggestedEdits;
|
|
62
|
+
// Start with main page comments and suggestions
|
|
63
|
+
let allComments: CommentType[] = [...mainComments];
|
|
68
64
|
|
|
69
|
-
|
|
70
|
-
|
|
65
|
+
// Base page context
|
|
66
|
+
const basePageId = editContext?.currentItemDescriptor?.id;
|
|
71
67
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
68
|
+
// Combine with suggestions
|
|
69
|
+
let combined: FeedbackItem[] = [
|
|
70
|
+
...allComments,
|
|
71
|
+
...filteredSuggestedEdits,
|
|
72
|
+
];
|
|
77
73
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
74
|
+
// Only keep items whose mainItemId is the current page
|
|
75
|
+
if (basePageId) {
|
|
76
|
+
combined = combined.filter(
|
|
77
|
+
(item: any) => item.mainItemId === basePageId,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Apply tag filter to comments only (suggested edits do not have tags)
|
|
82
|
+
const tagFiltered = selectedTagsFilter.length
|
|
83
|
+
? combined.filter((item: any) => {
|
|
84
|
+
// Keep suggested edits
|
|
85
|
+
if ("oldValue" in item && "newValue" in item) return true;
|
|
86
|
+
const tags = (item.tags || "")
|
|
87
|
+
.split(",")
|
|
88
|
+
.map((t: string) => t.trim())
|
|
89
|
+
.filter(Boolean);
|
|
90
|
+
// OR logic: include if any selected tag matches
|
|
91
|
+
return selectedTagsFilter.some((t) => tags.includes(t));
|
|
92
|
+
})
|
|
81
93
|
: combined;
|
|
82
94
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
// OR logic: include if any selected tag matches
|
|
93
|
-
return selectedTagsFilter.some((t) => tags.includes(t));
|
|
94
|
-
})
|
|
95
|
-
: scoped;
|
|
95
|
+
// Sort by creation date
|
|
96
|
+
tagFiltered.sort(
|
|
97
|
+
(a, b) =>
|
|
98
|
+
new Date(b.created || "").getTime() -
|
|
99
|
+
new Date(a.created || "").getTime(),
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
if (!cancelled) setFeedbackItems(tagFiltered);
|
|
103
|
+
};
|
|
96
104
|
|
|
97
|
-
|
|
98
|
-
tagFiltered.sort(
|
|
99
|
-
(a, b) =>
|
|
100
|
-
new Date(b.created || "").getTime() -
|
|
101
|
-
new Date(a.created || "").getTime(),
|
|
102
|
-
);
|
|
105
|
+
load();
|
|
103
106
|
|
|
104
|
-
|
|
105
|
-
|
|
107
|
+
return () => {
|
|
108
|
+
cancelled = true;
|
|
109
|
+
};
|
|
110
|
+
}, [editContext, hideAppliedSuggestions, selectedTagsFilter]);
|
|
106
111
|
|
|
107
112
|
useEffect(() => {
|
|
108
113
|
try {
|
|
@@ -114,13 +119,6 @@ export function Comments() {
|
|
|
114
119
|
} catch {}
|
|
115
120
|
}, [selectedTagsFilter]);
|
|
116
121
|
|
|
117
|
-
useEffect(() => {
|
|
118
|
-
try {
|
|
119
|
-
if (typeof window !== "undefined")
|
|
120
|
-
localStorage.setItem("editor.comments.scope", scope);
|
|
121
|
-
} catch {}
|
|
122
|
-
}, [scope]);
|
|
123
|
-
|
|
124
122
|
// Tags are provided once via editContext.availableCommentTags
|
|
125
123
|
|
|
126
124
|
return (
|
|
@@ -158,17 +156,6 @@ export function Comments() {
|
|
|
158
156
|
editContext?.addComment();
|
|
159
157
|
}}
|
|
160
158
|
/>
|
|
161
|
-
<SimpleIconButton
|
|
162
|
-
selected={editContext?.showComments}
|
|
163
|
-
icon={
|
|
164
|
-
<MessageSquareMore size={16} strokeWidth={1} className="p-0.5" />
|
|
165
|
-
}
|
|
166
|
-
label="Show Comments"
|
|
167
|
-
onClick={() => {
|
|
168
|
-
editContext?.setShowComments((x) => !x);
|
|
169
|
-
}}
|
|
170
|
-
/>
|
|
171
|
-
|
|
172
159
|
<SimpleIconButton
|
|
173
160
|
selected={!!editContext?.showResolvedComments}
|
|
174
161
|
icon={<CheckCircle2 size={16} strokeWidth={1} className="p-0.5" />}
|
|
@@ -181,15 +168,7 @@ export function Comments() {
|
|
|
181
168
|
editContext?.setShowResolvedComments((x) => !x);
|
|
182
169
|
}}
|
|
183
170
|
/>
|
|
184
|
-
|
|
185
|
-
selected={editContext?.showSuggestedEdits}
|
|
186
|
-
icon={<Lightbulb size={16} strokeWidth={1} className="p-0.5" />}
|
|
187
|
-
label="Show Suggestions"
|
|
188
|
-
data-testid="show-suggestions-button"
|
|
189
|
-
onClick={() => {
|
|
190
|
-
editContext?.setShowSuggestedEdits((x) => !x);
|
|
191
|
-
}}
|
|
192
|
-
/>
|
|
171
|
+
|
|
193
172
|
{editContext?.showSuggestedEdits && (
|
|
194
173
|
<SimpleIconButton
|
|
195
174
|
selected={editContext?.showSuggestedEditsDiff}
|
|
@@ -221,77 +200,75 @@ export function Comments() {
|
|
|
221
200
|
}}
|
|
222
201
|
/>
|
|
223
202
|
<div className="ml-auto flex items-center gap-2">
|
|
224
|
-
<SimpleIconButton
|
|
225
|
-
selected={scope === "all"}
|
|
226
|
-
icon={<GitBranch size={16} strokeWidth={1} className="p-0.5" />}
|
|
227
|
-
label={
|
|
228
|
-
scope === "all"
|
|
229
|
-
? "Include Children (on)"
|
|
230
|
-
: "Include Children (off)"
|
|
231
|
-
}
|
|
232
|
-
onClick={() => setScope(scope === "all" ? "itemOnly" : "all")}
|
|
233
|
-
/>
|
|
234
|
-
|
|
235
203
|
{availableTags.length > 0 && (
|
|
236
|
-
<
|
|
237
|
-
<
|
|
238
|
-
<
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
204
|
+
<Tooltip delayDuration={500}>
|
|
205
|
+
<Popover>
|
|
206
|
+
<PopoverTrigger asChild>
|
|
207
|
+
<TooltipTrigger asChild>
|
|
208
|
+
<SimpleIconButton
|
|
209
|
+
showTooltip={false}
|
|
210
|
+
selected={selectedTagsFilter.length > 0}
|
|
211
|
+
icon={
|
|
212
|
+
<Tags size={16} strokeWidth={1} className="p-0.5" />
|
|
213
|
+
}
|
|
214
|
+
label={
|
|
215
|
+
selectedTagsFilter.length > 0
|
|
216
|
+
? `Tags (${selectedTagsFilter.length})`
|
|
217
|
+
: "Tags"
|
|
218
|
+
}
|
|
219
|
+
onClick={() => {}}
|
|
220
|
+
/>
|
|
221
|
+
</TooltipTrigger>
|
|
222
|
+
</PopoverTrigger>
|
|
223
|
+
<PopoverContent className="w-72 p-3" align="start">
|
|
224
|
+
<div className="mb-2 text-xs text-gray-600">
|
|
225
|
+
Filter by tags
|
|
226
|
+
</div>
|
|
227
|
+
<div className="flex flex-wrap gap-2">
|
|
228
|
+
{availableTags.map((tag) => {
|
|
229
|
+
const isSelected = selectedTagsFilter.includes(tag.label);
|
|
230
|
+
return (
|
|
231
|
+
<Button
|
|
232
|
+
key={tag.label}
|
|
233
|
+
type="button"
|
|
234
|
+
size="sm"
|
|
235
|
+
variant={isSelected ? "secondary" : "outline"}
|
|
236
|
+
className="h-6 px-2 text-xs"
|
|
237
|
+
onClick={() => {
|
|
238
|
+
setSelectedTagsFilter((prev) =>
|
|
239
|
+
prev.includes(tag.label)
|
|
240
|
+
? prev.filter((l) => l !== tag.label)
|
|
241
|
+
: [...prev, tag.label],
|
|
242
|
+
);
|
|
243
|
+
}}
|
|
244
|
+
style={{
|
|
245
|
+
borderColor: isSelected ? tag.color : undefined,
|
|
246
|
+
backgroundColor: isSelected
|
|
247
|
+
? tag.color + "22"
|
|
248
|
+
: undefined,
|
|
249
|
+
}}
|
|
250
|
+
>
|
|
251
|
+
{tag.label}
|
|
252
|
+
</Button>
|
|
253
|
+
);
|
|
254
|
+
})}
|
|
255
|
+
</div>
|
|
256
|
+
{selectedTagsFilter.length > 0 && (
|
|
257
|
+
<div className="mt-3 text-right">
|
|
256
258
|
<Button
|
|
257
|
-
key={tag.label}
|
|
258
|
-
type="button"
|
|
259
259
|
size="sm"
|
|
260
|
-
variant=
|
|
260
|
+
variant="ghost"
|
|
261
261
|
className="h-6 px-2 text-xs"
|
|
262
|
-
onClick={() =>
|
|
263
|
-
setSelectedTagsFilter((prev) =>
|
|
264
|
-
prev.includes(tag.label)
|
|
265
|
-
? prev.filter((l) => l !== tag.label)
|
|
266
|
-
: [...prev, tag.label],
|
|
267
|
-
);
|
|
268
|
-
}}
|
|
269
|
-
style={{
|
|
270
|
-
borderColor: isSelected ? tag.color : undefined,
|
|
271
|
-
backgroundColor: isSelected
|
|
272
|
-
? tag.color + "22"
|
|
273
|
-
: undefined,
|
|
274
|
-
}}
|
|
262
|
+
onClick={() => setSelectedTagsFilter([])}
|
|
275
263
|
>
|
|
276
|
-
|
|
264
|
+
Clear
|
|
277
265
|
</Button>
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
</
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
size="sm"
|
|
285
|
-
variant="ghost"
|
|
286
|
-
className="h-6 px-2 text-xs"
|
|
287
|
-
onClick={() => setSelectedTagsFilter([])}
|
|
288
|
-
>
|
|
289
|
-
Clear
|
|
290
|
-
</Button>
|
|
291
|
-
</div>
|
|
292
|
-
)}
|
|
293
|
-
</PopoverContent>
|
|
294
|
-
</Popover>
|
|
266
|
+
</div>
|
|
267
|
+
)}
|
|
268
|
+
</PopoverContent>
|
|
269
|
+
</Popover>
|
|
270
|
+
<TooltipContent>Filter by tags</TooltipContent>
|
|
271
|
+
</Tooltip>
|
|
295
272
|
)}
|
|
296
273
|
</div>
|
|
297
274
|
</SimpleToolbar>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SuggestedEdit as SuggestedEditType } from "../../types";
|
|
2
|
-
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
import React, { useEffect, useRef, useState } from "react";
|
|
3
3
|
import { useEditContext, useFieldsEditContext } from "../client/editContext";
|
|
4
4
|
import {
|
|
5
5
|
deleteSuggestedEdit,
|
|
@@ -100,21 +100,27 @@ export function SuggestedEditComponent({ edit }: { edit: SuggestedEditType }) {
|
|
|
100
100
|
|
|
101
101
|
// Render contextual info by retrieving item and field names from the loaded item.
|
|
102
102
|
const renderContextInfo = () => {
|
|
103
|
-
const
|
|
103
|
+
const pageName = editContext?.currentItemDescriptor?.name;
|
|
104
|
+
const itemName = item ? item.name : undefined;
|
|
104
105
|
const fieldName =
|
|
105
106
|
item && item.fields
|
|
106
107
|
? item.fields.find(
|
|
107
108
|
(f: { id: string; name?: string }) => f.id === edit.fieldId,
|
|
108
|
-
)?.name
|
|
109
|
-
:
|
|
110
|
-
|
|
109
|
+
)?.name || undefined
|
|
110
|
+
: undefined;
|
|
111
|
+
|
|
112
|
+
const segments = [pageName, itemName, fieldName].filter(
|
|
113
|
+
(x): x is string => !!x && x.length > 0,
|
|
114
|
+
);
|
|
115
|
+
if (segments.length === 0) return null;
|
|
111
116
|
return (
|
|
112
117
|
<div className="mt-3 flex items-center border-t pt-3 text-xs">
|
|
113
|
-
{
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
+
{segments.map((seg, idx) => (
|
|
119
|
+
<React.Fragment key={idx}>
|
|
120
|
+
{idx > 0 && <div className="text-2xs mx-2 text-gray-500">></div>}
|
|
121
|
+
<div className="text-2xs text-gray-500">{seg}</div>
|
|
122
|
+
</React.Fragment>
|
|
123
|
+
))}
|
|
118
124
|
</div>
|
|
119
125
|
);
|
|
120
126
|
};
|
|
@@ -208,23 +208,28 @@ export function SuggestionDisplayPopover({
|
|
|
208
208
|
};
|
|
209
209
|
|
|
210
210
|
const renderContextInfo = () => {
|
|
211
|
-
const
|
|
211
|
+
const pageName = editContext?.currentItemDescriptor?.name;
|
|
212
|
+
const itemName = item ? item.name : undefined;
|
|
212
213
|
const fieldName =
|
|
213
214
|
item && item.fields
|
|
214
215
|
? item.fields.find(
|
|
215
216
|
(f: { id: string; name?: string }) => f.id === suggestion.fieldId,
|
|
216
|
-
)?.name
|
|
217
|
-
:
|
|
217
|
+
)?.name || undefined
|
|
218
|
+
: undefined;
|
|
218
219
|
|
|
219
|
-
|
|
220
|
+
const segments = [pageName, itemName, fieldName].filter(
|
|
221
|
+
(x): x is string => !!x && x.length > 0,
|
|
222
|
+
);
|
|
223
|
+
if (segments.length === 0) return null;
|
|
220
224
|
|
|
221
225
|
return (
|
|
222
226
|
<div className="mt-3 flex items-center border-t pt-3 text-xs">
|
|
223
|
-
{
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
227
|
+
{segments.map((seg, idx) => (
|
|
228
|
+
<React.Fragment key={idx}>
|
|
229
|
+
{idx > 0 && <div className="mx-2 text-xs text-gray-500">></div>}
|
|
230
|
+
<div className="text-xs text-gray-500">{seg}</div>
|
|
231
|
+
</React.Fragment>
|
|
232
|
+
))}
|
|
228
233
|
</div>
|
|
229
234
|
);
|
|
230
235
|
};
|
|
@@ -12,6 +12,16 @@ export function getComments(itemId: string, language: string, version: number) {
|
|
|
12
12
|
);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
// Latest comments across the system, already filtered by backend for user access.
|
|
16
|
+
export function getLatestComments(take?: number) {
|
|
17
|
+
const params = new URLSearchParams();
|
|
18
|
+
if (take && take > 0) params.set("take", take.toString());
|
|
19
|
+
const query = params.toString();
|
|
20
|
+
return get<Comment[]>(
|
|
21
|
+
`/alpaca/editor/comments/latest${query ? `?${query}` : ""}`,
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
15
25
|
export function resolveComment(comment: Comment) {
|
|
16
26
|
return post(`/alpaca/editor/comments/resolve?commentId=${comment.id}`, {});
|
|
17
27
|
}
|
|
@@ -21,6 +21,16 @@ export function getSuggestedEdits(
|
|
|
21
21
|
);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
// Latest suggested edits across the system, already filtered by backend for user access.
|
|
25
|
+
export function getLatestSuggestedEdits(take?: number) {
|
|
26
|
+
const params = new URLSearchParams();
|
|
27
|
+
if (take && take > 0) params.set("take", take.toString());
|
|
28
|
+
const query = params.toString();
|
|
29
|
+
return get<SuggestedEdit[]>(
|
|
30
|
+
`/alpaca/editor/suggested-edits/latest${query ? `?${query}` : ""}`,
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
24
34
|
/**
|
|
25
35
|
* Retrieves a single suggested edit by its unique identifier.
|
|
26
36
|
*/
|
|
@@ -4,6 +4,7 @@ import { Switch } from "../../components/ui/switch";
|
|
|
4
4
|
import { Button } from "../../components/ui/button";
|
|
5
5
|
import { Badge } from "../../components/ui/badge";
|
|
6
6
|
import { Loader2, RefreshCw, FileText } from "lucide-react";
|
|
7
|
+
import { formatTime } from "../utils";
|
|
7
8
|
|
|
8
9
|
import {
|
|
9
10
|
generatePageContext,
|
|
@@ -120,7 +121,7 @@ export function Completions() {
|
|
|
120
121
|
{pageContext.abstract}
|
|
121
122
|
</p>
|
|
122
123
|
<div className="text-xs text-gray-400">
|
|
123
|
-
Generated: {pageContext.lastGenerated
|
|
124
|
+
{`Generated: ${formatTime(pageContext.lastGenerated)}`}
|
|
124
125
|
</div>
|
|
125
126
|
</div>
|
|
126
127
|
) : (
|
package/src/editor/ui/Icons.tsx
CHANGED
|
@@ -891,10 +891,12 @@ export function SecretAgentIcon({
|
|
|
891
891
|
title,
|
|
892
892
|
strokeWidth = 1,
|
|
893
893
|
size = 20,
|
|
894
|
+
className,
|
|
894
895
|
}: {
|
|
895
896
|
title?: string;
|
|
896
897
|
strokeWidth?: number;
|
|
897
898
|
size?: number;
|
|
899
|
+
className?: string;
|
|
898
900
|
}) {
|
|
899
901
|
return (
|
|
900
902
|
<svg
|
|
@@ -909,6 +911,7 @@ export function SecretAgentIcon({
|
|
|
909
911
|
strokeLinejoin="round"
|
|
910
912
|
role="img"
|
|
911
913
|
aria-label={title}
|
|
914
|
+
className={className}
|
|
912
915
|
>
|
|
913
916
|
<path d="M3 10h18" />
|
|
914
917
|
<path d="M7 10l2-5h6l2 5" />
|
|
@@ -23,10 +23,10 @@ export function SimpleTable<T>({
|
|
|
23
23
|
}) {
|
|
24
24
|
return (
|
|
25
25
|
<table className="text-surface min-w-full table-auto text-left text-xs font-light">
|
|
26
|
-
<thead className="border-b border-neutral-200
|
|
26
|
+
<thead className="border-b border-neutral-200">
|
|
27
27
|
<tr>
|
|
28
28
|
{columns.map((col, index) => (
|
|
29
|
-
<th key={index} className="px-1.5 py-1.5">
|
|
29
|
+
<th key={index} className="px-1.5 py-1.5 font-medium">
|
|
30
30
|
{col.header}
|
|
31
31
|
</th>
|
|
32
32
|
))}
|
package/src/editor/utils.ts
CHANGED
|
@@ -504,23 +504,81 @@ export function normalizeGuid(id: string) {
|
|
|
504
504
|
return "{" + id + "}";
|
|
505
505
|
}
|
|
506
506
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
507
|
+
function getLocale() {
|
|
508
|
+
try {
|
|
509
|
+
if (typeof navigator !== "undefined" && navigator.language)
|
|
510
|
+
return navigator.language;
|
|
511
|
+
} catch {}
|
|
512
|
+
return "en";
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
function getUserTimeZone() {
|
|
516
|
+
try {
|
|
517
|
+
const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
518
|
+
return tz || "UTC";
|
|
519
|
+
} catch {
|
|
520
|
+
return "UTC";
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
export function formatDate(
|
|
525
|
+
date: Date,
|
|
526
|
+
options?: Intl.DateTimeFormatOptions & { timeZone?: string },
|
|
527
|
+
) {
|
|
528
|
+
const locale = getLocale();
|
|
529
|
+
const timeZone = options?.timeZone || getUserTimeZone();
|
|
530
|
+
const fmt = new Intl.DateTimeFormat(locale, {
|
|
531
|
+
year: "numeric",
|
|
532
|
+
month: "numeric",
|
|
533
|
+
day: "numeric",
|
|
534
|
+
hour: "numeric",
|
|
535
|
+
minute: "numeric",
|
|
536
|
+
second: "numeric",
|
|
537
|
+
hour12: false,
|
|
538
|
+
timeZone,
|
|
539
|
+
...options,
|
|
540
|
+
});
|
|
541
|
+
return fmt.format(date);
|
|
542
|
+
}
|
|
516
543
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
)
|
|
544
|
+
export function formatDateOnly(
|
|
545
|
+
date: Date,
|
|
546
|
+
options?: Intl.DateTimeFormatOptions & { timeZone?: string },
|
|
547
|
+
) {
|
|
548
|
+
const locale = getLocale();
|
|
549
|
+
const timeZone = options?.timeZone || getUserTimeZone();
|
|
550
|
+
const fmt = new Intl.DateTimeFormat(locale, {
|
|
551
|
+
year: "numeric",
|
|
552
|
+
month: "numeric",
|
|
553
|
+
day: "numeric",
|
|
554
|
+
timeZone,
|
|
555
|
+
...options,
|
|
556
|
+
});
|
|
557
|
+
return fmt.format(date);
|
|
558
|
+
}
|
|
521
559
|
|
|
522
|
-
export function
|
|
523
|
-
|
|
560
|
+
export function formatTime(
|
|
561
|
+
date: Date,
|
|
562
|
+
options?: Intl.DateTimeFormatOptions & { timeZone?: string },
|
|
563
|
+
) {
|
|
564
|
+
const locale = getLocale();
|
|
565
|
+
const timeZone = options?.timeZone || getUserTimeZone();
|
|
566
|
+
const fmt = new Intl.DateTimeFormat(locale, {
|
|
567
|
+
hour: "numeric",
|
|
568
|
+
minute: "numeric",
|
|
569
|
+
second: "numeric",
|
|
570
|
+
hour12: false,
|
|
571
|
+
timeZone,
|
|
572
|
+
...options,
|
|
573
|
+
});
|
|
574
|
+
return fmt.format(date);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
export function formatDateTime(
|
|
578
|
+
date: Date,
|
|
579
|
+
options?: Intl.DateTimeFormatOptions & { timeZone?: string },
|
|
580
|
+
) {
|
|
581
|
+
return formatDate(date, options);
|
|
524
582
|
}
|
|
525
583
|
|
|
526
584
|
export function findClosestFieldElement(node: Node | null): HTMLElement | null {
|
package/src/revision.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const version = "1.0.
|
|
2
|
-
export const buildDate = "2025-09-23
|
|
1
|
+
export const version = "1.0.4106";
|
|
2
|
+
export const buildDate = "2025-09-23 20:25:39";
|
package/src/types.ts
CHANGED
|
@@ -260,6 +260,7 @@ export type IndexStatus = {
|
|
|
260
260
|
rebuilding: boolean;
|
|
261
261
|
batches: EmbeddingBatch[];
|
|
262
262
|
latestEmbeddedItems?: LatestEmbeddedItem[];
|
|
263
|
+
messages?: SystemStatusMessage[];
|
|
263
264
|
};
|
|
264
265
|
|
|
265
266
|
export type EmbeddingBatch = {
|
|
@@ -337,6 +338,7 @@ export type Comment = {
|
|
|
337
338
|
isNew: boolean;
|
|
338
339
|
itemId: string;
|
|
339
340
|
itemName?: string;
|
|
341
|
+
mainItemName?: string;
|
|
340
342
|
mainItemId: string;
|
|
341
343
|
language: string;
|
|
342
344
|
version: number;
|
|
@@ -408,7 +410,9 @@ export interface SuggestedEdit {
|
|
|
408
410
|
mainItemId: string;
|
|
409
411
|
mainItemLanguage: string;
|
|
410
412
|
mainItemVersion: number;
|
|
413
|
+
mainItemName?: string;
|
|
411
414
|
itemId: string;
|
|
415
|
+
itemName?: string;
|
|
412
416
|
fieldId: string;
|
|
413
417
|
oldValue: string;
|
|
414
418
|
newValue: string;
|