@semiont/react-ui 0.5.27 → 0.5.28
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/{PdfAnnotationCanvas.client-EVUPTUWZ.js → PdfAnnotationCanvas.client-C2IGG4SW.js} +31 -4
- package/dist/{ar-OU3DQGC6.js → ar-FABPTJVB.js} +39 -23
- package/dist/{bn-PHWCR6AZ.js → bn-LKP6BDMH.js} +39 -23
- package/dist/{chunk-PCRRBU7H.js → chunk-2GOHTTHW.js} +39 -23
- package/dist/{chunk-5VDTWRXJ.js → chunk-2YHEE63S.js} +31 -31
- package/dist/{cs-NEXYZ62I.js → cs-YQYNWHRG.js} +39 -23
- package/dist/{da-FAT43YCU.js → da-QHZOYKRY.js} +39 -23
- package/dist/{de-KRQ3WBCU.js → de-GKA7RD7J.js} +39 -23
- package/dist/{el-Q4IU3EKC.js → el-45T257AL.js} +39 -23
- package/dist/{en-2KADE7N4.js → en-RVW5EQ66.js} +2 -2
- package/dist/{es-2IO3R2MK.js → es-AVER7RU4.js} +39 -23
- package/dist/{fa-Q5GOQFXX.js → fa-K3VPK3O2.js} +39 -23
- package/dist/{fi-R6NMRWBE.js → fi-5NEKF7EB.js} +39 -23
- package/dist/{fr-QY4D5E6J.js → fr-FUMNDLBZ.js} +39 -23
- package/dist/{he-X6Y77XHY.js → he-3JGNA3PR.js} +39 -23
- package/dist/{hi-XL7IOEQM.js → hi-IJY375DF.js} +39 -23
- package/dist/{id-QZ4ZZS67.js → id-LWHKJ7ZD.js} +39 -23
- package/dist/index.css +279 -74
- package/dist/index.d.ts +170 -145
- package/dist/index.js +2743 -2365
- package/dist/{it-ME2Q7OB6.js → it-EBVOV4RW.js} +39 -23
- package/dist/{ja-HX7QASRI.js → ja-KWRIX2NF.js} +39 -23
- package/dist/{ko-EQO5AHAV.js → ko-L5CJMFDS.js} +39 -23
- package/dist/{ms-UILFSF3I.js → ms-LSNMJDR2.js} +39 -23
- package/dist/{nl-NNI45PMK.js → nl-ZB32MB7U.js} +39 -23
- package/dist/{no-MAL5F6P6.js → no-4GTNY7M5.js} +39 -23
- package/dist/{pl-4RMY6JAJ.js → pl-LUHBLTHB.js} +39 -23
- package/dist/{pt-VQH2X3QQ.js → pt-C4H3UNQ6.js} +39 -23
- package/dist/{ro-XXCQO2OG.js → ro-GGITS5V4.js} +39 -23
- package/dist/{sv-7Z6EJ6U4.js → sv-T56RTLBP.js} +39 -23
- package/dist/test-utils.js +2 -2
- package/dist/{th-L3DXXYVQ.js → th-22X2IWCB.js} +39 -23
- package/dist/{tr-P3DFVLFJ.js → tr-77TFG62H.js} +39 -23
- package/dist/{uk-7C5D3PXS.js → uk-MIIL6NXT.js} +39 -23
- package/dist/{vi-ZLTLEO7P.js → vi-7JYOIGNV.js} +39 -23
- package/dist/{zh-5FHVWDIN.js → zh-ID6DRYU4.js} +39 -23
- package/package.json +9 -8
- package/src/components/AssistProgress.tsx +36 -2
- package/src/components/CodeMirrorRenderer.tsx +8 -8
- package/src/components/__tests__/AssistProgress.test.tsx +59 -0
- package/src/components/modals/ComposeStep.tsx +218 -0
- package/src/components/modals/ConfigureGatherStep.tsx +10 -18
- package/src/components/modals/ConfigureGenerationStep.tsx +35 -19
- package/src/components/modals/ConfigureSearchStep.tsx +19 -0
- package/src/components/modals/ContextSummary.tsx +185 -72
- package/src/components/modals/CorpusPane.tsx +75 -0
- package/src/components/modals/DiscardPrompt.tsx +38 -0
- package/src/components/modals/GatherContextStep.tsx +237 -107
- package/src/components/modals/ReferenceWizardModal.tsx +238 -50
- package/src/components/modals/ResourceGenerateModal.tsx +216 -108
- package/src/components/modals/SearchModal.css +337 -101
- package/src/components/modals/SearchResultsStep.tsx +61 -68
- package/src/components/modals/WizardFooter.tsx +7 -1
- package/src/components/modals/__tests__/ComposeStep.test.tsx +152 -0
- package/src/components/modals/__tests__/ConfigureGatherStep.test.tsx +14 -26
- package/src/components/modals/__tests__/ConfigureGenerationStep.test.tsx +35 -0
- package/src/components/modals/__tests__/ConfigureSearchStep.test.tsx +24 -1
- package/src/components/modals/__tests__/GatherContextStep.resource.test.tsx +463 -25
- package/src/components/modals/__tests__/ReferenceWizardModal.test.tsx +417 -38
- package/src/components/modals/__tests__/ResourceGenerateModal.test.tsx +276 -85
- package/src/components/modals/__tests__/SearchResultsStep.test.tsx +61 -0
- package/src/components/modals/__tests__/WizardFooter.test.tsx +113 -4
- package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +34 -1
- package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +38 -1
- package/src/components/resource/AnnotateView.tsx +3 -3
- package/src/components/resource/BrowseView.tsx +5 -5
- package/src/components/resource/ResourceViewer.tsx +4 -4
- package/src/components/resource/__tests__/AnnotateView.embeddable.test.tsx +1 -1
- package/src/components/resource/__tests__/BrowseView.embeddable.test.tsx +1 -1
- package/src/components/resource/__tests__/BrowseView.test.tsx +9 -9
- package/src/components/resource/annotate-renderers.tsx +3 -3
- package/src/components/resource/panels/AssistSection.css +35 -0
- package/src/components/resource/panels/ReferenceEntry.tsx +9 -2
- package/src/components/resource/panels/ReferencesPanel.tsx +4 -0
- package/src/components/resource/panels/ResourceInfoPanel.tsx +89 -20
- package/src/components/resource/panels/UnifiedAnnotationsPanel.tsx +7 -2
- package/src/components/resource/panels/__tests__/ReferenceEntry.test.tsx +41 -0
- package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +33 -1
- package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +148 -6
- package/src/features/resource-compose/__tests__/ResourceComposePage.test.tsx +0 -65
- package/src/features/resource-compose/components/ResourceComposePage.tsx +17 -130
- package/src/features/resource-compose/state/__tests__/compose-page-state-unit.test.ts +1 -100
- package/src/features/resource-compose/state/compose-page-state-unit.ts +5 -57
- package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +71 -15
- package/src/features/resource-viewer/components/ResourceViewerPage.tsx +133 -59
- package/src/styles/core/forms.css +35 -8
- package/src/styles/features/resource-viewer.css +0 -22
- package/src/styles/features/resource.css +0 -4
- package/translations/ar.json +38 -22
- package/translations/bn.json +38 -22
- package/translations/cs.json +38 -22
- package/translations/da.json +38 -22
- package/translations/de.json +38 -22
- package/translations/el.json +38 -22
- package/translations/en.json +38 -22
- package/translations/es.json +38 -22
- package/translations/fa.json +38 -22
- package/translations/fi.json +38 -22
- package/translations/fr.json +38 -22
- package/translations/he.json +38 -22
- package/translations/hi.json +38 -22
- package/translations/id.json +38 -22
- package/translations/it.json +38 -22
- package/translations/ja.json +38 -22
- package/translations/ko.json +38 -22
- package/translations/ms.json +38 -22
- package/translations/nl.json +38 -22
- package/translations/no.json +38 -22
- package/translations/pl.json +38 -22
- package/translations/pt.json +38 -22
- package/translations/ro.json +38 -22
- package/translations/sv.json +38 -22
- package/translations/th.json +38 -22
- package/translations/tr.json +38 -22
- package/translations/uk.json +38 -22
- package/translations/vi.json +38 -22
- package/translations/zh.json +38 -22
- package/dist/PdfAnnotationCanvas.client-EVUPTUWZ.js.map +0 -1
- package/dist/PdfAnnotationCanvas.client-TGDPPGXJ.css.map +0 -1
- package/dist/ar-OU3DQGC6.js.map +0 -1
- package/dist/bn-PHWCR6AZ.js.map +0 -1
- package/dist/chunk-5VDTWRXJ.js.map +0 -1
- package/dist/chunk-BTUG3VJJ.js.map +0 -1
- package/dist/chunk-O23TLLXW.js.map +0 -1
- package/dist/chunk-PCRRBU7H.js.map +0 -1
- package/dist/chunk-QT7LYM72.js.map +0 -1
- package/dist/chunk-VXASXU4K.js.map +0 -1
- package/dist/cs-NEXYZ62I.js.map +0 -1
- package/dist/da-FAT43YCU.js.map +0 -1
- package/dist/de-KRQ3WBCU.js.map +0 -1
- package/dist/el-Q4IU3EKC.js.map +0 -1
- package/dist/en-2KADE7N4.js.map +0 -1
- package/dist/es-2IO3R2MK.js.map +0 -1
- package/dist/fa-Q5GOQFXX.js.map +0 -1
- package/dist/fi-R6NMRWBE.js.map +0 -1
- package/dist/fr-QY4D5E6J.js.map +0 -1
- package/dist/he-X6Y77XHY.js.map +0 -1
- package/dist/hi-XL7IOEQM.js.map +0 -1
- package/dist/id-QZ4ZZS67.js.map +0 -1
- package/dist/index.css.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/integrations/css-modules-helper.js.map +0 -1
- package/dist/integrations/styled-components-theme.js.map +0 -1
- package/dist/it-ME2Q7OB6.js.map +0 -1
- package/dist/ja-HX7QASRI.js.map +0 -1
- package/dist/ko-EQO5AHAV.js.map +0 -1
- package/dist/ms-UILFSF3I.js.map +0 -1
- package/dist/nl-NNI45PMK.js.map +0 -1
- package/dist/no-MAL5F6P6.js.map +0 -1
- package/dist/pl-4RMY6JAJ.js.map +0 -1
- package/dist/pt-VQH2X3QQ.js.map +0 -1
- package/dist/ro-XXCQO2OG.js.map +0 -1
- package/dist/sv-7Z6EJ6U4.js.map +0 -1
- package/dist/test-utils.css.map +0 -1
- package/dist/test-utils.js.map +0 -1
- package/dist/th-L3DXXYVQ.js.map +0 -1
- package/dist/tr-P3DFVLFJ.js.map +0 -1
- package/dist/uk-7C5D3PXS.js.map +0 -1
- package/dist/vi-ZLTLEO7P.js.map +0 -1
- package/dist/zh-5FHVWDIN.js.map +0 -1
- package/src/components/modals/ResourceSearchModal.tsx +0 -224
- package/src/components/modals/__tests__/ResourceSearchModal.test.tsx +0 -163
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useState, useEffect, useCallback } from 'react';
|
|
3
|
+
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
4
4
|
import { Dialog, DialogPanel, DialogTitle, Transition, TransitionChild } from '@headlessui/react';
|
|
5
5
|
import type { GatheredContext, CollaboratorEntry } from '@semiont/core';
|
|
6
6
|
import { uuidV4 } from '@semiont/core';
|
|
@@ -14,13 +14,18 @@ import { ConfigureSearchStep } from './ConfigureSearchStep';
|
|
|
14
14
|
import type { SearchConfig } from './ConfigureSearchStep';
|
|
15
15
|
import type { GenerationDraft } from './ConfigureGenerationStep';
|
|
16
16
|
import { SearchResultsStep } from './SearchResultsStep';
|
|
17
|
+
import { ComposeStep } from './ComposeStep';
|
|
18
|
+
import type { ComposeDraft, ComposeParams } from './ComposeStep';
|
|
19
|
+
import { DiscardPrompt } from './DiscardPrompt';
|
|
20
|
+
import { useLineNumbers } from '../../contexts/LineNumbersContext';
|
|
17
21
|
import type { ScoredResult } from './SearchResultsStep';
|
|
18
22
|
|
|
19
23
|
type WizardStep =
|
|
20
24
|
| { step: 'gather' }
|
|
21
25
|
| { step: 'configure-search' }
|
|
22
26
|
| { step: 'search-results'; results: ScoredResult[] }
|
|
23
|
-
| { step: 'configure-generation' }
|
|
27
|
+
| { step: 'configure-generation' }
|
|
28
|
+
| { step: 'compose' };
|
|
24
29
|
|
|
25
30
|
export interface ReferenceWizardModalProps {
|
|
26
31
|
/**
|
|
@@ -39,6 +44,12 @@ export interface ReferenceWizardModalProps {
|
|
|
39
44
|
defaultTitle: string;
|
|
40
45
|
/** Entity types from the annotation */
|
|
41
46
|
entityTypes: string[];
|
|
47
|
+
/**
|
|
48
|
+
* The source resource's display name — a page fact (the wizard opens FROM
|
|
49
|
+
* that resource), shown in the gather skeleton's source line before the
|
|
50
|
+
* gathered context can say it itself.
|
|
51
|
+
*/
|
|
52
|
+
resourceName?: string;
|
|
42
53
|
/** Current locale for generation defaults */
|
|
43
54
|
locale: string;
|
|
44
55
|
/** Gathered context state */
|
|
@@ -48,21 +59,36 @@ export interface ReferenceWizardModalProps {
|
|
|
48
59
|
/** Callbacks */
|
|
49
60
|
onGenerateSubmit: (referenceId: string, config: GenerationConfig) => void;
|
|
50
61
|
onLinkResource: (referenceId: string, targetResourceId: string) => void;
|
|
51
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Create-and-link (COMPOSE-IN-MODAL): the host runs `yield.resource` then
|
|
64
|
+
* `bind.body` and settles the promise; rejection keeps the modal open with
|
|
65
|
+
* the compose footer re-enabled. Replaces the old navigate-to-page flow.
|
|
66
|
+
*/
|
|
67
|
+
onComposeSubmit: (referenceId: string, params: ComposeParams) => Promise<void>;
|
|
68
|
+
/** Picker vocabulary for compose when the reference fixed no entity types. */
|
|
69
|
+
entityTypeOptions?: string[];
|
|
70
|
+
/** Editor hover delay for the compose step's CodeMirror. */
|
|
71
|
+
hoverDelayMs?: number;
|
|
52
72
|
/** Translation strings */
|
|
53
73
|
translations: {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
searchResultsTitle: string;
|
|
74
|
+
/** The ONE title, all steps — the flow is resolving a reference; the
|
|
75
|
+
strategy band below says where in it you are. */
|
|
76
|
+
resolveTitle: string;
|
|
58
77
|
sourceContextLabel: string;
|
|
59
78
|
connectionsLabel: string;
|
|
60
79
|
citedByLabel: string;
|
|
80
|
+
graphPaneTitle: string;
|
|
81
|
+
graphEmpty: string;
|
|
82
|
+
resourceLinkLabel: string;
|
|
83
|
+
corpusPaneTitle: string;
|
|
84
|
+
corpusEmpty: string;
|
|
85
|
+
excludedReceipt: string;
|
|
86
|
+
machineRead: string;
|
|
61
87
|
userHintLabel: string;
|
|
88
|
+
userHintEffect: string;
|
|
62
89
|
userHintPlaceholder: string;
|
|
63
90
|
loadingContext: string;
|
|
64
91
|
failedContext: string;
|
|
65
|
-
cancel: string;
|
|
66
92
|
search: string;
|
|
67
93
|
searching: string;
|
|
68
94
|
generate: string;
|
|
@@ -74,6 +100,7 @@ export interface ReferenceWizardModalProps {
|
|
|
74
100
|
noResults: string;
|
|
75
101
|
resourceTitle: string;
|
|
76
102
|
resourceTitlePlaceholder: string;
|
|
103
|
+
saveLocation: string;
|
|
77
104
|
additionalInstructions: string;
|
|
78
105
|
additionalInstructionsPlaceholder: string;
|
|
79
106
|
language: string;
|
|
@@ -87,6 +114,14 @@ export interface ReferenceWizardModalProps {
|
|
|
87
114
|
maxResults: string;
|
|
88
115
|
semanticScoring: string;
|
|
89
116
|
semanticScoringHelp: string;
|
|
117
|
+
searchFailed: string;
|
|
118
|
+
entityTypes: string;
|
|
119
|
+
contentLabel: string;
|
|
120
|
+
createAndLink: string;
|
|
121
|
+
creatingAndLinking: string;
|
|
122
|
+
discardDraftPrompt: string;
|
|
123
|
+
discardDraft: string;
|
|
124
|
+
keepEditing: string;
|
|
90
125
|
};
|
|
91
126
|
}
|
|
92
127
|
|
|
@@ -97,13 +132,16 @@ export function ReferenceWizardModal({
|
|
|
97
132
|
resourceId,
|
|
98
133
|
defaultTitle,
|
|
99
134
|
entityTypes,
|
|
135
|
+
resourceName,
|
|
100
136
|
locale,
|
|
101
137
|
context,
|
|
102
138
|
contextLoading,
|
|
103
139
|
contextError,
|
|
104
140
|
onGenerateSubmit,
|
|
105
141
|
onLinkResource,
|
|
106
|
-
|
|
142
|
+
onComposeSubmit,
|
|
143
|
+
entityTypeOptions = [],
|
|
144
|
+
hoverDelayMs = 300,
|
|
107
145
|
translations: t,
|
|
108
146
|
generationAgent,
|
|
109
147
|
}: ReferenceWizardModalProps) {
|
|
@@ -118,11 +156,27 @@ export function ReferenceWizardModal({
|
|
|
118
156
|
temperature: 0.7, maxTokensText: '500',
|
|
119
157
|
});
|
|
120
158
|
const [isSearching, setIsSearching] = useState(false);
|
|
159
|
+
const [searchError, setSearchError] = useState<string | null>(null);
|
|
121
160
|
const [userHint, setUserHint] = useState('');
|
|
161
|
+
const freshComposeDraft = (): ComposeDraft => ({
|
|
162
|
+
name: defaultTitle, storagePath: '', content: '', entityTypes: [], language: locale,
|
|
163
|
+
});
|
|
164
|
+
const [composeDraft, setComposeDraft] = useState<ComposeDraft>(freshComposeDraft);
|
|
165
|
+
const [showDiscardPrompt, setShowDiscardPrompt] = useState(false);
|
|
166
|
+
// The editor consumes the shared display setting; the step itself stays
|
|
167
|
+
// provider-free, so the wizard resolves it and passes it down.
|
|
168
|
+
const { showLineNumbers } = useLineNumbers();
|
|
169
|
+
|
|
170
|
+
// The dirty baseline is what was SEEDED, not the live prop: defaultTitle
|
|
171
|
+
// derives from observable wizard state and can re-emit while the modal is
|
|
172
|
+
// open; an untouched draft must not read as dirty because the baseline
|
|
173
|
+
// moved under it.
|
|
174
|
+
const seededTitle = useRef(defaultTitle);
|
|
122
175
|
|
|
123
176
|
// Reset to gather step when modal opens
|
|
124
177
|
useEffect(() => {
|
|
125
178
|
if (isOpen) {
|
|
179
|
+
seededTitle.current = defaultTitle;
|
|
126
180
|
setWizardStep({ step: 'gather' });
|
|
127
181
|
setSearchConfig({ limit: 10, useSemanticScoring: true });
|
|
128
182
|
setGenerationDraft({
|
|
@@ -130,7 +184,10 @@ export function ReferenceWizardModal({
|
|
|
130
184
|
temperature: 0.7, maxTokensText: '500',
|
|
131
185
|
});
|
|
132
186
|
setIsSearching(false);
|
|
187
|
+
setSearchError(null);
|
|
133
188
|
setUserHint('');
|
|
189
|
+
setComposeDraft(freshComposeDraft());
|
|
190
|
+
setShowDiscardPrompt(false);
|
|
134
191
|
}
|
|
135
192
|
}, [isOpen]);
|
|
136
193
|
|
|
@@ -143,6 +200,17 @@ export function ReferenceWizardModal({
|
|
|
143
200
|
}
|
|
144
201
|
});
|
|
145
202
|
|
|
203
|
+
// …and to failures, same scoping. A refused emit (/bus/emit 4xx), a matcher
|
|
204
|
+
// error, and the match unit's timeout all land here — without this
|
|
205
|
+
// subscription every one of them left the button on "Searching…" forever.
|
|
206
|
+
useEventSubscription('match:search-failed', (event) => {
|
|
207
|
+
if (!isOpen) return;
|
|
208
|
+
if (annotationId && event.referenceId === annotationId) {
|
|
209
|
+
setIsSearching(false);
|
|
210
|
+
setSearchError(event.error);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
146
214
|
const handleBind = useCallback(() => {
|
|
147
215
|
setWizardStep({ step: 'configure-search' });
|
|
148
216
|
}, []);
|
|
@@ -158,9 +226,9 @@ export function ReferenceWizardModal({
|
|
|
158
226
|
* `focus.userHint` ("hint to supplement or replace the selected text for search and
|
|
159
227
|
* generation"). So the hint was misplaced on every path, not just missing on one.
|
|
160
228
|
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
229
|
+
* Both consumers read it: the matcher folds it into its search term and its
|
|
230
|
+
* LLM-scoring passage (matcher.ts, since #911), and generation's prompt builder
|
|
231
|
+
* renders it in the annotation section (resource-generation.ts).
|
|
164
232
|
*/
|
|
165
233
|
const contextWithHint = !context
|
|
166
234
|
? null
|
|
@@ -173,18 +241,57 @@ export function ReferenceWizardModal({
|
|
|
173
241
|
}, []);
|
|
174
242
|
|
|
175
243
|
const handleCompose = useCallback(() => {
|
|
176
|
-
if (!
|
|
177
|
-
|
|
244
|
+
if (!context || !annotationId || !resourceId) return;
|
|
245
|
+
setWizardStep({ step: 'compose' });
|
|
246
|
+
}, [context, annotationId, resourceId]);
|
|
247
|
+
|
|
248
|
+
const handleComposeSubmit = useCallback(async (params: ComposeParams) => {
|
|
249
|
+
if (!annotationId) return;
|
|
250
|
+
// Rejection propagates to ComposeStep (footer re-enables); the host
|
|
251
|
+
// surfaces the error. Success closes UNCONDITIONALLY — the dirty guard
|
|
252
|
+
// protects dismissal, not completion.
|
|
253
|
+
await onComposeSubmit(annotationId, params);
|
|
178
254
|
onClose();
|
|
179
|
-
}, [
|
|
255
|
+
}, [annotationId, onComposeSubmit, onClose]);
|
|
256
|
+
|
|
257
|
+
// D4 (widened by GATHER-AT-THE-TOP): a modal dies on ✕/Escape/backdrop, but
|
|
258
|
+
// typed work must not die with it — WHEREVER the user currently is (drafts
|
|
259
|
+
// survive stepping away, so the guard must too). Typed text only (D5):
|
|
260
|
+
// seeded titles, toggles, and sliders never nag.
|
|
261
|
+
const draftDirty =
|
|
262
|
+
composeDraft.content.trim() !== '' ||
|
|
263
|
+
composeDraft.storagePath.trim() !== '' ||
|
|
264
|
+
composeDraft.name !== seededTitle.current ||
|
|
265
|
+
generationDraft.title !== seededTitle.current ||
|
|
266
|
+
generationDraft.storagePath.trim() !== '' ||
|
|
267
|
+
generationDraft.prompt.trim() !== '';
|
|
268
|
+
const handleDismiss = useCallback(() => {
|
|
269
|
+
if (draftDirty) {
|
|
270
|
+
setShowDiscardPrompt(true);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
onClose();
|
|
274
|
+
}, [draftDirty, onClose]);
|
|
180
275
|
|
|
181
276
|
const handleBackToGather = useCallback(() => {
|
|
182
277
|
setWizardStep({ step: 'gather' });
|
|
183
278
|
}, []);
|
|
184
279
|
|
|
280
|
+
// The strategy steps stack evidence + step content in ONE scroll pane. On
|
|
281
|
+
// entry, start at the BOTTOM: the step's own content (form, results) shows
|
|
282
|
+
// in full, the evidence tucks up under the modal top, reachable by
|
|
283
|
+
// scrolling up. jsdom has no layout (scrollHeight 0), so this is a no-op
|
|
284
|
+
// in tests — the same posture as the viewer's guarded scrolls.
|
|
285
|
+
const stepScrollRef = useRef<HTMLDivElement>(null);
|
|
286
|
+
useEffect(() => {
|
|
287
|
+
const el = stepScrollRef.current;
|
|
288
|
+
if (el) el.scrollTop = el.scrollHeight;
|
|
289
|
+
}, [wizardStep.step]);
|
|
290
|
+
|
|
185
291
|
const handleSearchSubmit = useCallback((config: SearchConfig) => {
|
|
186
292
|
if (!annotationId || !contextWithHint || !resourceId) return;
|
|
187
293
|
setIsSearching(true);
|
|
294
|
+
setSearchError(null);
|
|
188
295
|
session?.client.match.requestSearch({
|
|
189
296
|
correlationId: uuidV4(),
|
|
190
297
|
resourceId,
|
|
@@ -208,18 +315,29 @@ export function ReferenceWizardModal({
|
|
|
208
315
|
onClose();
|
|
209
316
|
}, [annotationId, onLinkResource, onClose]);
|
|
210
317
|
|
|
211
|
-
//
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
318
|
+
// The evidence display's translations — shared by the gather step and the
|
|
319
|
+
// strategy steps, which keep the context in view (display-only, GFR A2)
|
|
320
|
+
// above their forms rather than navigating away from it.
|
|
321
|
+
const displayTranslations = {
|
|
322
|
+
loadingContext: t.loadingContext,
|
|
323
|
+
failedContext: t.failedContext,
|
|
324
|
+
sourceContextLabel: t.sourceContextLabel,
|
|
325
|
+
connectionsLabel: t.connectionsLabel,
|
|
326
|
+
citedByLabel: t.citedByLabel,
|
|
327
|
+
graphPaneTitle: t.graphPaneTitle,
|
|
328
|
+
graphEmpty: t.graphEmpty,
|
|
329
|
+
resourceLinkLabel: t.resourceLinkLabel,
|
|
330
|
+
corpusPaneTitle: t.corpusPaneTitle,
|
|
331
|
+
corpusEmpty: t.corpusEmpty,
|
|
332
|
+
excludedReceipt: t.excludedReceipt,
|
|
333
|
+
machineRead: t.machineRead,
|
|
334
|
+
score: t.score,
|
|
335
|
+
};
|
|
336
|
+
|
|
219
337
|
|
|
220
338
|
return (
|
|
221
339
|
<Transition appear show={isOpen}>
|
|
222
|
-
<Dialog as="div" className="semiont-search-modal" onClose={
|
|
340
|
+
<Dialog as="div" className="semiont-search-modal" onClose={handleDismiss}>
|
|
223
341
|
{/* Backdrop */}
|
|
224
342
|
<TransitionChild
|
|
225
343
|
enter="ease-out duration-200"
|
|
@@ -243,13 +361,15 @@ export function ReferenceWizardModal({
|
|
|
243
361
|
leaveFrom="opacity-100 scale-100"
|
|
244
362
|
leaveTo="opacity-0 scale-95"
|
|
245
363
|
>
|
|
246
|
-
|
|
364
|
+
{/* Every step shows the evidence display now, so every step is
|
|
365
|
+
wide and gets the gather layout (flex column, capped height). */}
|
|
366
|
+
<DialogPanel className="semiont-search-modal__panel semiont-search-modal__panel--with-border semiont-search-modal__panel--gather semiont-search-modal__panel--wide">
|
|
247
367
|
<div className="semiont-search-modal__header">
|
|
248
368
|
<DialogTitle className="semiont-search-modal__title">
|
|
249
|
-
{
|
|
369
|
+
{t.resolveTitle}
|
|
250
370
|
</DialogTitle>
|
|
251
371
|
<button
|
|
252
|
-
onClick={
|
|
372
|
+
onClick={handleDismiss}
|
|
253
373
|
className="semiont-search-modal__close-button"
|
|
254
374
|
aria-label="Close"
|
|
255
375
|
>
|
|
@@ -257,36 +377,87 @@ export function ReferenceWizardModal({
|
|
|
257
377
|
</button>
|
|
258
378
|
</div>
|
|
259
379
|
|
|
380
|
+
{showDiscardPrompt && (
|
|
381
|
+
<DiscardPrompt
|
|
382
|
+
prompt={t.discardDraftPrompt}
|
|
383
|
+
discardLabel={t.discardDraft}
|
|
384
|
+
keepLabel={t.keepEditing}
|
|
385
|
+
onDiscard={() => { setShowDiscardPrompt(false); onClose(); }}
|
|
386
|
+
onKeepEditing={() => setShowDiscardPrompt(false)}
|
|
387
|
+
/>
|
|
388
|
+
)}
|
|
389
|
+
|
|
260
390
|
{wizardStep.step === 'gather' && (
|
|
261
391
|
<GatherContextStep
|
|
262
392
|
context={context}
|
|
263
393
|
contextLoading={contextLoading}
|
|
264
394
|
contextError={contextError}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
395
|
+
pending={{ exact: defaultTitle, entityTypes, ...(resourceName ? { resourceName } : {}) }}
|
|
396
|
+
annotate={{
|
|
397
|
+
userHint,
|
|
398
|
+
onUserHintChange: setUserHint,
|
|
399
|
+
onBind: handleBind,
|
|
400
|
+
onGenerate: handleGenerate,
|
|
401
|
+
onCompose: handleCompose,
|
|
402
|
+
translations: {
|
|
403
|
+
search: t.search,
|
|
404
|
+
generate: t.generate,
|
|
405
|
+
compose: t.compose,
|
|
406
|
+
resolutionStrategyLabel: t.resolutionStrategyLabel,
|
|
407
|
+
userHintLabel: t.userHintLabel,
|
|
408
|
+
userHintEffect: t.userHintEffect,
|
|
409
|
+
userHintPlaceholder: t.userHintPlaceholder,
|
|
410
|
+
},
|
|
411
|
+
}}
|
|
412
|
+
translations={displayTranslations}
|
|
413
|
+
/>
|
|
414
|
+
)}
|
|
415
|
+
|
|
416
|
+
{wizardStep.step === 'compose' && context && (
|
|
417
|
+
<div className="semiont-wizard__step-scroll" ref={stepScrollRef}>
|
|
418
|
+
<GatherContextStep
|
|
419
|
+
context={context}
|
|
420
|
+
contextLoading={contextLoading}
|
|
421
|
+
contextError={contextError}
|
|
422
|
+
chosenStrategy={{ label: t.resolutionStrategyLabel, value: `✍️ ${t.compose}` }}
|
|
423
|
+
translations={displayTranslations}
|
|
424
|
+
/>
|
|
425
|
+
<ComposeStep
|
|
426
|
+
draft={composeDraft}
|
|
427
|
+
onDraftChange={(patch) => setComposeDraft((d) => ({ ...d, ...patch }))}
|
|
428
|
+
referenceEntityTypes={entityTypes}
|
|
429
|
+
entityTypeOptions={entityTypeOptions}
|
|
430
|
+
showLineNumbers={showLineNumbers}
|
|
431
|
+
hoverDelayMs={hoverDelayMs}
|
|
432
|
+
onBack={handleBackToGather}
|
|
433
|
+
onCompose={handleComposeSubmit}
|
|
270
434
|
translations={{
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
generate: t.generate,
|
|
281
|
-
compose: t.compose,
|
|
282
|
-
resolutionStrategyLabel: t.resolutionStrategyLabel,
|
|
435
|
+
resourceTitle: t.resourceTitle,
|
|
436
|
+
resourceTitlePlaceholder: t.resourceTitlePlaceholder,
|
|
437
|
+
saveLocation: t.saveLocation,
|
|
438
|
+
entityTypes: t.entityTypes,
|
|
439
|
+
language: t.language,
|
|
440
|
+
contentLabel: t.contentLabel,
|
|
441
|
+
back: t.back,
|
|
442
|
+
createAndLink: t.createAndLink,
|
|
443
|
+
creatingAndLinking: t.creatingAndLinking,
|
|
283
444
|
}}
|
|
284
445
|
/>
|
|
446
|
+
</div>
|
|
285
447
|
)}
|
|
286
448
|
|
|
287
449
|
{wizardStep.step === 'configure-generation' && context && (
|
|
450
|
+
<div className="semiont-wizard__step-scroll" ref={stepScrollRef}>
|
|
451
|
+
<GatherContextStep
|
|
452
|
+
context={context}
|
|
453
|
+
contextLoading={contextLoading}
|
|
454
|
+
contextError={contextError}
|
|
455
|
+
chosenStrategy={{ label: t.resolutionStrategyLabel, value: `✨ ${t.generate}` }}
|
|
456
|
+
translations={displayTranslations}
|
|
457
|
+
/>
|
|
288
458
|
<ConfigureGenerationStep
|
|
289
459
|
{...(generationAgent ? { generationAgent } : {})}
|
|
460
|
+
{...(userHint ? { hintEcho: { label: t.userHintLabel, value: userHint } } : {})}
|
|
290
461
|
context={contextWithHint ?? context}
|
|
291
462
|
config={generationDraft}
|
|
292
463
|
onConfigChange={setGenerationDraft}
|
|
@@ -295,6 +466,7 @@ export function ReferenceWizardModal({
|
|
|
295
466
|
translations={{
|
|
296
467
|
resourceTitle: t.resourceTitle,
|
|
297
468
|
resourceTitlePlaceholder: t.resourceTitlePlaceholder,
|
|
469
|
+
saveLocation: t.saveLocation,
|
|
298
470
|
additionalInstructions: t.additionalInstructions,
|
|
299
471
|
additionalInstructionsPlaceholder: t.additionalInstructionsPlaceholder,
|
|
300
472
|
language: t.language,
|
|
@@ -309,13 +481,24 @@ export function ReferenceWizardModal({
|
|
|
309
481
|
generate: t.generate,
|
|
310
482
|
}}
|
|
311
483
|
/>
|
|
484
|
+
</div>
|
|
312
485
|
)}
|
|
313
486
|
|
|
314
487
|
{wizardStep.step === 'configure-search' && (
|
|
488
|
+
<div className="semiont-wizard__step-scroll" ref={stepScrollRef}>
|
|
489
|
+
<GatherContextStep
|
|
490
|
+
context={context}
|
|
491
|
+
contextLoading={contextLoading}
|
|
492
|
+
contextError={contextError}
|
|
493
|
+
chosenStrategy={{ label: t.resolutionStrategyLabel, value: `🔍 ${t.search}` }}
|
|
494
|
+
translations={displayTranslations}
|
|
495
|
+
/>
|
|
315
496
|
<ConfigureSearchStep
|
|
316
497
|
config={searchConfig}
|
|
498
|
+
{...(userHint ? { hintEcho: { label: t.userHintLabel, value: userHint } } : {})}
|
|
317
499
|
onConfigChange={setSearchConfig}
|
|
318
500
|
isSearching={isSearching}
|
|
501
|
+
searchError={searchError}
|
|
319
502
|
onBack={handleBackToGather}
|
|
320
503
|
onSearch={handleSearchSubmit}
|
|
321
504
|
translations={{
|
|
@@ -325,14 +508,23 @@ export function ReferenceWizardModal({
|
|
|
325
508
|
back: t.back,
|
|
326
509
|
search: t.search,
|
|
327
510
|
searching: t.searching,
|
|
511
|
+
searchFailed: t.searchFailed,
|
|
328
512
|
}}
|
|
329
513
|
/>
|
|
514
|
+
</div>
|
|
330
515
|
)}
|
|
331
516
|
|
|
332
517
|
{wizardStep.step === 'search-results' && context && (
|
|
518
|
+
<div className="semiont-wizard__step-scroll" ref={stepScrollRef}>
|
|
519
|
+
<GatherContextStep
|
|
520
|
+
context={context}
|
|
521
|
+
contextLoading={contextLoading}
|
|
522
|
+
contextError={contextError}
|
|
523
|
+
chosenStrategy={{ label: t.resolutionStrategyLabel, value: `🔍 ${t.search}` }}
|
|
524
|
+
translations={displayTranslations}
|
|
525
|
+
/>
|
|
333
526
|
<SearchResultsStep
|
|
334
527
|
results={wizardStep.results}
|
|
335
|
-
context={context}
|
|
336
528
|
onLink={handleLink}
|
|
337
529
|
onBack={handleBackToGather}
|
|
338
530
|
translations={{
|
|
@@ -340,13 +532,9 @@ export function ReferenceWizardModal({
|
|
|
340
532
|
link: t.link,
|
|
341
533
|
back: t.back,
|
|
342
534
|
score: t.score,
|
|
343
|
-
sourceContextLabel: t.sourceContextLabel,
|
|
344
|
-
connectionsLabel: t.connectionsLabel,
|
|
345
|
-
citedByLabel: t.citedByLabel,
|
|
346
|
-
userHintLabel: t.userHintLabel,
|
|
347
|
-
userHintPlaceholder: t.userHintPlaceholder,
|
|
348
535
|
}}
|
|
349
536
|
/>
|
|
537
|
+
</div>
|
|
350
538
|
)}
|
|
351
539
|
</DialogPanel>
|
|
352
540
|
</TransitionChild>
|