agent-canvas 0.1.12 → 0.1.13
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/daemon/client/AnnotationEditor.tsx +1 -3
- package/daemon/client/AnnotationProvider.tsx +0 -15
- package/daemon/client/App.tsx +5 -1
- package/daemon/client/Popover.tsx +6 -1
- package/daemon/client/ResponsePreview.tsx +22 -7
- package/daemon/client/components/Choice.tsx +8 -12
- package/daemon/client/components/UserInput.tsx +7 -11
- package/daemon/dist/client.js +54 -54
- package/daemon/dist/components.js +45 -45
- package/package.json +1 -1
|
@@ -59,9 +59,7 @@ export function AnnotationEditor({
|
|
|
59
59
|
const openFilePicker = useCallback(() => fileInputRef.current?.click(), []);
|
|
60
60
|
|
|
61
61
|
// Expose file picker to parent
|
|
62
|
-
|
|
63
|
-
if (openFilePickerRef) openFilePickerRef.current = openFilePicker;
|
|
64
|
-
}, [openFilePickerRef, openFilePicker]);
|
|
62
|
+
if (openFilePickerRef) openFilePickerRef.current = openFilePicker;
|
|
65
63
|
|
|
66
64
|
const setRef = useCallback((el: HTMLTextAreaElement | null) => {
|
|
67
65
|
internalRef.current = el;
|
|
@@ -48,7 +48,6 @@ function clearPersisted(sessionId: string, revision: number) {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
export function AnnotationProvider({ sessionId, revision, isReadOnly, children }: AnnotationProviderProps) {
|
|
51
|
-
const prevKeyRef = useRef(`${sessionId}:${revision}`);
|
|
52
51
|
const [annotations, setAnnotations] = useState<Annotation[]>(() => {
|
|
53
52
|
const saved = loadPersisted(sessionId, revision);
|
|
54
53
|
return saved?.annotations ?? [];
|
|
@@ -67,20 +66,6 @@ export function AnnotationProvider({ sessionId, revision, isReadOnly, children }
|
|
|
67
66
|
return saved?.feedbackEntries ? new Map(saved.feedbackEntries) : new Map();
|
|
68
67
|
});
|
|
69
68
|
|
|
70
|
-
// Reset state when session/revision changes
|
|
71
|
-
useEffect(() => {
|
|
72
|
-
const key = `${sessionId}:${revision}`;
|
|
73
|
-
if (key === prevKeyRef.current) return;
|
|
74
|
-
prevKeyRef.current = key;
|
|
75
|
-
|
|
76
|
-
const saved = loadPersisted(sessionId, revision);
|
|
77
|
-
setAnnotations(saved?.annotations ?? []);
|
|
78
|
-
setGeneralNote(saved?.generalNote ?? "");
|
|
79
|
-
setResponses(saved?.responses ? new Map(saved.responses) : new Map());
|
|
80
|
-
setFeedbackEntries(saved?.feedbackEntries ? new Map(saved.feedbackEntries) : new Map());
|
|
81
|
-
setActiveAnnotationId(null);
|
|
82
|
-
}, [sessionId, revision]);
|
|
83
|
-
|
|
84
69
|
// Persist to localStorage (debounced)
|
|
85
70
|
const persistTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
86
71
|
useEffect(() => {
|
package/daemon/client/App.tsx
CHANGED
|
@@ -564,7 +564,11 @@ function ResponseBanner({ markdown }: { markdown: string }) {
|
|
|
564
564
|
const responseAnnotations = useMemo(() => annotations.filter((a) => a.filePath === RESPONSE_ANNOTATION_PATH), [annotations]);
|
|
565
565
|
|
|
566
566
|
// Reset dismissed state when markdown changes
|
|
567
|
-
|
|
567
|
+
const [prevMarkdown, setPrevMarkdown] = useState(markdown);
|
|
568
|
+
if (markdown !== prevMarkdown) {
|
|
569
|
+
setPrevMarkdown(markdown);
|
|
570
|
+
setDismissed(false);
|
|
571
|
+
}
|
|
568
572
|
|
|
569
573
|
// Restore marks after content renders
|
|
570
574
|
useEffect(() => {
|
|
@@ -153,7 +153,12 @@ export function AnnotationPopover({
|
|
|
153
153
|
return idx + row;
|
|
154
154
|
};
|
|
155
155
|
|
|
156
|
-
|
|
156
|
+
const [prevNote, setPrevNote] = useState(note);
|
|
157
|
+
if (note !== prevNote) {
|
|
158
|
+
setPrevNote(note);
|
|
159
|
+
setSelectedIdx(null);
|
|
160
|
+
setSuppressed(isEditMode);
|
|
161
|
+
}
|
|
157
162
|
|
|
158
163
|
const applySuggestion = useCallback((s: string) => {
|
|
159
164
|
setNote(s);
|
|
@@ -11,17 +11,32 @@ interface ResponsePreviewProps {
|
|
|
11
11
|
|
|
12
12
|
export function ResponsePreview({ open, onClose, onSubmit }: ResponsePreviewProps) {
|
|
13
13
|
const { annotations, generalNote, responses, feedbackEntries } = useAnnotations();
|
|
14
|
-
const [
|
|
14
|
+
const [editedText, setEditedText] = useState("");
|
|
15
15
|
const [manuallyEdited, setManuallyEdited] = useState(false);
|
|
16
16
|
const [editMode, setEditMode] = useState(false);
|
|
17
17
|
const [validationError, setValidationError] = useState<string | null>(null);
|
|
18
18
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
|
19
|
+
const [prevOpen, setPrevOpen] = useState(false);
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
21
|
+
if (open && !prevOpen) {
|
|
22
|
+
setManuallyEdited(false);
|
|
23
|
+
setEditMode(false);
|
|
24
|
+
setValidationError(null);
|
|
25
|
+
}
|
|
26
|
+
if (!open && prevOpen) {
|
|
27
|
+
setManuallyEdited(false);
|
|
28
|
+
setEditMode(false);
|
|
29
|
+
setValidationError(null);
|
|
30
|
+
}
|
|
31
|
+
if (open !== prevOpen) {
|
|
32
|
+
setPrevOpen(open);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const generatedText = useMemo(
|
|
36
|
+
() => generateMarkdown(annotations, generalNote, responses, feedbackEntries),
|
|
37
|
+
[annotations, generalNote, responses, feedbackEntries]
|
|
38
|
+
);
|
|
39
|
+
const text = manuallyEdited ? editedText : generatedText;
|
|
25
40
|
|
|
26
41
|
useEffect(() => {
|
|
27
42
|
if (open && editMode && textareaRef.current) {
|
|
@@ -86,7 +101,7 @@ export function ResponsePreview({ open, onClose, onSubmit }: ResponsePreviewProp
|
|
|
86
101
|
<textarea
|
|
87
102
|
ref={textareaRef}
|
|
88
103
|
value={text}
|
|
89
|
-
onChange={(e) => {
|
|
104
|
+
onChange={(e) => { setEditedText(e.target.value); setManuallyEdited(true); }}
|
|
90
105
|
className="flex-1 w-full bg-bg-base p-5 text-[13px] font-mono text-text-code resize-none focus:outline-none leading-relaxed placeholder:text-text-disabled"
|
|
91
106
|
placeholder="Your feedback will appear here..."
|
|
92
107
|
/>
|
|
@@ -18,11 +18,9 @@ export function Choice({ id, label, options, required }: ChoiceProps) {
|
|
|
18
18
|
const [showNote, setShowNote] = useState(false);
|
|
19
19
|
const wrapperRef = useRef<HTMLDivElement>(null);
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
}, [id]);
|
|
21
|
+
if (!responses.has(id)) {
|
|
22
|
+
setResponse(id, { id, type: "radio", label, value: null, options, required });
|
|
23
|
+
}
|
|
26
24
|
|
|
27
25
|
const handleSelect = (opt: string) => {
|
|
28
26
|
setResponse(id, { ...current!, value: opt });
|
|
@@ -39,7 +37,7 @@ export function Choice({ id, label, options, required }: ChoiceProps) {
|
|
|
39
37
|
};
|
|
40
38
|
el.addEventListener("kb-select", handler);
|
|
41
39
|
return () => el.removeEventListener("kb-select", handler);
|
|
42
|
-
});
|
|
40
|
+
}, [options, handleSelect]);
|
|
43
41
|
|
|
44
42
|
const showError = current?.required && !selected;
|
|
45
43
|
|
|
@@ -95,11 +93,9 @@ export function MultiChoice({ id, label, options, required }: MultiChoiceProps)
|
|
|
95
93
|
const [showNote, setShowNote] = useState(false);
|
|
96
94
|
const wrapperRef = useRef<HTMLDivElement>(null);
|
|
97
95
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
}, [id]);
|
|
96
|
+
if (!responses.has(id)) {
|
|
97
|
+
setResponse(id, { id, type: "checkbox", label, value: [], options, required });
|
|
98
|
+
}
|
|
103
99
|
|
|
104
100
|
const toggle = (opt: string) => {
|
|
105
101
|
const next = selected.includes(opt) ? selected.filter((o) => o !== opt) : [...selected, opt];
|
|
@@ -117,7 +113,7 @@ export function MultiChoice({ id, label, options, required }: MultiChoiceProps)
|
|
|
117
113
|
};
|
|
118
114
|
el.addEventListener("kb-select", handler);
|
|
119
115
|
return () => el.removeEventListener("kb-select", handler);
|
|
120
|
-
});
|
|
116
|
+
}, [options, toggle]);
|
|
121
117
|
|
|
122
118
|
const showError = current?.required && selected.length === 0;
|
|
123
119
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useRef, useState } from "react";
|
|
2
2
|
import { useAnnotations } from "#canvas/runtime";
|
|
3
3
|
import { ResponseNote } from "./ResponseNote";
|
|
4
4
|
import { autoResizeTextarea } from "../utils";
|
|
@@ -20,11 +20,9 @@ export function UserInput({ id, label, placeholder, multiline, required }: UserI
|
|
|
20
20
|
const [showNote, setShowNote] = useState(false);
|
|
21
21
|
const ref = useRef<HTMLTextAreaElement>(null);
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
}, [id]);
|
|
23
|
+
if (!responses.has(id)) {
|
|
24
|
+
setResponse(id, { id, type: "text", label, value: "", required });
|
|
25
|
+
}
|
|
28
26
|
|
|
29
27
|
const handleChange = (v: string) => {
|
|
30
28
|
setResponse(id, { ...current!, value: v });
|
|
@@ -75,11 +73,9 @@ export function RangeInput({ id, label, min = 1, max = 10, step = 1, required, m
|
|
|
75
73
|
const note = current?.note || "";
|
|
76
74
|
const [showNote, setShowNote] = useState(false);
|
|
77
75
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
}, [id]);
|
|
76
|
+
if (!responses.has(id)) {
|
|
77
|
+
setResponse(id, { id, type: "range", label, value: null, required });
|
|
78
|
+
}
|
|
83
79
|
|
|
84
80
|
const handleChange = (v: number) => {
|
|
85
81
|
setResponse(id, { ...current!, value: v });
|