@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,21 +1,17 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { useState, useEffect, useCallback } from 'react';
|
|
4
|
-
import type { CollaboratorEntry } from '@semiont/core';
|
|
3
|
+
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
4
|
+
import type { CollaboratorEntry, GatheredContext } from '@semiont/core';
|
|
5
|
+
import type { ResourceGatherOptions } from '@semiont/sdk';
|
|
5
6
|
import { Dialog, DialogPanel, DialogTitle, Transition, TransitionChild } from '@headlessui/react';
|
|
6
|
-
import { useResourceGather } from '../../hooks/useResourceGather';
|
|
7
7
|
import { ConfigureGatherStep, type ResourceGatherConfig } from './ConfigureGatherStep';
|
|
8
|
+
import { DiscardPrompt } from './DiscardPrompt';
|
|
8
9
|
import { GatherContextStep } from './GatherContextStep';
|
|
9
10
|
import { ConfigureGenerationStep, type GenerationConfig, type GenerationDraft } from './ConfigureGenerationStep';
|
|
10
11
|
|
|
11
12
|
export interface ResourceGenerateModalTranslations {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
reviewTitle: string;
|
|
15
|
-
configureTitle: string;
|
|
16
|
-
next: string;
|
|
17
|
-
back: string;
|
|
18
|
-
cancel: string;
|
|
13
|
+
/** The ONE modal title — names the flow, not a step. */
|
|
14
|
+
title: string;
|
|
19
15
|
// ConfigureGatherStep
|
|
20
16
|
gatherIntro: string;
|
|
21
17
|
includeContent: string;
|
|
@@ -23,16 +19,28 @@ export interface ResourceGenerateModalTranslations {
|
|
|
23
19
|
gatherDepth: string;
|
|
24
20
|
gatherMaxResources: string;
|
|
25
21
|
gatherButton: string;
|
|
26
|
-
|
|
22
|
+
/** Labels the recall chips: every type included until deselected. */
|
|
23
|
+
recallLabel: string;
|
|
24
|
+
/** Affordance on the post-gather receipt row (title/tooltip). */
|
|
25
|
+
editGather: string;
|
|
27
26
|
// GatherContextStep display
|
|
28
27
|
loadingContext: string;
|
|
29
28
|
failedContext: string;
|
|
30
29
|
sourceContextLabel: string;
|
|
31
30
|
connectionsLabel: string;
|
|
32
31
|
citedByLabel: string;
|
|
32
|
+
graphPaneTitle: string;
|
|
33
|
+
graphEmpty: string;
|
|
34
|
+
resourceLinkLabel: string;
|
|
35
|
+
corpusPaneTitle: string;
|
|
36
|
+
corpusEmpty: string;
|
|
37
|
+
excludedReceipt: string;
|
|
38
|
+
machineRead: string;
|
|
39
|
+
score: string;
|
|
33
40
|
// ConfigureGenerationStep
|
|
34
41
|
resourceTitle: string;
|
|
35
42
|
resourceTitlePlaceholder: string;
|
|
43
|
+
saveLocation: string;
|
|
36
44
|
additionalInstructions: string;
|
|
37
45
|
additionalInstructionsPlaceholder: string;
|
|
38
46
|
language: string;
|
|
@@ -44,6 +52,10 @@ export interface ResourceGenerateModalTranslations {
|
|
|
44
52
|
maxLengthHelp: string;
|
|
45
53
|
maxLengthCeiling: string;
|
|
46
54
|
generate: string;
|
|
55
|
+
// DiscardPrompt (GATHER-AT-THE-TOP P1)
|
|
56
|
+
discardDraftPrompt: string;
|
|
57
|
+
discardDraft: string;
|
|
58
|
+
keepEditing: string;
|
|
47
59
|
}
|
|
48
60
|
|
|
49
61
|
export interface ResourceGenerateModalProps {
|
|
@@ -58,7 +70,6 @@ export interface ResourceGenerateModalProps {
|
|
|
58
70
|
resourceId: string;
|
|
59
71
|
defaultTitle: string;
|
|
60
72
|
locale: string;
|
|
61
|
-
gatherDefaults?: Partial<ResourceGatherConfig>;
|
|
62
73
|
/**
|
|
63
74
|
* Entity types offered in the exclusion picker. Owner-supplied so the
|
|
64
75
|
* modal cannot present a failed load as an empty vocabulary.
|
|
@@ -70,15 +81,34 @@ export interface ResourceGenerateModalProps {
|
|
|
70
81
|
* annotation wizard delegates generation to its parent.
|
|
71
82
|
*/
|
|
72
83
|
onGenerateSubmit: (resourceId: string, config: GenerationConfig) => void;
|
|
84
|
+
/**
|
|
85
|
+
* Resource-gather state, verbatim from the SDK's gather unit slots
|
|
86
|
+
* (`gather.resourceContext$` / `resourceLoading$` / `resourceError$`) — the
|
|
87
|
+
* page reads the observables and threads them here, the same shape the
|
|
88
|
+
* reference wizard has always had (FLOW-LIFECYCLE-CONVERGENCE D3/A6). The
|
|
89
|
+
* modal renders this state; it never owns it.
|
|
90
|
+
*/
|
|
91
|
+
gatherContext: GatheredContext | null;
|
|
92
|
+
gatherLoading: boolean;
|
|
93
|
+
gatherError: Error | null;
|
|
94
|
+
/**
|
|
95
|
+
* Run the gather — the page wires `gather.gatherResource(resourceId, …)`.
|
|
96
|
+
* No resourceId in the payload: the owner already holds it. `gatherResource`
|
|
97
|
+
* clears its slots at start, so no reset threading is needed.
|
|
98
|
+
*/
|
|
99
|
+
onGather: (options: ResourceGatherOptions) => void;
|
|
73
100
|
translations: ResourceGenerateModalTranslations;
|
|
74
101
|
}
|
|
75
102
|
|
|
76
|
-
type Step = 'configure-gather' | 'review' | 'configure-generation';
|
|
77
|
-
|
|
78
103
|
/**
|
|
79
|
-
* Resource-generate flow (GENERATE-FROM-BUTTON
|
|
80
|
-
*
|
|
81
|
-
*
|
|
104
|
+
* Resource-generate flow (GENERATE-FROM-BUTTON, folded by GATHER-AT-THE-TOP):
|
|
105
|
+
* one composite stack in a single scroll pane — the gather controls at the
|
|
106
|
+
* top, the gathered `GatheredContext` below them once gather fires, and the
|
|
107
|
+
* generation params beneath the evidence once context arrives. Re-gathering
|
|
108
|
+
* is scroll-up → tweak → Gather; `gatherResource` clears its slots at start,
|
|
109
|
+
* so the evidence refreshes in place. [gather zone] → [evidence] → [act
|
|
110
|
+
* zone]: the same grammar the resolve wizard expresses, whose gather zone
|
|
111
|
+
* happens to be automatic and whose act zone has a strategy choice.
|
|
82
112
|
*/
|
|
83
113
|
export function ResourceGenerateModal({
|
|
84
114
|
isOpen,
|
|
@@ -86,54 +116,128 @@ export function ResourceGenerateModal({
|
|
|
86
116
|
resourceId,
|
|
87
117
|
defaultTitle,
|
|
88
118
|
locale,
|
|
89
|
-
gatherDefaults,
|
|
90
119
|
entityTypeOptions = [],
|
|
91
120
|
onGenerateSubmit,
|
|
121
|
+
gatherContext,
|
|
122
|
+
gatherLoading,
|
|
123
|
+
gatherError,
|
|
124
|
+
onGather,
|
|
92
125
|
translations: t,
|
|
93
126
|
generationAgent,
|
|
94
127
|
}: ResourceGenerateModalProps) {
|
|
95
128
|
// Same draft ownership as the wizard (WIZARD-NAVIGATION D3): the step is
|
|
96
129
|
// controlled, so stepping back through this modal keeps what was typed.
|
|
97
|
-
const
|
|
130
|
+
const freshDraft = (): GenerationDraft => ({
|
|
98
131
|
title: defaultTitle, storagePath: '', prompt: '', language: locale,
|
|
99
132
|
temperature: 0.7, maxTokensText: '500',
|
|
100
133
|
});
|
|
134
|
+
const [generationDraft, setGenerationDraft] = useState<GenerationDraft>(freshDraft);
|
|
101
135
|
|
|
102
|
-
|
|
103
|
-
|
|
136
|
+
// "Has THIS run gathered yet?" — the page's gather slots survive across
|
|
137
|
+
// opens, so a context prop can be stale at open time. Nothing renders below
|
|
138
|
+
// the controls until the user fires a gather in this run.
|
|
139
|
+
const [gatherFired, setGatherFired] = useState(false);
|
|
140
|
+
// The fired snapshot feeds the receipt: what THIS gather actually asked
|
|
141
|
+
// for, exclusions included — not the form's live state, which the user can
|
|
142
|
+
// edit without re-firing.
|
|
143
|
+
const [lastGather, setLastGather] = useState<(ResourceGatherConfig & { excludeEntityTypes: string[] }) | null>(null);
|
|
144
|
+
const [editingGather, setEditingGather] = useState(false);
|
|
145
|
+
const [showDiscardPrompt, setShowDiscardPrompt] = useState(false);
|
|
104
146
|
// Supplied by the owner, which already tracks the list with its failure
|
|
105
147
|
// state. Fetching it here could only model (value | not-yet), so a failed
|
|
106
148
|
// load would render an empty exclusion picker as though the KB had no
|
|
107
149
|
// entity types. See .plans/PANEL-FAILURE-STATES.md
|
|
108
150
|
const [excludeEntityTypes, setExcludeEntityTypes] = useState<string[]>([]);
|
|
109
151
|
|
|
110
|
-
// Reset to the first step
|
|
152
|
+
// Reset to the first step ON OPENING — and re-seed the draft, because
|
|
153
|
+
// `defaultTitle` is the source resource's name and loads asynchronously: the
|
|
154
|
+
// useState initializer ran at mount, which for the real page was before the
|
|
155
|
+
// name existed (GFR A4). Guarded to the false→true transition so a name
|
|
156
|
+
// arriving mid-flow cannot clobber what the user has typed.
|
|
157
|
+
const wasOpen = useRef(false);
|
|
158
|
+
// The dirty baseline is what was SEEDED, not the live prop: defaultTitle
|
|
159
|
+
// can move while the modal is open (the source resource's name loads
|
|
160
|
+
// asynchronously), and an untouched draft must not read as dirty because
|
|
161
|
+
// the baseline moved under it.
|
|
162
|
+
const seededTitle = useRef(defaultTitle);
|
|
111
163
|
useEffect(() => {
|
|
112
|
-
if (isOpen) {
|
|
113
|
-
|
|
164
|
+
if (isOpen && !wasOpen.current) {
|
|
165
|
+
setGatherFired(false);
|
|
166
|
+
setLastGather(null);
|
|
167
|
+
setEditingGather(false);
|
|
114
168
|
setExcludeEntityTypes([]);
|
|
115
|
-
|
|
169
|
+
setGenerationDraft(freshDraft());
|
|
170
|
+
setShowDiscardPrompt(false);
|
|
171
|
+
seededTitle.current = defaultTitle;
|
|
116
172
|
}
|
|
117
|
-
|
|
173
|
+
wasOpen.current = isOpen;
|
|
174
|
+
// freshDraft reads defaultTitle/locale at call time; the effect keys on the
|
|
175
|
+
// OPENING, not on their drift while open.
|
|
176
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
177
|
+
}, [isOpen]);
|
|
118
178
|
|
|
119
179
|
const handleGather = useCallback((config: ResourceGatherConfig) => {
|
|
120
|
-
|
|
121
|
-
|
|
180
|
+
setGatherFired(true);
|
|
181
|
+
setLastGather({ ...config, excludeEntityTypes });
|
|
182
|
+
setEditingGather(false);
|
|
183
|
+
onGather({
|
|
122
184
|
...config,
|
|
123
185
|
...(excludeEntityTypes.length ? { excludeEntityTypes } : {}),
|
|
124
186
|
});
|
|
125
|
-
}, [
|
|
187
|
+
}, [onGather, excludeEntityTypes]);
|
|
126
188
|
|
|
127
189
|
const handleGenerate = useCallback((config: GenerationConfig) => {
|
|
128
190
|
onGenerateSubmit(resourceId, config);
|
|
129
191
|
onClose();
|
|
130
192
|
}, [onGenerateSubmit, resourceId, onClose]);
|
|
131
193
|
|
|
132
|
-
|
|
194
|
+
// D4/D5 (GATHER-AT-THE-TOP P1): typed text must not die with a dismissed
|
|
195
|
+
// modal. Toggles, depth, and exclusion picks are cheap to redo and never
|
|
196
|
+
// nag. Generate's completion path above bypasses this — the guard protects
|
|
197
|
+
// dismissal, not completion.
|
|
198
|
+
const draftDirty =
|
|
199
|
+
generationDraft.title !== seededTitle.current ||
|
|
200
|
+
generationDraft.storagePath.trim() !== '' ||
|
|
201
|
+
generationDraft.prompt.trim() !== '';
|
|
202
|
+
const handleDismiss = useCallback(() => {
|
|
203
|
+
if (draftDirty) {
|
|
204
|
+
setShowDiscardPrompt(true);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
onClose();
|
|
208
|
+
}, [draftDirty, onClose]);
|
|
209
|
+
|
|
210
|
+
// The whole stack is ONE scroll pane; when the params zone appears (context
|
|
211
|
+
// arrival — including each re-gather), enter at the BOTTOM so the
|
|
212
|
+
// parameters show in full, the evidence and controls tucked up under the
|
|
213
|
+
// modal top. jsdom has no layout (scrollHeight 0) — no-op in tests.
|
|
214
|
+
const stepScrollRef = useRef<HTMLDivElement>(null);
|
|
215
|
+
useEffect(() => {
|
|
216
|
+
const el = stepScrollRef.current;
|
|
217
|
+
if (el && gatherContext) el.scrollTop = el.scrollHeight;
|
|
218
|
+
}, [gatherContext]);
|
|
219
|
+
|
|
220
|
+
// The evidence zone: what the generation will be grounded in stays in view
|
|
221
|
+
// above the form.
|
|
222
|
+
const displayTranslations = {
|
|
223
|
+
loadingContext: t.loadingContext,
|
|
224
|
+
failedContext: t.failedContext,
|
|
225
|
+
sourceContextLabel: t.sourceContextLabel,
|
|
226
|
+
connectionsLabel: t.connectionsLabel,
|
|
227
|
+
citedByLabel: t.citedByLabel,
|
|
228
|
+
graphPaneTitle: t.graphPaneTitle,
|
|
229
|
+
graphEmpty: t.graphEmpty,
|
|
230
|
+
resourceLinkLabel: t.resourceLinkLabel,
|
|
231
|
+
corpusPaneTitle: t.corpusPaneTitle,
|
|
232
|
+
corpusEmpty: t.corpusEmpty,
|
|
233
|
+
excludedReceipt: t.excludedReceipt,
|
|
234
|
+
machineRead: t.machineRead,
|
|
235
|
+
score: t.score,
|
|
236
|
+
};
|
|
133
237
|
|
|
134
238
|
return (
|
|
135
239
|
<Transition appear show={isOpen}>
|
|
136
|
-
<Dialog as="div" className="semiont-search-modal" onClose={
|
|
240
|
+
<Dialog as="div" className="semiont-search-modal" onClose={handleDismiss}>
|
|
137
241
|
<TransitionChild
|
|
138
242
|
enter="ease-out duration-200"
|
|
139
243
|
enterFrom="opacity-0"
|
|
@@ -155,21 +259,53 @@ export function ResourceGenerateModal({
|
|
|
155
259
|
leaveFrom="opacity-100 scale-100"
|
|
156
260
|
leaveTo="opacity-0 scale-95"
|
|
157
261
|
>
|
|
158
|
-
<DialogPanel className="semiont-search-modal__panel semiont-search-modal__panel--with-border semiont-search-modal__panel--gather">
|
|
262
|
+
<DialogPanel className="semiont-search-modal__panel semiont-search-modal__panel--with-border semiont-search-modal__panel--gather semiont-search-modal__panel--wide">
|
|
159
263
|
<div className="semiont-search-modal__header">
|
|
160
|
-
<DialogTitle className="semiont-search-modal__title">{
|
|
161
|
-
<button onClick={
|
|
264
|
+
<DialogTitle className="semiont-search-modal__title">{t.title}</DialogTitle>
|
|
265
|
+
<button onClick={handleDismiss} className="semiont-search-modal__close-button" aria-label="Close">
|
|
162
266
|
✕
|
|
163
267
|
</button>
|
|
164
268
|
</div>
|
|
165
269
|
|
|
166
|
-
{
|
|
270
|
+
{showDiscardPrompt && (
|
|
271
|
+
<DiscardPrompt
|
|
272
|
+
prompt={t.discardDraftPrompt}
|
|
273
|
+
discardLabel={t.discardDraft}
|
|
274
|
+
keepLabel={t.keepEditing}
|
|
275
|
+
onDiscard={() => { setShowDiscardPrompt(false); onClose(); }}
|
|
276
|
+
onKeepEditing={() => setShowDiscardPrompt(false)}
|
|
277
|
+
/>
|
|
278
|
+
)}
|
|
279
|
+
|
|
280
|
+
<div className="semiont-wizard__step-scroll" ref={stepScrollRef}>
|
|
281
|
+
{/* Once fired, the spent controls fold into a receipt of
|
|
282
|
+
what THIS gather asked for — the evidence leads the
|
|
283
|
+
pane, the parameters stay visible and revisable. The
|
|
284
|
+
form below is HIDDEN, not unmounted, so its values
|
|
285
|
+
survive for the expand path. */}
|
|
286
|
+
{gatherFired && !editingGather && lastGather && (
|
|
287
|
+
<button
|
|
288
|
+
type="button"
|
|
289
|
+
className="semiont-gather-receipt"
|
|
290
|
+
title={t.editGather}
|
|
291
|
+
onClick={() => setEditingGather(true)}
|
|
292
|
+
>
|
|
293
|
+
{[
|
|
294
|
+
`${t.gatherDepth} ${lastGather.depth}`,
|
|
295
|
+
`${t.gatherMaxResources} ${lastGather.maxResources}`,
|
|
296
|
+
...(lastGather.includeContent ? [t.includeContent] : []),
|
|
297
|
+
...(lastGather.includeSummary ? [t.includeSummary] : []),
|
|
298
|
+
...(lastGather.excludeEntityTypes.length
|
|
299
|
+
? [t.excludedReceipt.replace('{{types}}', lastGather.excludeEntityTypes.join(', '))]
|
|
300
|
+
: []),
|
|
301
|
+
].join(' · ')}
|
|
302
|
+
<span aria-hidden="true"> ✎</span>
|
|
303
|
+
</button>
|
|
304
|
+
)}
|
|
305
|
+
<div hidden={gatherFired && !editingGather}>
|
|
167
306
|
<ConfigureGatherStep
|
|
168
|
-
defaults={gatherDefaults}
|
|
169
307
|
onGather={handleGather}
|
|
170
|
-
onCancel={onClose}
|
|
171
308
|
translations={{
|
|
172
|
-
cancel: t.cancel,
|
|
173
309
|
intro: t.gatherIntro,
|
|
174
310
|
includeContent: t.includeContent,
|
|
175
311
|
includeSummary: t.includeSummary,
|
|
@@ -180,17 +316,21 @@ export function ResourceGenerateModal({
|
|
|
180
316
|
>
|
|
181
317
|
{entityTypeOptions.length > 0 && (
|
|
182
318
|
<div className="semiont-form__field semiont-form__entity-types">
|
|
183
|
-
<label className="semiont-form__label">{t.
|
|
184
|
-
|
|
319
|
+
<label className="semiont-form__label">{t.recallLabel}</label>
|
|
320
|
+
{/* Recall chips — the exclude wire, inverted for the
|
|
321
|
+
UI: every type is IN the recall until crossed off,
|
|
322
|
+
so the state is still the exclude list and a chip
|
|
323
|
+
is included when absent from it. */}
|
|
324
|
+
<div className="semiont-form__recall-chips">
|
|
185
325
|
{entityTypeOptions.map((et) => {
|
|
186
|
-
const
|
|
326
|
+
const isIncluded = !excludeEntityTypes.includes(et);
|
|
187
327
|
return (
|
|
188
328
|
<button
|
|
189
329
|
key={et}
|
|
190
330
|
type="button"
|
|
191
|
-
className="semiont-
|
|
192
|
-
data-
|
|
193
|
-
aria-pressed={
|
|
331
|
+
className="semiont-form__recall-chip"
|
|
332
|
+
data-included={isIncluded}
|
|
333
|
+
aria-pressed={isIncluded}
|
|
194
334
|
onClick={() => setExcludeEntityTypes(prev => prev.includes(et) ? prev.filter(x => x !== et) : [...prev, et])}
|
|
195
335
|
>
|
|
196
336
|
{et}
|
|
@@ -201,75 +341,43 @@ export function ResourceGenerateModal({
|
|
|
201
341
|
</div>
|
|
202
342
|
)}
|
|
203
343
|
</ConfigureGatherStep>
|
|
204
|
-
|
|
344
|
+
</div>
|
|
205
345
|
|
|
206
|
-
|
|
207
|
-
<>
|
|
346
|
+
{gatherFired && (
|
|
208
347
|
<GatherContextStep
|
|
209
|
-
context={
|
|
210
|
-
contextLoading={
|
|
211
|
-
contextError={
|
|
348
|
+
context={gatherContext}
|
|
349
|
+
contextLoading={gatherLoading}
|
|
350
|
+
contextError={gatherError}
|
|
351
|
+
translations={displayTranslations}
|
|
352
|
+
/>
|
|
353
|
+
)}
|
|
354
|
+
|
|
355
|
+
{gatherFired && gatherContext && (
|
|
356
|
+
<ConfigureGenerationStep
|
|
357
|
+
{...(generationAgent ? { generationAgent } : {})}
|
|
358
|
+
context={gatherContext}
|
|
359
|
+
config={generationDraft}
|
|
360
|
+
onConfigChange={setGenerationDraft}
|
|
361
|
+
onGenerate={handleGenerate}
|
|
212
362
|
translations={{
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
363
|
+
resourceTitle: t.resourceTitle,
|
|
364
|
+
resourceTitlePlaceholder: t.resourceTitlePlaceholder,
|
|
365
|
+
saveLocation: t.saveLocation,
|
|
366
|
+
additionalInstructions: t.additionalInstructions,
|
|
367
|
+
additionalInstructionsPlaceholder: t.additionalInstructionsPlaceholder,
|
|
368
|
+
language: t.language,
|
|
369
|
+
languageHelp: t.languageHelp,
|
|
370
|
+
creativity: t.creativity,
|
|
371
|
+
creativityFocused: t.creativityFocused,
|
|
372
|
+
creativityCreative: t.creativityCreative,
|
|
373
|
+
maxLength: t.maxLength,
|
|
374
|
+
maxLengthHelp: t.maxLengthHelp,
|
|
375
|
+
maxLengthCeiling: t.maxLengthCeiling,
|
|
376
|
+
generate: t.generate,
|
|
225
377
|
}}
|
|
226
378
|
/>
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
type="button"
|
|
230
|
-
onClick={() => setStep('configure-gather')}
|
|
231
|
-
className="semiont-button--secondary semiont-button--flex"
|
|
232
|
-
>
|
|
233
|
-
◀ {t.back}
|
|
234
|
-
</button>
|
|
235
|
-
<button
|
|
236
|
-
type="button"
|
|
237
|
-
onClick={() => setStep('configure-generation')}
|
|
238
|
-
disabled={!context}
|
|
239
|
-
className="semiont-button--primary semiont-button--flex"
|
|
240
|
-
>
|
|
241
|
-
{t.next} ▶
|
|
242
|
-
</button>
|
|
243
|
-
</div>
|
|
244
|
-
</>
|
|
245
|
-
)}
|
|
246
|
-
|
|
247
|
-
{step === 'configure-generation' && context && (
|
|
248
|
-
<ConfigureGenerationStep
|
|
249
|
-
{...(generationAgent ? { generationAgent } : {})}
|
|
250
|
-
context={context}
|
|
251
|
-
config={generationDraft}
|
|
252
|
-
onConfigChange={setGenerationDraft}
|
|
253
|
-
onBack={() => setStep('review')}
|
|
254
|
-
onGenerate={handleGenerate}
|
|
255
|
-
translations={{
|
|
256
|
-
resourceTitle: t.resourceTitle,
|
|
257
|
-
resourceTitlePlaceholder: t.resourceTitlePlaceholder,
|
|
258
|
-
additionalInstructions: t.additionalInstructions,
|
|
259
|
-
additionalInstructionsPlaceholder: t.additionalInstructionsPlaceholder,
|
|
260
|
-
language: t.language,
|
|
261
|
-
languageHelp: t.languageHelp,
|
|
262
|
-
creativity: t.creativity,
|
|
263
|
-
creativityFocused: t.creativityFocused,
|
|
264
|
-
creativityCreative: t.creativityCreative,
|
|
265
|
-
maxLength: t.maxLength,
|
|
266
|
-
maxLengthHelp: t.maxLengthHelp,
|
|
267
|
-
maxLengthCeiling: t.maxLengthCeiling,
|
|
268
|
-
back: t.back,
|
|
269
|
-
generate: t.generate,
|
|
270
|
-
}}
|
|
271
|
-
/>
|
|
272
|
-
)}
|
|
379
|
+
)}
|
|
380
|
+
</div>
|
|
273
381
|
</DialogPanel>
|
|
274
382
|
</TransitionChild>
|
|
275
383
|
</div>
|