@semiont/react-ui 0.5.27 → 0.5.29
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/README.md +3 -3
- package/dist/{PdfAnnotationCanvas.client-EVUPTUWZ.js → PdfAnnotationCanvas.client-LSH3PZPY.js} +32 -5
- package/dist/{ar-OU3DQGC6.js → ar-AZBRADEB.js} +43 -23
- package/dist/{bn-PHWCR6AZ.js → bn-CCEW6AOS.js} +43 -23
- package/dist/{chunk-VXASXU4K.js → chunk-3ZBKCWUZ.js} +1 -1
- package/dist/{chunk-5VDTWRXJ.js → chunk-G4VHL4UA.js} +31 -31
- package/dist/{chunk-PCRRBU7H.js → chunk-SDKFZLEX.js} +43 -23
- package/dist/{cs-NEXYZ62I.js → cs-HXPF2CTE.js} +43 -23
- package/dist/{da-FAT43YCU.js → da-K5NTK7LH.js} +43 -23
- package/dist/{de-KRQ3WBCU.js → de-GMRQEDZI.js} +43 -23
- package/dist/{el-Q4IU3EKC.js → el-EUB4CI4G.js} +43 -23
- package/dist/{en-2KADE7N4.js → en-R5XA26NF.js} +2 -2
- package/dist/{es-2IO3R2MK.js → es-Z32DAZ6W.js} +43 -23
- package/dist/{fa-Q5GOQFXX.js → fa-G7HN6B32.js} +43 -23
- package/dist/{fi-R6NMRWBE.js → fi-3YBLZO7I.js} +43 -23
- package/dist/{fr-QY4D5E6J.js → fr-VUBH7BBS.js} +43 -23
- package/dist/{he-X6Y77XHY.js → he-WQQEY26B.js} +43 -23
- package/dist/{hi-XL7IOEQM.js → hi-HJZ6W4JB.js} +43 -23
- package/dist/{id-QZ4ZZS67.js → id-ZOGZ37MI.js} +43 -23
- package/dist/index.css +279 -74
- package/dist/index.d.ts +318 -393
- package/dist/index.js +2619 -2687
- package/dist/{it-ME2Q7OB6.js → it-DT6UW66F.js} +43 -23
- package/dist/{ja-HX7QASRI.js → ja-RUKQCOLO.js} +43 -23
- package/dist/{ko-EQO5AHAV.js → ko-ZH5ADKZM.js} +43 -23
- package/dist/{ms-UILFSF3I.js → ms-Y2AFPZTU.js} +43 -23
- package/dist/{nl-NNI45PMK.js → nl-OQEWIXNA.js} +43 -23
- package/dist/{no-MAL5F6P6.js → no-KPAYJZWY.js} +43 -23
- package/dist/{pl-4RMY6JAJ.js → pl-WSXK2UUD.js} +43 -23
- package/dist/{pt-VQH2X3QQ.js → pt-NWRJRUCK.js} +43 -23
- package/dist/{ro-XXCQO2OG.js → ro-3CGVMOC6.js} +43 -23
- package/dist/{sv-7Z6EJ6U4.js → sv-HGSEBA7S.js} +43 -23
- package/dist/test-utils.js +16 -7
- package/dist/{th-L3DXXYVQ.js → th-NZ4G352Z.js} +43 -23
- package/dist/{tr-P3DFVLFJ.js → tr-LGGS4DLW.js} +43 -23
- package/dist/{uk-7C5D3PXS.js → uk-AIX536L4.js} +43 -23
- package/dist/{vi-ZLTLEO7P.js → vi-V6CVQZLQ.js} +43 -23
- package/dist/{zh-5FHVWDIN.js → zh-AGKPGI3L.js} +43 -23
- package/package.json +16 -15
- package/src/components/AssistProgress.tsx +36 -2
- package/src/components/CodeMirrorRenderer.tsx +8 -8
- package/src/components/StatusDisplay.tsx +13 -13
- package/src/components/__tests__/AssistProgress.test.tsx +59 -0
- package/src/components/__tests__/StatusDisplay.test.tsx +9 -9
- package/src/components/modals/ComposeStep.tsx +233 -0
- package/src/components/modals/ConfigureGatherStep.tsx +10 -18
- package/src/components/modals/ConfigureGenerationStep.tsx +178 -34
- 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 +252 -59
- package/src/components/modals/ResourceGenerateModal.tsx +225 -112
- 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 +206 -8
- 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 +442 -39
- package/src/components/modals/__tests__/ResourceGenerateModal.test.tsx +300 -86
- package/src/components/modals/__tests__/SearchResultsStep.test.tsx +61 -0
- package/src/components/modals/__tests__/WizardFooter.test.tsx +116 -9
- 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 +8 -8
- package/src/components/resource/DownloadFileLink.tsx +1 -1
- 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.reference-hover.test.tsx +1 -1
- package/src/components/resource/__tests__/BrowseView.test.tsx +11 -11
- package/src/components/resource/__tests__/download-link.test.tsx +6 -6
- 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 +11 -4
- package/src/components/resource/panels/ReferencesPanel.tsx +9 -1
- 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.observable-flow.test.tsx +1 -1
- package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +84 -3
- package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +149 -7
- package/src/features/auth/__tests__/SignInForm.a11y.test.tsx +12 -12
- package/src/features/auth/components/SignInForm.tsx +53 -53
- package/src/features/auth-welcome/state/__tests__/welcome-state-unit.test.ts +2 -2
- package/src/features/resource-compose/__tests__/ResourceComposePage.test.tsx +0 -65
- package/src/features/resource-compose/components/ResourceComposePage.tsx +35 -133
- 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-discovery/__tests__/ResourceDiscoveryPage.test.tsx +1 -1
- package/src/features/resource-discovery/components/ResourceDiscoveryPage.tsx +2 -2
- package/src/features/resource-discovery/state/discover-state-unit.ts +1 -1
- package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +73 -17
- package/src/features/resource-viewer/__tests__/generation-options.test.ts +53 -0
- package/src/features/resource-viewer/components/ResourceViewerPage.tsx +148 -83
- package/src/features/resource-viewer/generation-options.ts +29 -0
- 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/src/styles/index.css +0 -1
- package/translations/ar.json +42 -22
- package/translations/bn.json +42 -22
- package/translations/cs.json +42 -22
- package/translations/da.json +42 -22
- package/translations/de.json +42 -22
- package/translations/el.json +42 -22
- package/translations/en.json +42 -22
- package/translations/es.json +42 -22
- package/translations/fa.json +42 -22
- package/translations/fi.json +42 -22
- package/translations/fr.json +42 -22
- package/translations/he.json +42 -22
- package/translations/hi.json +42 -22
- package/translations/id.json +42 -22
- package/translations/it.json +42 -22
- package/translations/ja.json +42 -22
- package/translations/ko.json +42 -22
- package/translations/ms.json +42 -22
- package/translations/nl.json +42 -22
- package/translations/no.json +42 -22
- package/translations/pl.json +42 -22
- package/translations/pt.json +42 -22
- package/translations/ro.json +42 -22
- package/translations/sv.json +42 -22
- package/translations/th.json +42 -22
- package/translations/tr.json +42 -22
- package/translations/uk.json +42 -22
- package/translations/vi.json +42 -22
- package/translations/zh.json +42 -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
- package/src/features/admin-exchange/__tests__/AdminExchangePage.test.tsx +0 -137
- package/src/features/admin-exchange/__tests__/ExportCard.test.tsx +0 -41
- package/src/features/admin-exchange/__tests__/ImportCard.test.tsx +0 -148
- package/src/features/admin-exchange/__tests__/ImportProgress.test.tsx +0 -117
- package/src/features/admin-exchange/components/AdminExchangePage.tsx +0 -117
- package/src/features/admin-exchange/components/ExportCard.tsx +0 -35
- package/src/features/admin-exchange/components/ImportCard.tsx +0 -183
- package/src/features/admin-exchange/components/ImportProgress.tsx +0 -80
- package/src/features/admin-exchange/state/__tests__/exchange-state-unit.test.ts +0 -185
- package/src/features/admin-exchange/state/exchange-state-unit.ts +0 -133
- package/src/features/moderation-linked-data/__tests__/LinkedDataPage.test.tsx +0 -118
- package/src/features/moderation-linked-data/components/LinkedDataPage.tsx +0 -118
- package/src/styles/features/exchange.css +0 -374
|
@@ -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
|
-
import { ConfigureGenerationStep, type GenerationConfig, type GenerationDraft } from './ConfigureGenerationStep';
|
|
10
|
+
import { ConfigureGenerationStep, freshGenerationDraft, 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;
|
|
@@ -43,7 +51,13 @@ export interface ResourceGenerateModalTranslations {
|
|
|
43
51
|
maxLength: string;
|
|
44
52
|
maxLengthHelp: string;
|
|
45
53
|
maxLengthCeiling: string;
|
|
54
|
+
outputFormat: string;
|
|
55
|
+
formatExtensionMismatch: string;
|
|
46
56
|
generate: string;
|
|
57
|
+
// DiscardPrompt (GATHER-AT-THE-TOP P1)
|
|
58
|
+
discardDraftPrompt: string;
|
|
59
|
+
discardDraft: string;
|
|
60
|
+
keepEditing: string;
|
|
47
61
|
}
|
|
48
62
|
|
|
49
63
|
export interface ResourceGenerateModalProps {
|
|
@@ -57,8 +71,9 @@ export interface ResourceGenerateModalProps {
|
|
|
57
71
|
onClose: () => void;
|
|
58
72
|
resourceId: string;
|
|
59
73
|
defaultTitle: string;
|
|
74
|
+
/** Folder of the source resource, so the artifact lands beside it (D11). */
|
|
75
|
+
defaultFolder?: string;
|
|
60
76
|
locale: string;
|
|
61
|
-
gatherDefaults?: Partial<ResourceGatherConfig>;
|
|
62
77
|
/**
|
|
63
78
|
* Entity types offered in the exclusion picker. Owner-supplied so the
|
|
64
79
|
* modal cannot present a failed load as an empty vocabulary.
|
|
@@ -70,70 +85,161 @@ export interface ResourceGenerateModalProps {
|
|
|
70
85
|
* annotation wizard delegates generation to its parent.
|
|
71
86
|
*/
|
|
72
87
|
onGenerateSubmit: (resourceId: string, config: GenerationConfig) => void;
|
|
88
|
+
/**
|
|
89
|
+
* Resource-gather state, verbatim from the SDK's gather unit slots
|
|
90
|
+
* (`gather.resourceContext$` / `resourceLoading$` / `resourceError$`) — the
|
|
91
|
+
* page reads the observables and threads them here, the same shape the
|
|
92
|
+
* reference wizard has always had (FLOW-LIFECYCLE-CONVERGENCE D3/A6). The
|
|
93
|
+
* modal renders this state; it never owns it.
|
|
94
|
+
*/
|
|
95
|
+
gatherContext: GatheredContext | null;
|
|
96
|
+
gatherLoading: boolean;
|
|
97
|
+
gatherError: Error | null;
|
|
98
|
+
/**
|
|
99
|
+
* Run the gather — the page wires `gather.gatherResource(resourceId, …)`.
|
|
100
|
+
* No resourceId in the payload: the owner already holds it. `gatherResource`
|
|
101
|
+
* clears its slots at start, so no reset threading is needed.
|
|
102
|
+
*/
|
|
103
|
+
onGather: (options: ResourceGatherOptions) => void;
|
|
73
104
|
translations: ResourceGenerateModalTranslations;
|
|
74
105
|
}
|
|
75
106
|
|
|
76
|
-
type Step = 'configure-gather' | 'review' | 'configure-generation';
|
|
77
|
-
|
|
78
107
|
/**
|
|
79
|
-
* Resource-generate flow (GENERATE-FROM-BUTTON
|
|
80
|
-
*
|
|
81
|
-
*
|
|
108
|
+
* Resource-generate flow (GENERATE-FROM-BUTTON, folded by GATHER-AT-THE-TOP):
|
|
109
|
+
* one composite stack in a single scroll pane — the gather controls at the
|
|
110
|
+
* top, the gathered `GatheredContext` below them once gather fires, and the
|
|
111
|
+
* generation params beneath the evidence once context arrives. Re-gathering
|
|
112
|
+
* is scroll-up → tweak → Gather; `gatherResource` clears its slots at start,
|
|
113
|
+
* so the evidence refreshes in place. [gather zone] → [evidence] → [act
|
|
114
|
+
* zone]: the same grammar the resolve wizard expresses, whose gather zone
|
|
115
|
+
* happens to be automatic and whose act zone has a strategy choice.
|
|
82
116
|
*/
|
|
83
117
|
export function ResourceGenerateModal({
|
|
84
118
|
isOpen,
|
|
85
119
|
onClose,
|
|
86
120
|
resourceId,
|
|
87
121
|
defaultTitle,
|
|
122
|
+
defaultFolder,
|
|
88
123
|
locale,
|
|
89
|
-
gatherDefaults,
|
|
90
124
|
entityTypeOptions = [],
|
|
91
125
|
onGenerateSubmit,
|
|
126
|
+
gatherContext,
|
|
127
|
+
gatherLoading,
|
|
128
|
+
gatherError,
|
|
129
|
+
onGather,
|
|
92
130
|
translations: t,
|
|
93
131
|
generationAgent,
|
|
94
132
|
}: ResourceGenerateModalProps) {
|
|
95
133
|
// Same draft ownership as the wizard (WIZARD-NAVIGATION D3): the step is
|
|
96
134
|
// controlled, so stepping back through this modal keeps what was typed.
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
temperature: 0.7, maxTokensText: '500',
|
|
100
|
-
});
|
|
135
|
+
const freshDraft = (): GenerationDraft => freshGenerationDraft(defaultTitle, locale);
|
|
136
|
+
const [generationDraft, setGenerationDraft] = useState<GenerationDraft>(freshDraft);
|
|
101
137
|
|
|
102
|
-
|
|
103
|
-
|
|
138
|
+
// "Has THIS run gathered yet?" — the page's gather slots survive across
|
|
139
|
+
// opens, so a context prop can be stale at open time. Nothing renders below
|
|
140
|
+
// the controls until the user fires a gather in this run.
|
|
141
|
+
const [gatherFired, setGatherFired] = useState(false);
|
|
142
|
+
// The fired snapshot feeds the receipt: what THIS gather actually asked
|
|
143
|
+
// for, exclusions included — not the form's live state, which the user can
|
|
144
|
+
// edit without re-firing.
|
|
145
|
+
const [lastGather, setLastGather] = useState<(ResourceGatherConfig & { excludeEntityTypes: string[] }) | null>(null);
|
|
146
|
+
const [editingGather, setEditingGather] = useState(false);
|
|
147
|
+
const [showDiscardPrompt, setShowDiscardPrompt] = useState(false);
|
|
104
148
|
// Supplied by the owner, which already tracks the list with its failure
|
|
105
149
|
// state. Fetching it here could only model (value | not-yet), so a failed
|
|
106
150
|
// load would render an empty exclusion picker as though the KB had no
|
|
107
151
|
// entity types. See .plans/PANEL-FAILURE-STATES.md
|
|
108
152
|
const [excludeEntityTypes, setExcludeEntityTypes] = useState<string[]>([]);
|
|
109
153
|
|
|
110
|
-
// Reset to the first step
|
|
154
|
+
// Reset to the first step ON OPENING — and re-seed the draft, because
|
|
155
|
+
// `defaultTitle` is the source resource's name and loads asynchronously: the
|
|
156
|
+
// useState initializer ran at mount, which for the real page was before the
|
|
157
|
+
// name existed (GFR A4). Guarded to the false→true transition so a name
|
|
158
|
+
// arriving mid-flow cannot clobber what the user has typed.
|
|
159
|
+
const wasOpen = useRef(false);
|
|
160
|
+
// The dirty baseline is what was SEEDED, not the live prop: defaultTitle
|
|
161
|
+
// can move while the modal is open (the source resource's name loads
|
|
162
|
+
// asynchronously), and an untouched draft must not read as dirty because
|
|
163
|
+
// the baseline moved under it.
|
|
164
|
+
const seededTitle = useRef(defaultTitle);
|
|
111
165
|
useEffect(() => {
|
|
112
|
-
if (isOpen) {
|
|
113
|
-
|
|
166
|
+
if (isOpen && !wasOpen.current) {
|
|
167
|
+
setGatherFired(false);
|
|
168
|
+
setLastGather(null);
|
|
169
|
+
setEditingGather(false);
|
|
114
170
|
setExcludeEntityTypes([]);
|
|
115
|
-
|
|
171
|
+
setGenerationDraft(freshDraft());
|
|
172
|
+
setShowDiscardPrompt(false);
|
|
173
|
+
seededTitle.current = defaultTitle;
|
|
116
174
|
}
|
|
117
|
-
|
|
175
|
+
wasOpen.current = isOpen;
|
|
176
|
+
// freshDraft reads defaultTitle/locale at call time; the effect keys on the
|
|
177
|
+
// OPENING, not on their drift while open.
|
|
178
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
179
|
+
}, [isOpen]);
|
|
118
180
|
|
|
119
181
|
const handleGather = useCallback((config: ResourceGatherConfig) => {
|
|
120
|
-
|
|
121
|
-
|
|
182
|
+
setGatherFired(true);
|
|
183
|
+
setLastGather({ ...config, excludeEntityTypes });
|
|
184
|
+
setEditingGather(false);
|
|
185
|
+
onGather({
|
|
122
186
|
...config,
|
|
123
187
|
...(excludeEntityTypes.length ? { excludeEntityTypes } : {}),
|
|
124
188
|
});
|
|
125
|
-
}, [
|
|
189
|
+
}, [onGather, excludeEntityTypes]);
|
|
126
190
|
|
|
127
191
|
const handleGenerate = useCallback((config: GenerationConfig) => {
|
|
128
192
|
onGenerateSubmit(resourceId, config);
|
|
129
193
|
onClose();
|
|
130
194
|
}, [onGenerateSubmit, resourceId, onClose]);
|
|
131
195
|
|
|
132
|
-
|
|
196
|
+
// D4/D5 (GATHER-AT-THE-TOP P1): typed text must not die with a dismissed
|
|
197
|
+
// modal. Toggles, depth, and exclusion picks are cheap to redo and never
|
|
198
|
+
// nag. Generate's completion path above bypasses this — the guard protects
|
|
199
|
+
// dismissal, not completion.
|
|
200
|
+
const draftDirty =
|
|
201
|
+
generationDraft.title !== seededTitle.current ||
|
|
202
|
+
generationDraft.storagePath.trim() !== '' ||
|
|
203
|
+
generationDraft.prompt.trim() !== '';
|
|
204
|
+
const handleDismiss = useCallback(() => {
|
|
205
|
+
if (draftDirty) {
|
|
206
|
+
setShowDiscardPrompt(true);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
onClose();
|
|
210
|
+
}, [draftDirty, onClose]);
|
|
211
|
+
|
|
212
|
+
// The whole stack is ONE scroll pane; when the params zone appears (context
|
|
213
|
+
// arrival — including each re-gather), enter at the BOTTOM so the
|
|
214
|
+
// parameters show in full, the evidence and controls tucked up under the
|
|
215
|
+
// modal top. jsdom has no layout (scrollHeight 0) — no-op in tests.
|
|
216
|
+
const stepScrollRef = useRef<HTMLDivElement>(null);
|
|
217
|
+
useEffect(() => {
|
|
218
|
+
const el = stepScrollRef.current;
|
|
219
|
+
if (el && gatherContext) el.scrollTop = el.scrollHeight;
|
|
220
|
+
}, [gatherContext]);
|
|
221
|
+
|
|
222
|
+
// The evidence zone: what the generation will be grounded in stays in view
|
|
223
|
+
// above the form.
|
|
224
|
+
const displayTranslations = {
|
|
225
|
+
loadingContext: t.loadingContext,
|
|
226
|
+
failedContext: t.failedContext,
|
|
227
|
+
sourceContextLabel: t.sourceContextLabel,
|
|
228
|
+
connectionsLabel: t.connectionsLabel,
|
|
229
|
+
citedByLabel: t.citedByLabel,
|
|
230
|
+
graphPaneTitle: t.graphPaneTitle,
|
|
231
|
+
graphEmpty: t.graphEmpty,
|
|
232
|
+
resourceLinkLabel: t.resourceLinkLabel,
|
|
233
|
+
corpusPaneTitle: t.corpusPaneTitle,
|
|
234
|
+
corpusEmpty: t.corpusEmpty,
|
|
235
|
+
excludedReceipt: t.excludedReceipt,
|
|
236
|
+
machineRead: t.machineRead,
|
|
237
|
+
score: t.score,
|
|
238
|
+
};
|
|
133
239
|
|
|
134
240
|
return (
|
|
135
241
|
<Transition appear show={isOpen}>
|
|
136
|
-
<Dialog as="div" className="semiont-search-modal" onClose={
|
|
242
|
+
<Dialog as="div" className="semiont-search-modal" onClose={handleDismiss}>
|
|
137
243
|
<TransitionChild
|
|
138
244
|
enter="ease-out duration-200"
|
|
139
245
|
enterFrom="opacity-0"
|
|
@@ -155,21 +261,53 @@ export function ResourceGenerateModal({
|
|
|
155
261
|
leaveFrom="opacity-100 scale-100"
|
|
156
262
|
leaveTo="opacity-0 scale-95"
|
|
157
263
|
>
|
|
158
|
-
<DialogPanel className="semiont-search-modal__panel semiont-search-modal__panel--with-border semiont-search-modal__panel--gather">
|
|
264
|
+
<DialogPanel className="semiont-search-modal__panel semiont-search-modal__panel--with-border semiont-search-modal__panel--gather semiont-search-modal__panel--wide">
|
|
159
265
|
<div className="semiont-search-modal__header">
|
|
160
|
-
<DialogTitle className="semiont-search-modal__title">{
|
|
161
|
-
<button onClick={
|
|
266
|
+
<DialogTitle className="semiont-search-modal__title">{t.title}</DialogTitle>
|
|
267
|
+
<button onClick={handleDismiss} className="semiont-search-modal__close-button" aria-label="Close">
|
|
162
268
|
✕
|
|
163
269
|
</button>
|
|
164
270
|
</div>
|
|
165
271
|
|
|
166
|
-
{
|
|
272
|
+
{showDiscardPrompt && (
|
|
273
|
+
<DiscardPrompt
|
|
274
|
+
prompt={t.discardDraftPrompt}
|
|
275
|
+
discardLabel={t.discardDraft}
|
|
276
|
+
keepLabel={t.keepEditing}
|
|
277
|
+
onDiscard={() => { setShowDiscardPrompt(false); onClose(); }}
|
|
278
|
+
onKeepEditing={() => setShowDiscardPrompt(false)}
|
|
279
|
+
/>
|
|
280
|
+
)}
|
|
281
|
+
|
|
282
|
+
<div className="semiont-wizard__step-scroll" ref={stepScrollRef}>
|
|
283
|
+
{/* Once fired, the spent controls fold into a receipt of
|
|
284
|
+
what THIS gather asked for — the evidence leads the
|
|
285
|
+
pane, the parameters stay visible and revisable. The
|
|
286
|
+
form below is HIDDEN, not unmounted, so its values
|
|
287
|
+
survive for the expand path. */}
|
|
288
|
+
{gatherFired && !editingGather && lastGather && (
|
|
289
|
+
<button
|
|
290
|
+
type="button"
|
|
291
|
+
className="semiont-gather-receipt"
|
|
292
|
+
title={t.editGather}
|
|
293
|
+
onClick={() => setEditingGather(true)}
|
|
294
|
+
>
|
|
295
|
+
{[
|
|
296
|
+
`${t.gatherDepth} ${lastGather.depth}`,
|
|
297
|
+
`${t.gatherMaxResources} ${lastGather.maxResources}`,
|
|
298
|
+
...(lastGather.includeContent ? [t.includeContent] : []),
|
|
299
|
+
...(lastGather.includeSummary ? [t.includeSummary] : []),
|
|
300
|
+
...(lastGather.excludeEntityTypes.length
|
|
301
|
+
? [t.excludedReceipt.replace('{{types}}', lastGather.excludeEntityTypes.join(', '))]
|
|
302
|
+
: []),
|
|
303
|
+
].join(' · ')}
|
|
304
|
+
<span aria-hidden="true"> ✎</span>
|
|
305
|
+
</button>
|
|
306
|
+
)}
|
|
307
|
+
<div hidden={gatherFired && !editingGather}>
|
|
167
308
|
<ConfigureGatherStep
|
|
168
|
-
defaults={gatherDefaults}
|
|
169
309
|
onGather={handleGather}
|
|
170
|
-
onCancel={onClose}
|
|
171
310
|
translations={{
|
|
172
|
-
cancel: t.cancel,
|
|
173
311
|
intro: t.gatherIntro,
|
|
174
312
|
includeContent: t.includeContent,
|
|
175
313
|
includeSummary: t.includeSummary,
|
|
@@ -180,17 +318,21 @@ export function ResourceGenerateModal({
|
|
|
180
318
|
>
|
|
181
319
|
{entityTypeOptions.length > 0 && (
|
|
182
320
|
<div className="semiont-form__field semiont-form__entity-types">
|
|
183
|
-
<label className="semiont-form__label">{t.
|
|
184
|
-
|
|
321
|
+
<label className="semiont-form__label">{t.recallLabel}</label>
|
|
322
|
+
{/* Recall chips — the exclude wire, inverted for the
|
|
323
|
+
UI: every type is IN the recall until crossed off,
|
|
324
|
+
so the state is still the exclude list and a chip
|
|
325
|
+
is included when absent from it. */}
|
|
326
|
+
<div className="semiont-form__recall-chips">
|
|
185
327
|
{entityTypeOptions.map((et) => {
|
|
186
|
-
const
|
|
328
|
+
const isIncluded = !excludeEntityTypes.includes(et);
|
|
187
329
|
return (
|
|
188
330
|
<button
|
|
189
331
|
key={et}
|
|
190
332
|
type="button"
|
|
191
|
-
className="semiont-
|
|
192
|
-
data-
|
|
193
|
-
aria-pressed={
|
|
333
|
+
className="semiont-form__recall-chip"
|
|
334
|
+
data-included={isIncluded}
|
|
335
|
+
aria-pressed={isIncluded}
|
|
194
336
|
onClick={() => setExcludeEntityTypes(prev => prev.includes(et) ? prev.filter(x => x !== et) : [...prev, et])}
|
|
195
337
|
>
|
|
196
338
|
{et}
|
|
@@ -201,75 +343,46 @@ export function ResourceGenerateModal({
|
|
|
201
343
|
</div>
|
|
202
344
|
)}
|
|
203
345
|
</ConfigureGatherStep>
|
|
204
|
-
|
|
346
|
+
</div>
|
|
205
347
|
|
|
206
|
-
|
|
207
|
-
<>
|
|
348
|
+
{gatherFired && (
|
|
208
349
|
<GatherContextStep
|
|
209
|
-
context={
|
|
210
|
-
contextLoading={
|
|
211
|
-
contextError={
|
|
350
|
+
context={gatherContext}
|
|
351
|
+
contextLoading={gatherLoading}
|
|
352
|
+
contextError={gatherError}
|
|
353
|
+
translations={displayTranslations}
|
|
354
|
+
/>
|
|
355
|
+
)}
|
|
356
|
+
|
|
357
|
+
{gatherFired && gatherContext && (
|
|
358
|
+
<ConfigureGenerationStep
|
|
359
|
+
{...(generationAgent ? { generationAgent } : {})}
|
|
360
|
+
context={gatherContext}
|
|
361
|
+
config={generationDraft}
|
|
362
|
+
onConfigChange={setGenerationDraft}
|
|
363
|
+
defaultFolder={defaultFolder}
|
|
364
|
+
onGenerate={handleGenerate}
|
|
212
365
|
translations={{
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
366
|
+
resourceTitle: t.resourceTitle,
|
|
367
|
+
resourceTitlePlaceholder: t.resourceTitlePlaceholder,
|
|
368
|
+
saveLocation: t.saveLocation,
|
|
369
|
+
additionalInstructions: t.additionalInstructions,
|
|
370
|
+
additionalInstructionsPlaceholder: t.additionalInstructionsPlaceholder,
|
|
371
|
+
language: t.language,
|
|
372
|
+
languageHelp: t.languageHelp,
|
|
373
|
+
creativity: t.creativity,
|
|
374
|
+
creativityFocused: t.creativityFocused,
|
|
375
|
+
creativityCreative: t.creativityCreative,
|
|
376
|
+
maxLength: t.maxLength,
|
|
377
|
+
maxLengthHelp: t.maxLengthHelp,
|
|
378
|
+
maxLengthCeiling: t.maxLengthCeiling,
|
|
379
|
+
outputFormat: t.outputFormat,
|
|
380
|
+
formatExtensionMismatch: t.formatExtensionMismatch,
|
|
381
|
+
generate: t.generate,
|
|
225
382
|
}}
|
|
226
383
|
/>
|
|
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
|
-
)}
|
|
384
|
+
)}
|
|
385
|
+
</div>
|
|
273
386
|
</DialogPanel>
|
|
274
387
|
</TransitionChild>
|
|
275
388
|
</div>
|