@semiont/react-ui 0.5.9 → 0.5.11
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 +1 -1
- package/dist/{PdfAnnotationCanvas.client-U4EVBZEV.js → PdfAnnotationCanvas.client-KWQ7XDWT.js} +5 -2
- package/dist/PdfAnnotationCanvas.client-KWQ7XDWT.js.map +1 -0
- package/dist/{ar-WA47UUWA.js → ar-ZHKO4XDR.js} +45 -4
- package/dist/ar-ZHKO4XDR.js.map +1 -0
- package/dist/{bn-5ANDRIU6.js → bn-3BUDKAK5.js} +45 -4
- package/dist/bn-3BUDKAK5.js.map +1 -0
- package/dist/{chunk-YBGN4ACY.js → chunk-O23TLLXW.js} +1 -6
- package/dist/{chunk-WHUGODTB.js → chunk-PFUXQPWJ.js} +127 -127
- package/dist/{chunk-WHUGODTB.js.map → chunk-PFUXQPWJ.js.map} +1 -1
- package/dist/{chunk-GERSK2DY.js → chunk-R52YAGHK.js} +42 -1
- package/dist/chunk-R52YAGHK.js.map +1 -0
- package/dist/{cs-3RU7F4JX.js → cs-2EFEUKTW.js} +45 -4
- package/dist/cs-2EFEUKTW.js.map +1 -0
- package/dist/{da-GSW5P5HG.js → da-SUD3Q44Q.js} +45 -4
- package/dist/da-SUD3Q44Q.js.map +1 -0
- package/dist/{de-JUAUYF4Z.js → de-6IC5QRX7.js} +45 -4
- package/dist/de-6IC5QRX7.js.map +1 -0
- package/dist/{el-JNLWCKEC.js → el-Q4NAXFRC.js} +45 -4
- package/dist/el-Q4NAXFRC.js.map +1 -0
- package/dist/{en-RBN2GUHF.js → en-P2L4X27N.js} +5 -3
- package/dist/{es-WPOX225H.js → es-YUKZBD4W.js} +45 -4
- package/dist/es-YUKZBD4W.js.map +1 -0
- package/dist/{fa-TAEP6N77.js → fa-OJ47LILE.js} +45 -4
- package/dist/fa-OJ47LILE.js.map +1 -0
- package/dist/{fi-ZVZHANSP.js → fi-QFFL5CUB.js} +45 -4
- package/dist/fi-QFFL5CUB.js.map +1 -0
- package/dist/{fr-VLZW7M4N.js → fr-BOQZZWP4.js} +45 -4
- package/dist/fr-BOQZZWP4.js.map +1 -0
- package/dist/{he-QFAFYA77.js → he-LXDY3TFA.js} +45 -4
- package/dist/he-LXDY3TFA.js.map +1 -0
- package/dist/{hi-AO3DQPCV.js → hi-HOJER77V.js} +45 -4
- package/dist/hi-HOJER77V.js.map +1 -0
- package/dist/{id-GTXF42WM.js → id-I5WQ6EWD.js} +45 -4
- package/dist/id-I5WQ6EWD.js.map +1 -0
- package/dist/index.css +150 -112
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +403 -45
- package/dist/index.js +4660 -18860
- package/dist/index.js.map +1 -1
- package/dist/integrations/css-modules-helper.js +1 -1
- package/dist/integrations/styled-components-theme.js +1 -1
- package/dist/{it-AS5GM232.js → it-UYH642IJ.js} +45 -4
- package/dist/it-UYH642IJ.js.map +1 -0
- package/dist/{ja-GZ4HLUOF.js → ja-JTVWAC4L.js} +45 -4
- package/dist/ja-JTVWAC4L.js.map +1 -0
- package/dist/{ko-A4XUXFGJ.js → ko-IHXFMOIZ.js} +45 -4
- package/dist/ko-IHXFMOIZ.js.map +1 -0
- package/dist/{ms-YBAO3S6K.js → ms-JH25VFLO.js} +45 -4
- package/dist/ms-JH25VFLO.js.map +1 -0
- package/dist/{nl-3TJGIIIU.js → nl-SURXW7IQ.js} +45 -4
- package/dist/nl-SURXW7IQ.js.map +1 -0
- package/dist/{no-4AXIQPRQ.js → no-HXIKQFDZ.js} +45 -4
- package/dist/no-HXIKQFDZ.js.map +1 -0
- package/dist/{pl-5GP6GKXO.js → pl-7A4KU6XK.js} +45 -4
- package/dist/pl-7A4KU6XK.js.map +1 -0
- package/dist/{pt-26Y6JFG5.js → pt-6MGYP7Q5.js} +45 -4
- package/dist/pt-6MGYP7Q5.js.map +1 -0
- package/dist/{ro-C7UXFRWJ.js → ro-IROCHNIA.js} +45 -4
- package/dist/ro-IROCHNIA.js.map +1 -0
- package/dist/{sv-44DVD76T.js → sv-WDJD75CV.js} +45 -4
- package/dist/sv-WDJD75CV.js.map +1 -0
- package/dist/test-utils.js +9 -4
- package/dist/test-utils.js.map +1 -1
- package/dist/{th-GIQRTBOY.js → th-RIO2E6B3.js} +45 -4
- package/dist/th-RIO2E6B3.js.map +1 -0
- package/dist/{tr-WMQWO4D6.js → tr-TZ7ERCIN.js} +45 -4
- package/dist/tr-TZ7ERCIN.js.map +1 -0
- package/dist/{uk-I7ML6RGG.js → uk-ZFWDKLUE.js} +45 -4
- package/dist/uk-ZFWDKLUE.js.map +1 -0
- package/dist/{vi-FGWECASQ.js → vi-UIOSP2JG.js} +45 -4
- package/dist/vi-UIOSP2JG.js.map +1 -0
- package/dist/{zh-L5FN73XC.js → zh-6R6YUY46.js} +45 -4
- package/dist/zh-6R6YUY46.js.map +1 -0
- package/package.json +18 -9
- package/src/components/AnnotateReferencesProgressWidget.tsx +35 -16
- package/src/components/ResourceTagsInline.tsx +94 -11
- package/src/components/StatusDisplay.css +36 -0
- package/src/components/__tests__/AnnotateReferencesProgressWidget.test.tsx +41 -91
- package/src/components/__tests__/ResourceTagsInline.test.tsx +101 -3
- package/src/components/annotation/AnnotateToolbar.tsx +53 -28
- package/src/components/annotation/__tests__/AnnotateToolbar.display.test.tsx +76 -0
- package/src/components/annotation/__tests__/AnnotateToolbar.test.tsx +124 -360
- package/src/components/image-annotation/SvgDrawingCanvas.tsx +5 -1
- package/src/components/modals/ConfigureGatherStep.tsx +102 -0
- package/src/components/modals/ContextSummary.tsx +15 -6
- package/src/components/modals/GatherContextStep.tsx +104 -59
- package/src/components/modals/ResourceGenerateModal.tsx +258 -0
- package/src/components/modals/__tests__/ConfigureGatherStep.test.tsx +82 -0
- package/src/components/modals/__tests__/GatherContextStep.resource.test.tsx +107 -0
- package/src/components/modals/__tests__/ResourceGenerateModal.test.tsx +197 -0
- package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +5 -0
- package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +6 -6
- package/src/components/resource/AnnotateView.tsx +59 -38
- package/src/components/resource/BrowseView.tsx +159 -133
- package/src/components/resource/ResourceViewer.tsx +119 -128
- package/src/components/resource/__tests__/AnnotateView.embeddable.test.tsx +55 -0
- package/src/components/resource/__tests__/BrowseView.embeddable.test.tsx +49 -0
- package/src/components/resource/__tests__/BrowseView.links.test.tsx +60 -0
- package/src/components/resource/__tests__/BrowseView.overlay-async.test.tsx +113 -0
- package/src/components/resource/__tests__/BrowseView.reference-hover.test.tsx +161 -0
- package/src/components/resource/__tests__/BrowseView.registry.test.tsx +43 -0
- package/src/components/resource/__tests__/BrowseView.test.tsx +35 -22
- package/src/components/resource/__tests__/ResourceViewer.embeddable.test.tsx +63 -0
- package/src/components/resource/__tests__/ResourceViewer.mode-switch.test.tsx +12 -7
- package/src/components/resource/__tests__/ResourceViewer.toolbar-opt-out.test.tsx +135 -0
- package/src/components/resource/__tests__/ResourceViewer.toolbar-prefs.test.tsx +200 -0
- package/src/components/resource/__tests__/browse-renderers.test.tsx +34 -0
- package/src/components/resource/__tests__/inline-embedding.test.tsx +81 -0
- package/src/components/resource/__tests__/media-completeness.test.tsx +88 -0
- package/src/components/resource/browse-renderers.tsx +63 -0
- package/src/components/resource/panels/AssessmentPanel.tsx +4 -0
- package/src/components/resource/panels/CommentsPanel.tsx +4 -0
- package/src/components/resource/panels/HighlightPanel.tsx +4 -0
- package/src/components/resource/panels/ReferencesPanel.tsx +14 -0
- package/src/components/resource/panels/ResourceInfoPanel.tsx +22 -0
- package/src/components/resource/panels/TaggingPanel.tsx +4 -0
- package/src/components/resource/panels/UnifiedAnnotationsPanel.tsx +5 -2
- package/src/components/resource/panels/__tests__/AssessmentPanel.test.tsx +1 -0
- package/src/components/resource/panels/__tests__/CommentsPanel.test.tsx +1 -0
- package/src/components/resource/panels/__tests__/HighlightPanel.annotationProgress.test.tsx +16 -16
- package/src/components/resource/panels/__tests__/ReferencesPanel.observable-flow.test.tsx +1 -1
- package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +1 -0
- package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +26 -0
- package/src/components/resource/panels/__tests__/TaggingPanel.test.tsx +1 -0
- package/src/components/toolbar/Toolbar.css +14 -0
- package/src/features/admin-exchange/state/__tests__/exchange-state-unit.test.ts +14 -0
- package/src/features/admin-exchange/state/exchange-state-unit.ts +4 -2
- package/src/features/admin-security/state/__tests__/admin-security-state-unit.test.ts +14 -0
- package/src/features/admin-security/state/admin-security-state-unit.ts +4 -2
- package/src/features/admin-users/state/__tests__/admin-users-state-unit.test.ts +12 -5
- package/src/features/admin-users/state/admin-users-state-unit.ts +4 -2
- package/src/features/auth-welcome/state/__tests__/welcome-state-unit.test.ts +11 -0
- package/src/features/auth-welcome/state/welcome-state-unit.ts +1 -1
- package/src/features/moderate-entity-tags/state/__tests__/entity-tags-state-unit.test.ts +14 -0
- package/src/features/moderate-entity-tags/state/entity-tags-state-unit.ts +4 -2
- package/src/features/resource-compose/components/ResourceComposePage.tsx +13 -7
- package/src/features/resource-compose/state/__tests__/compose-page-state-unit.test.ts +13 -0
- package/src/features/resource-compose/state/compose-page-state-unit.ts +5 -2
- package/src/features/resource-discovery/state/__tests__/discover-state-unit.test.ts +15 -9
- package/src/features/resource-discovery/state/discover-state-unit.ts +5 -2
- package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +7 -17
- package/src/features/resource-viewer/components/ResourceViewerPage.tsx +119 -17
- package/src/features/resource-viewer/state/__tests__/resource-loader-state-unit.test.ts +11 -0
- package/src/features/resource-viewer/state/__tests__/resource-viewer-page-state-unit.test.ts +30 -0
- package/src/features/resource-viewer/state/resource-loader-state-unit.ts +1 -1
- package/src/features/resource-viewer/state/resource-viewer-page-state-unit.ts +7 -16
- package/src/styles/features/resource-viewer.css +19 -0
- package/translations/ar.json +41 -2
- package/translations/bn.json +41 -2
- package/translations/cs.json +41 -2
- package/translations/da.json +41 -2
- package/translations/de.json +41 -2
- package/translations/el.json +41 -2
- package/translations/en.json +39 -0
- package/translations/es.json +41 -2
- package/translations/fa.json +41 -2
- package/translations/fi.json +41 -2
- package/translations/fr.json +41 -2
- package/translations/he.json +41 -2
- package/translations/hi.json +41 -2
- package/translations/id.json +41 -2
- package/translations/it.json +41 -2
- package/translations/ja.json +41 -2
- package/translations/ko.json +41 -2
- package/translations/ms.json +41 -2
- package/translations/nl.json +41 -2
- package/translations/no.json +41 -2
- package/translations/pl.json +41 -2
- package/translations/pt.json +41 -2
- package/translations/ro.json +41 -2
- package/translations/sv.json +41 -2
- package/translations/th.json +41 -2
- package/translations/tr.json +41 -2
- package/translations/uk.json +41 -2
- package/translations/vi.json +41 -2
- package/translations/zh.json +41 -2
- package/dist/PdfAnnotationCanvas.client-U4EVBZEV.js.map +0 -1
- package/dist/ar-WA47UUWA.js.map +0 -1
- package/dist/bn-5ANDRIU6.js.map +0 -1
- package/dist/chunk-GERSK2DY.js.map +0 -1
- package/dist/cs-3RU7F4JX.js.map +0 -1
- package/dist/da-GSW5P5HG.js.map +0 -1
- package/dist/de-JUAUYF4Z.js.map +0 -1
- package/dist/el-JNLWCKEC.js.map +0 -1
- package/dist/es-WPOX225H.js.map +0 -1
- package/dist/fa-TAEP6N77.js.map +0 -1
- package/dist/fi-ZVZHANSP.js.map +0 -1
- package/dist/fr-VLZW7M4N.js.map +0 -1
- package/dist/he-QFAFYA77.js.map +0 -1
- package/dist/hi-AO3DQPCV.js.map +0 -1
- package/dist/id-GTXF42WM.js.map +0 -1
- package/dist/it-AS5GM232.js.map +0 -1
- package/dist/ja-GZ4HLUOF.js.map +0 -1
- package/dist/ko-A4XUXFGJ.js.map +0 -1
- package/dist/ms-YBAO3S6K.js.map +0 -1
- package/dist/nl-3TJGIIIU.js.map +0 -1
- package/dist/no-4AXIQPRQ.js.map +0 -1
- package/dist/pl-5GP6GKXO.js.map +0 -1
- package/dist/pt-26Y6JFG5.js.map +0 -1
- package/dist/ro-C7UXFRWJ.js.map +0 -1
- package/dist/sv-44DVD76T.js.map +0 -1
- package/dist/th-GIQRTBOY.js.map +0 -1
- package/dist/tr-WMQWO4D6.js.map +0 -1
- package/dist/uk-I7ML6RGG.js.map +0 -1
- package/dist/vi-FGWECASQ.js.map +0 -1
- package/dist/zh-L5FN73XC.js.map +0 -1
- /package/dist/{chunk-YBGN4ACY.js.map → chunk-O23TLLXW.js.map} +0 -0
- /package/dist/{en-RBN2GUHF.js.map → en-P2L4X27N.js.map} +0 -0
|
@@ -59,8 +59,9 @@ interface UnifiedAnnotationsPanelProps {
|
|
|
59
59
|
referencedBy?: any[];
|
|
60
60
|
referencedByLoading?: boolean;
|
|
61
61
|
|
|
62
|
-
// Resource context
|
|
63
|
-
|
|
62
|
+
// Resource context — threaded to every per-motivation panel, which stamps it
|
|
63
|
+
// as `source` on mark:submit (multi-viewer routing).
|
|
64
|
+
resourceId: string;
|
|
64
65
|
initialTab?: TabKey;
|
|
65
66
|
initialTabGeneration?: number; // Generation counter for tab switching
|
|
66
67
|
|
|
@@ -244,6 +245,7 @@ export function UnifiedAnnotationsPanel(props: UnifiedAnnotationsPanelProps) {
|
|
|
244
245
|
|
|
245
246
|
// Common props for all annotation panels
|
|
246
247
|
const commonProps = {
|
|
248
|
+
resourceId: props.resourceId,
|
|
247
249
|
annotations,
|
|
248
250
|
pendingAnnotation: props.pendingAnnotation,
|
|
249
251
|
isAssisting,
|
|
@@ -268,6 +270,7 @@ export function UnifiedAnnotationsPanel(props: UnifiedAnnotationsPanelProps) {
|
|
|
268
270
|
if (activeTab === 'reference') {
|
|
269
271
|
return (
|
|
270
272
|
<ReferencesPanel
|
|
273
|
+
resourceId={commonProps.resourceId}
|
|
271
274
|
annotations={commonProps.annotations}
|
|
272
275
|
pendingAnnotation={commonProps.pendingAnnotation}
|
|
273
276
|
isAssisting={commonProps.isAssisting}
|
|
@@ -74,7 +74,7 @@ describe('HighlightPanel + AssistSection Integration', () => {
|
|
|
74
74
|
describe('Detection Progress Prop Passing', () => {
|
|
75
75
|
it('should pass progress to AssistSection when provided', () => {
|
|
76
76
|
renderWithProviders(
|
|
77
|
-
<HighlightPanel
|
|
77
|
+
<HighlightPanel resourceId="res-1"
|
|
78
78
|
annotations={mockAnnotations}
|
|
79
79
|
pendingAnnotation={null}
|
|
80
80
|
isAssisting={true}
|
|
@@ -93,7 +93,7 @@ describe('HighlightPanel + AssistSection Integration', () => {
|
|
|
93
93
|
|
|
94
94
|
it('should pass null progress to AssistSection', () => {
|
|
95
95
|
renderWithProviders(
|
|
96
|
-
<HighlightPanel
|
|
96
|
+
<HighlightPanel resourceId="res-1"
|
|
97
97
|
annotations={mockAnnotations}
|
|
98
98
|
pendingAnnotation={null}
|
|
99
99
|
isAssisting={false}
|
|
@@ -109,7 +109,7 @@ describe('HighlightPanel + AssistSection Integration', () => {
|
|
|
109
109
|
|
|
110
110
|
it('should pass undefined progress to AssistSection', () => {
|
|
111
111
|
renderWithProviders(
|
|
112
|
-
<HighlightPanel
|
|
112
|
+
<HighlightPanel resourceId="res-1"
|
|
113
113
|
annotations={mockAnnotations}
|
|
114
114
|
pendingAnnotation={null}
|
|
115
115
|
isAssisting={false}
|
|
@@ -125,7 +125,7 @@ describe('HighlightPanel + AssistSection Integration', () => {
|
|
|
125
125
|
|
|
126
126
|
it('should keep progress visible after detection completes (isAssisting=false)', () => {
|
|
127
127
|
renderWithProviders(
|
|
128
|
-
<HighlightPanel
|
|
128
|
+
<HighlightPanel resourceId="res-1"
|
|
129
129
|
annotations={mockAnnotations}
|
|
130
130
|
pendingAnnotation={null}
|
|
131
131
|
isAssisting={false}
|
|
@@ -146,7 +146,7 @@ describe('HighlightPanel + AssistSection Integration', () => {
|
|
|
146
146
|
|
|
147
147
|
it('should pass progress with request parameters to AssistSection', () => {
|
|
148
148
|
renderWithProviders(
|
|
149
|
-
<HighlightPanel
|
|
149
|
+
<HighlightPanel resourceId="res-1"
|
|
150
150
|
annotations={mockAnnotations}
|
|
151
151
|
pendingAnnotation={null}
|
|
152
152
|
isAssisting={true}
|
|
@@ -172,7 +172,7 @@ describe('HighlightPanel + AssistSection Integration', () => {
|
|
|
172
172
|
describe('Annotate Mode Toggling', () => {
|
|
173
173
|
it('should render AssistSection when annotateMode is true', () => {
|
|
174
174
|
renderWithProviders(
|
|
175
|
-
<HighlightPanel
|
|
175
|
+
<HighlightPanel resourceId="res-1"
|
|
176
176
|
annotations={mockAnnotations}
|
|
177
177
|
pendingAnnotation={null}
|
|
178
178
|
isAssisting={false}
|
|
@@ -186,7 +186,7 @@ describe('HighlightPanel + AssistSection Integration', () => {
|
|
|
186
186
|
|
|
187
187
|
it('should NOT render AssistSection when annotateMode is false', () => {
|
|
188
188
|
renderWithProviders(
|
|
189
|
-
<HighlightPanel
|
|
189
|
+
<HighlightPanel resourceId="res-1"
|
|
190
190
|
annotations={mockAnnotations}
|
|
191
191
|
pendingAnnotation={null}
|
|
192
192
|
isAssisting={false}
|
|
@@ -200,7 +200,7 @@ describe('HighlightPanel + AssistSection Integration', () => {
|
|
|
200
200
|
|
|
201
201
|
it('should hide progress when switching to browse mode (annotateMode=false)', () => {
|
|
202
202
|
const { rerender } = renderWithProviders(
|
|
203
|
-
<HighlightPanel
|
|
203
|
+
<HighlightPanel resourceId="res-1"
|
|
204
204
|
annotations={mockAnnotations}
|
|
205
205
|
pendingAnnotation={null}
|
|
206
206
|
isAssisting={true}
|
|
@@ -217,7 +217,7 @@ describe('HighlightPanel + AssistSection Integration', () => {
|
|
|
217
217
|
|
|
218
218
|
// Switch to browse mode
|
|
219
219
|
rerender(
|
|
220
|
-
<HighlightPanel
|
|
220
|
+
<HighlightPanel resourceId="res-1"
|
|
221
221
|
annotations={mockAnnotations}
|
|
222
222
|
pendingAnnotation={null}
|
|
223
223
|
isAssisting={true}
|
|
@@ -238,7 +238,7 @@ describe('HighlightPanel + AssistSection Integration', () => {
|
|
|
238
238
|
describe('State Combinations', () => {
|
|
239
239
|
it('should handle isAssisting=true with no progress (starting state)', () => {
|
|
240
240
|
renderWithProviders(
|
|
241
|
-
<HighlightPanel
|
|
241
|
+
<HighlightPanel resourceId="res-1"
|
|
242
242
|
annotations={mockAnnotations}
|
|
243
243
|
pendingAnnotation={null}
|
|
244
244
|
isAssisting={true}
|
|
@@ -253,7 +253,7 @@ describe('HighlightPanel + AssistSection Integration', () => {
|
|
|
253
253
|
|
|
254
254
|
it('should handle isAssisting=false with progress (final state)', () => {
|
|
255
255
|
renderWithProviders(
|
|
256
|
-
<HighlightPanel
|
|
256
|
+
<HighlightPanel resourceId="res-1"
|
|
257
257
|
annotations={mockAnnotations}
|
|
258
258
|
pendingAnnotation={null}
|
|
259
259
|
isAssisting={false}
|
|
@@ -274,7 +274,7 @@ describe('HighlightPanel + AssistSection Integration', () => {
|
|
|
274
274
|
|
|
275
275
|
it('should handle multiple progress updates', () => {
|
|
276
276
|
const { rerender } = renderWithProviders(
|
|
277
|
-
<HighlightPanel
|
|
277
|
+
<HighlightPanel resourceId="res-1"
|
|
278
278
|
annotations={mockAnnotations}
|
|
279
279
|
pendingAnnotation={null}
|
|
280
280
|
isAssisting={true}
|
|
@@ -291,7 +291,7 @@ describe('HighlightPanel + AssistSection Integration', () => {
|
|
|
291
291
|
|
|
292
292
|
// Update to analyzing
|
|
293
293
|
rerender(
|
|
294
|
-
<HighlightPanel
|
|
294
|
+
<HighlightPanel resourceId="res-1"
|
|
295
295
|
annotations={mockAnnotations}
|
|
296
296
|
pendingAnnotation={null}
|
|
297
297
|
isAssisting={true}
|
|
@@ -309,7 +309,7 @@ describe('HighlightPanel + AssistSection Integration', () => {
|
|
|
309
309
|
|
|
310
310
|
// Update to complete
|
|
311
311
|
rerender(
|
|
312
|
-
<HighlightPanel
|
|
312
|
+
<HighlightPanel resourceId="res-1"
|
|
313
313
|
annotations={mockAnnotations}
|
|
314
314
|
pendingAnnotation={null}
|
|
315
315
|
isAssisting={false}
|
|
@@ -330,7 +330,7 @@ describe('HighlightPanel + AssistSection Integration', () => {
|
|
|
330
330
|
describe('Highlights List Rendering', () => {
|
|
331
331
|
it('should render highlights list alongside detection progress', () => {
|
|
332
332
|
renderWithProviders(
|
|
333
|
-
<HighlightPanel
|
|
333
|
+
<HighlightPanel resourceId="res-1"
|
|
334
334
|
annotations={mockAnnotations}
|
|
335
335
|
pendingAnnotation={null}
|
|
336
336
|
isAssisting={true}
|
|
@@ -350,7 +350,7 @@ describe('HighlightPanel + AssistSection Integration', () => {
|
|
|
350
350
|
|
|
351
351
|
it('should show empty state when no highlights', () => {
|
|
352
352
|
renderWithProviders(
|
|
353
|
-
<HighlightPanel
|
|
353
|
+
<HighlightPanel resourceId="res-1"
|
|
354
354
|
annotations={[]}
|
|
355
355
|
pendingAnnotation={null}
|
|
356
356
|
isAssisting={false}
|
|
@@ -69,7 +69,7 @@ const mockRoutes = { resourceDetail: (id: string) => `/resource/${id}` } as any;
|
|
|
69
69
|
function ObservableHarness({ source$ }: { source$: BehaviorSubject<string[]> }) {
|
|
70
70
|
const entityTypes = useObservable(source$) ?? [];
|
|
71
71
|
return (
|
|
72
|
-
<ReferencesPanel
|
|
72
|
+
<ReferencesPanel resourceId="res-1"
|
|
73
73
|
annotations={[]}
|
|
74
74
|
isAssisting={false}
|
|
75
75
|
progress={null}
|
|
@@ -20,6 +20,8 @@ vi.mock('../../../../contexts/TranslationContext', () => ({
|
|
|
20
20
|
storageUri: 'Storage',
|
|
21
21
|
clone: 'Clone',
|
|
22
22
|
cloneDescription: 'Generate a shareable clone link for this resource',
|
|
23
|
+
generate: 'Generate',
|
|
24
|
+
generateDescription: "Generate a new resource from this one's context",
|
|
23
25
|
archive: 'Archive',
|
|
24
26
|
archiveDescription: 'Move this resource to archived status',
|
|
25
27
|
unarchive: 'Unarchive',
|
|
@@ -269,6 +271,30 @@ describe('ResourceInfoPanel Component', () => {
|
|
|
269
271
|
});
|
|
270
272
|
});
|
|
271
273
|
|
|
274
|
+
describe('Generate Action', () => {
|
|
275
|
+
it('renders the Generate button when onGenerate is provided', () => {
|
|
276
|
+
renderWithEventBus(
|
|
277
|
+
<ResourceInfoPanel {...defaultProps} onGenerate={() => {}} />
|
|
278
|
+
);
|
|
279
|
+
expect(screen.getByRole('button', { name: /Generate/i })).toBeInTheDocument();
|
|
280
|
+
expect(screen.getByText("Generate a new resource from this one's context")).toBeInTheDocument();
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('hides the Generate button when onGenerate is omitted', () => {
|
|
284
|
+
renderWithEventBus(<ResourceInfoPanel {...defaultProps} />);
|
|
285
|
+
expect(screen.queryByRole('button', { name: /Generate/i })).not.toBeInTheDocument();
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
it('calls onGenerate when clicked', () => {
|
|
289
|
+
const onGenerate = vi.fn();
|
|
290
|
+
renderWithEventBus(
|
|
291
|
+
<ResourceInfoPanel {...defaultProps} onGenerate={onGenerate} />
|
|
292
|
+
);
|
|
293
|
+
fireEvent.click(screen.getByRole('button', { name: /Generate/i }));
|
|
294
|
+
expect(onGenerate).toHaveBeenCalledTimes(1);
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
|
|
272
298
|
describe('Provenance Section', () => {
|
|
273
299
|
it('should not render provenance section when no provenance data', () => {
|
|
274
300
|
renderWithEventBus(<ResourceInfoPanel {...defaultProps} />);
|
|
@@ -219,3 +219,17 @@
|
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
/* Popup Components */
|
|
222
|
+
|
|
223
|
+
/* ── Compact display form ────────────────────────────────────────────────────
|
|
224
|
+
* Display-only variant for inline embeds: icon-only, tight, chromeless. The
|
|
225
|
+
* bar's functionality is identical — only its form changes. */
|
|
226
|
+
.semiont-annotate-toolbar--compact {
|
|
227
|
+
gap: 0.375rem;
|
|
228
|
+
padding: 0.25rem 0;
|
|
229
|
+
background: transparent; /* the host container owns the background */
|
|
230
|
+
border-bottom: none;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.semiont-annotate-toolbar--compact .semiont-dropdown-label {
|
|
234
|
+
display: none; /* icon-only collapsed triggers; expanded menus keep labels */
|
|
235
|
+
}
|
|
@@ -2,6 +2,7 @@ import { describe, it, expect, vi } from 'vitest';
|
|
|
2
2
|
import { firstValueFrom, of, throwError } from 'rxjs';
|
|
3
3
|
import type { ShellStateUnit } from '../../../../state/shell-state-unit';
|
|
4
4
|
import { createExchangeStateUnit } from '../exchange-state-unit';
|
|
5
|
+
import { assertStateUnitAxioms, disposeProbe } from '@semiont/core/testing';
|
|
5
6
|
|
|
6
7
|
function mockBrowse(): ShellStateUnit {
|
|
7
8
|
return { dispose: vi.fn() } as unknown as ShellStateUnit;
|
|
@@ -169,3 +170,16 @@ describe('createExchangeStateUnit', () => {
|
|
|
169
170
|
stateUnit.dispose();
|
|
170
171
|
});
|
|
171
172
|
});
|
|
173
|
+
|
|
174
|
+
describe('ExchangeStateUnit — StateUnit axioms', () => {
|
|
175
|
+
it('satisfies the StateUnit axioms (incl. A7-passed: never disposes the injected browse)', () => {
|
|
176
|
+
assertStateUnitAxioms({
|
|
177
|
+
setup: () => {
|
|
178
|
+
const browse = disposeProbe();
|
|
179
|
+
return { unit: createExchangeStateUnit(browse as unknown as ShellStateUnit, vi.fn(), vi.fn()), passedIn: [browse] };
|
|
180
|
+
},
|
|
181
|
+
surfaces: (u) => [u.selectedFile$, u.preview$, u.importPhase$, u.importMessage$, u.importResult$, u.isExporting$, u.isImporting$],
|
|
182
|
+
invocations: (u) => [() => u.cancelImport(), () => u.doImport()],
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BehaviorSubject, lastValueFrom, type Observable } from 'rxjs';
|
|
2
2
|
import { tap } from 'rxjs/operators';
|
|
3
3
|
import { createDisposer } from '@semiont/sdk';
|
|
4
|
-
import type { StateUnit } from '@semiont/
|
|
4
|
+
import type { StateUnit } from '@semiont/core';
|
|
5
5
|
import type { ShellStateUnit } from '../../../state/shell-state-unit';
|
|
6
6
|
import type { BackendDownload, ProgressEvent } from '@semiont/core';
|
|
7
7
|
|
|
@@ -33,7 +33,9 @@ export function createExchangeStateUnit(
|
|
|
33
33
|
importFn: (file: File) => Observable<ProgressEvent>,
|
|
34
34
|
): ExchangeStateUnit {
|
|
35
35
|
const disposer = createDisposer();
|
|
36
|
-
|
|
36
|
+
// `browse` (ShellStateUnit) is a *passed-in* dependency owned by the caller
|
|
37
|
+
// (`useShellStateUnit`), not this unit — do NOT add it to the disposer (it's the
|
|
38
|
+
// shared, app-scoped shell). See packages/sdk/docs/STATE-UNITS.md (composition rule).
|
|
37
39
|
|
|
38
40
|
const selectedFile$ = new BehaviorSubject<File | null>(null);
|
|
39
41
|
const preview$ = new BehaviorSubject<ImportPreview | null>(null);
|
|
@@ -4,6 +4,7 @@ import { filter } from 'rxjs/operators';
|
|
|
4
4
|
import type { SemiontClient } from '@semiont/sdk';
|
|
5
5
|
import type { ShellStateUnit } from '../../../../state/shell-state-unit';
|
|
6
6
|
import { createAdminSecurityStateUnit } from '../admin-security-state-unit';
|
|
7
|
+
import { assertStateUnitAxioms, disposeProbe } from '@semiont/core/testing';
|
|
7
8
|
|
|
8
9
|
function mockBrowse(): ShellStateUnit {
|
|
9
10
|
return { dispose: vi.fn() } as unknown as ShellStateUnit;
|
|
@@ -66,3 +67,16 @@ describe('createAdminSecurityStateUnit', () => {
|
|
|
66
67
|
stateUnit.dispose();
|
|
67
68
|
});
|
|
68
69
|
});
|
|
70
|
+
|
|
71
|
+
describe('AdminSecurityStateUnit — StateUnit axioms', () => {
|
|
72
|
+
it('satisfies the StateUnit axioms (incl. A7-passed: never disposes the injected browse)', () => {
|
|
73
|
+
assertStateUnitAxioms({
|
|
74
|
+
setup: () => {
|
|
75
|
+
const browse = disposeProbe();
|
|
76
|
+
const client = mockClient(vi.fn().mockResolvedValue({ providers: [], allowedDomains: [] }));
|
|
77
|
+
return { unit: createAdminSecurityStateUnit(client, browse as unknown as ShellStateUnit), passedIn: [browse] };
|
|
78
|
+
},
|
|
79
|
+
surfaces: (u) => [u.providers$, u.allowedDomains$, u.isLoading$],
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BehaviorSubject, type Observable } from 'rxjs';
|
|
2
2
|
import { createDisposer } from '@semiont/sdk';
|
|
3
|
-
import type { StateUnit } from '@semiont/
|
|
3
|
+
import type { StateUnit } from '@semiont/core';
|
|
4
4
|
import type { ShellStateUnit } from '../../../state/shell-state-unit';
|
|
5
5
|
import type { SemiontClient } from '@semiont/sdk';
|
|
6
6
|
|
|
@@ -16,7 +16,9 @@ export function createAdminSecurityStateUnit(
|
|
|
16
16
|
browse: ShellStateUnit,
|
|
17
17
|
): AdminSecurityStateUnit {
|
|
18
18
|
const disposer = createDisposer();
|
|
19
|
-
|
|
19
|
+
// `browse` (ShellStateUnit) is a *passed-in* dependency owned by the caller
|
|
20
|
+
// (`useShellStateUnit`), not this unit — do NOT add it to the disposer (it's the
|
|
21
|
+
// shared, app-scoped shell). See packages/sdk/docs/STATE-UNITS.md (composition rule).
|
|
20
22
|
|
|
21
23
|
const providers$ = new BehaviorSubject<unknown[]>([]);
|
|
22
24
|
const allowedDomains$ = new BehaviorSubject<string[]>([]);
|
|
@@ -4,6 +4,7 @@ import { filter } from 'rxjs/operators';
|
|
|
4
4
|
import type { SemiontClient } from '@semiont/sdk';
|
|
5
5
|
import type { ShellStateUnit } from '../../../../state/shell-state-unit';
|
|
6
6
|
import { createAdminUsersStateUnit } from '../admin-users-state-unit';
|
|
7
|
+
import { assertStateUnitAxioms, disposeProbe } from '@semiont/core/testing';
|
|
7
8
|
|
|
8
9
|
function mockBrowse(): ShellStateUnit {
|
|
9
10
|
return { dispose: vi.fn() } as unknown as ShellStateUnit;
|
|
@@ -77,10 +78,16 @@ describe('createAdminUsersStateUnit', () => {
|
|
|
77
78
|
stateUnit.dispose();
|
|
78
79
|
});
|
|
79
80
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('AdminUsersStateUnit — StateUnit axioms', () => {
|
|
84
|
+
it('satisfies the StateUnit axioms (incl. A7-passed: never disposes the injected browse)', () => {
|
|
85
|
+
assertStateUnitAxioms({
|
|
86
|
+
setup: () => {
|
|
87
|
+
const browse = disposeProbe();
|
|
88
|
+
return { unit: createAdminUsersStateUnit(mockClient(), browse as unknown as ShellStateUnit), passedIn: [browse] };
|
|
89
|
+
},
|
|
90
|
+
surfaces: (u) => [u.users$, u.stats$, u.usersLoading$, u.statsLoading$],
|
|
91
|
+
});
|
|
85
92
|
});
|
|
86
93
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BehaviorSubject, type Observable } from 'rxjs';
|
|
2
2
|
import { userDID } from '@semiont/core';
|
|
3
3
|
import { createDisposer } from '@semiont/sdk';
|
|
4
|
-
import type { StateUnit } from '@semiont/
|
|
4
|
+
import type { StateUnit } from '@semiont/core';
|
|
5
5
|
import type { ShellStateUnit } from '../../../state/shell-state-unit';
|
|
6
6
|
import type { SemiontClient } from '@semiont/sdk';
|
|
7
7
|
|
|
@@ -19,7 +19,9 @@ export function createAdminUsersStateUnit(
|
|
|
19
19
|
browse: ShellStateUnit,
|
|
20
20
|
): AdminUsersStateUnit {
|
|
21
21
|
const disposer = createDisposer();
|
|
22
|
-
|
|
22
|
+
// `browse` (ShellStateUnit) is a *passed-in* dependency owned by the caller
|
|
23
|
+
// (`useShellStateUnit`), not this unit — do NOT add it to the disposer (it's the
|
|
24
|
+
// shared, app-scoped shell). See packages/sdk/docs/STATE-UNITS.md (composition rule).
|
|
23
25
|
|
|
24
26
|
const users$ = new BehaviorSubject<unknown[]>([]);
|
|
25
27
|
const stats$ = new BehaviorSubject<unknown | null>(null);
|
|
@@ -3,6 +3,7 @@ import { firstValueFrom } from 'rxjs';
|
|
|
3
3
|
import { filter } from 'rxjs/operators';
|
|
4
4
|
import type { SemiontClient } from '@semiont/sdk';
|
|
5
5
|
import { createWelcomeStateUnit } from '../welcome-state-unit';
|
|
6
|
+
import { assertStateUnitAxioms } from '@semiont/core/testing';
|
|
6
7
|
|
|
7
8
|
function mockClient(overrides: {
|
|
8
9
|
getMe?: ReturnType<typeof vi.fn>;
|
|
@@ -84,3 +85,13 @@ describe('createWelcomeStateUnit', () => {
|
|
|
84
85
|
stateUnit.dispose();
|
|
85
86
|
});
|
|
86
87
|
});
|
|
88
|
+
|
|
89
|
+
describe('WelcomeStateUnit — StateUnit axioms', () => {
|
|
90
|
+
it('satisfies the StateUnit axioms', () => {
|
|
91
|
+
assertStateUnitAxioms({
|
|
92
|
+
setup: () => createWelcomeStateUnit(mockClient()),
|
|
93
|
+
surfaces: (u) => [u.userData$, u.isProcessing$],
|
|
94
|
+
invocations: (u) => [() => u.acceptTerms()],
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BehaviorSubject, type Observable } from 'rxjs';
|
|
2
2
|
import { createDisposer } from '@semiont/sdk';
|
|
3
|
-
import type { StateUnit } from '@semiont/
|
|
3
|
+
import type { StateUnit } from '@semiont/core';
|
|
4
4
|
import type { SemiontClient } from '@semiont/sdk';
|
|
5
5
|
|
|
6
6
|
export interface WelcomeStateUnit extends StateUnit {
|
|
@@ -4,6 +4,7 @@ import { filter } from 'rxjs/operators';
|
|
|
4
4
|
import type { SemiontClient } from '@semiont/sdk';
|
|
5
5
|
import type { ShellStateUnit } from '../../../../state/shell-state-unit';
|
|
6
6
|
import { createEntityTagsStateUnit } from '../entity-tags-state-unit';
|
|
7
|
+
import { assertStateUnitAxioms, disposeProbe } from '@semiont/core/testing';
|
|
7
8
|
|
|
8
9
|
function mockBrowse(): ShellStateUnit {
|
|
9
10
|
return { dispose: vi.fn() } as unknown as ShellStateUnit;
|
|
@@ -100,3 +101,16 @@ describe('createEntityTagsStateUnit', () => {
|
|
|
100
101
|
stateUnit.dispose();
|
|
101
102
|
});
|
|
102
103
|
});
|
|
104
|
+
|
|
105
|
+
describe('EntityTagsStateUnit — StateUnit axioms', () => {
|
|
106
|
+
it('satisfies the StateUnit axioms (incl. A7-passed: never disposes the injected browse)', () => {
|
|
107
|
+
assertStateUnitAxioms({
|
|
108
|
+
setup: () => {
|
|
109
|
+
const browse = disposeProbe();
|
|
110
|
+
return { unit: createEntityTagsStateUnit(mockClient(), browse as unknown as ShellStateUnit), passedIn: [browse] };
|
|
111
|
+
},
|
|
112
|
+
surfaces: (u) => [u.newTag$, u.error$, u.isAdding$],
|
|
113
|
+
invocations: (u) => [() => u.setNewTag(''), () => u.addTag()],
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BehaviorSubject, type Observable, map } from 'rxjs';
|
|
2
2
|
import { createDisposer } from '@semiont/sdk';
|
|
3
|
-
import type { StateUnit } from '@semiont/
|
|
3
|
+
import type { StateUnit } from '@semiont/core';
|
|
4
4
|
import type { ShellStateUnit } from '../../../state/shell-state-unit';
|
|
5
5
|
import type { SemiontClient } from '@semiont/sdk';
|
|
6
6
|
|
|
@@ -20,7 +20,9 @@ export function createEntityTagsStateUnit(
|
|
|
20
20
|
browse: ShellStateUnit,
|
|
21
21
|
): EntityTagsStateUnit {
|
|
22
22
|
const disposer = createDisposer();
|
|
23
|
-
|
|
23
|
+
// `browse` (ShellStateUnit) is a *passed-in* dependency owned by the caller
|
|
24
|
+
// (`useShellStateUnit`), not this unit — do NOT add it to the disposer (it's the
|
|
25
|
+
// shared, app-scoped shell). See packages/sdk/docs/STATE-UNITS.md (composition rule).
|
|
24
26
|
|
|
25
27
|
const newTag$ = new BehaviorSubject<string>('');
|
|
26
28
|
const error$ = new BehaviorSubject<string>('');
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import React, { useState, useEffect } from 'react';
|
|
10
|
-
import type
|
|
10
|
+
import { deriveViews, type GatheredContext } from '@semiont/core';
|
|
11
11
|
import { capabilitiesOf, AUTHORABLE_MEDIA_TYPES, MEDIA_TYPES, mediaTypeForExtension, isSupportedMediaType, LOCALES } from '@semiont/core';
|
|
12
12
|
import type { UploadProgress } from '@semiont/sdk';
|
|
13
13
|
import { type CloneData, type ReferenceData } from '../state/compose-page-state-unit';
|
|
@@ -283,6 +283,12 @@ export function ResourceComposePage({
|
|
|
283
283
|
const isClone = mode === 'clone';
|
|
284
284
|
const isReferenceCompletion = mode === 'reference';
|
|
285
285
|
|
|
286
|
+
// Gathered-context panel — annotation-focus only for now.
|
|
287
|
+
const composeFocus = gatheredContext?.focus.kind === 'annotation' ? gatheredContext.focus : null;
|
|
288
|
+
const composeConnections = gatheredContext && composeFocus
|
|
289
|
+
? deriveViews(gatheredContext.graph, String(composeFocus.sourceResource.id)).connections
|
|
290
|
+
: [];
|
|
291
|
+
|
|
286
292
|
return (
|
|
287
293
|
<div className={`semiont-page${activePanel && COMMON_PANELS.includes(activePanel as ToolbarPanelType) ? ' semiont-page--panel-open' : ''}`}>
|
|
288
294
|
{/* Main Content Area */}
|
|
@@ -316,7 +322,7 @@ export function ResourceComposePage({
|
|
|
316
322
|
border: '1px solid var(--semiont-border-primary)',
|
|
317
323
|
}}>
|
|
318
324
|
<h3 className="semiont-form__label" style={{ marginBottom: '0.75rem' }}>Gathered Context</h3>
|
|
319
|
-
{
|
|
325
|
+
{composeFocus?.selected && (
|
|
320
326
|
<div style={{
|
|
321
327
|
padding: '0.75rem',
|
|
322
328
|
backgroundColor: 'var(--semiont-bg-primary)',
|
|
@@ -327,27 +333,27 @@ export function ResourceComposePage({
|
|
|
327
333
|
marginBottom: '0.5rem',
|
|
328
334
|
}}>
|
|
329
335
|
<div style={{ fontSize: 'var(--semiont-text-sm)', fontFamily: 'monospace', whiteSpace: 'pre-wrap', color: 'var(--semiont-text-secondary)' }}>
|
|
330
|
-
{
|
|
336
|
+
{composeFocus.selected.before && <span>{composeFocus.selected.before}</span>}
|
|
331
337
|
<span style={{
|
|
332
338
|
backgroundColor: 'var(--semiont-color-primary-100)',
|
|
333
339
|
padding: '0 0.25rem',
|
|
334
340
|
fontWeight: 600,
|
|
335
341
|
color: 'var(--semiont-color-primary-900)',
|
|
336
342
|
}}>
|
|
337
|
-
{
|
|
343
|
+
{composeFocus.selected.text}
|
|
338
344
|
</span>
|
|
339
|
-
{
|
|
345
|
+
{composeFocus.selected.after && <span>{composeFocus.selected.after}</span>}
|
|
340
346
|
</div>
|
|
341
347
|
</div>
|
|
342
348
|
)}
|
|
343
|
-
{
|
|
349
|
+
{composeConnections.length > 0 && (
|
|
344
350
|
<div style={{
|
|
345
351
|
padding: '0.5rem 0',
|
|
346
352
|
fontSize: 'var(--semiont-text-sm)',
|
|
347
353
|
color: 'var(--semiont-text-secondary)',
|
|
348
354
|
}}>
|
|
349
355
|
<span style={{ fontSize: 'var(--semiont-text-xs)', fontWeight: 500, marginRight: '0.5rem' }}>Connections:</span>
|
|
350
|
-
{
|
|
356
|
+
{composeConnections.map(conn => (
|
|
351
357
|
<span key={conn.resourceId} className="semiont-chip" style={{ fontSize: 'var(--semiont-text-xs)', padding: '0.125rem 0.5rem', marginRight: '0.25rem' }}>
|
|
352
358
|
{conn.resourceName}
|
|
353
359
|
</span>
|
|
@@ -4,6 +4,7 @@ import { filter } from 'rxjs/operators';
|
|
|
4
4
|
import type { SemiontClient } from '@semiont/sdk';
|
|
5
5
|
import type { ShellStateUnit } from '../../../../state/shell-state-unit';
|
|
6
6
|
import { createComposePageStateUnit } from '../compose-page-state-unit';
|
|
7
|
+
import { assertStateUnitAxioms, disposeProbe } from '@semiont/core/testing';
|
|
7
8
|
|
|
8
9
|
/** Build an `UploadObservable`-shaped mock that emits started → finished. */
|
|
9
10
|
function mockUpload(resourceId: string) {
|
|
@@ -185,3 +186,15 @@ describe('createComposePageStateUnit', () => {
|
|
|
185
186
|
stateUnit.dispose();
|
|
186
187
|
});
|
|
187
188
|
});
|
|
189
|
+
|
|
190
|
+
describe('ComposePageStateUnit — StateUnit axioms', () => {
|
|
191
|
+
it('satisfies the StateUnit axioms (incl. A7-passed: never disposes the injected browse)', () => {
|
|
192
|
+
assertStateUnitAxioms({
|
|
193
|
+
setup: () => {
|
|
194
|
+
const browse = disposeProbe();
|
|
195
|
+
return { unit: createComposePageStateUnit(mockClient(), browse as unknown as ShellStateUnit, {}), passedIn: [browse] };
|
|
196
|
+
},
|
|
197
|
+
surfaces: (u) => [u.mode$, u.loading$, u.cloneData$, u.referenceData$, u.gatheredContext$, u.uploadProgress$],
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
});
|
|
@@ -2,7 +2,7 @@ import { BehaviorSubject, type Observable, map } from 'rxjs';
|
|
|
2
2
|
import type { GatheredContext, AnnotationId, AccessToken, ResourceDescriptor, ResourceId } from '@semiont/core';
|
|
3
3
|
import { resourceId as makeResourceId, annotationId as makeAnnotationId } from '@semiont/core';
|
|
4
4
|
import { createDisposer } from '@semiont/sdk';
|
|
5
|
-
import type { StateUnit } from '@semiont/
|
|
5
|
+
import type { StateUnit } from '@semiont/core';
|
|
6
6
|
import type { ShellStateUnit } from '../../../state/shell-state-unit';
|
|
7
7
|
import type { SemiontClient } from '@semiont/sdk';
|
|
8
8
|
import { decodeWithCharset, extensionForMediaType } from '@semiont/core';
|
|
@@ -72,7 +72,9 @@ export function createComposePageStateUnit(
|
|
|
72
72
|
auth?: AccessToken,
|
|
73
73
|
): ComposePageStateUnit {
|
|
74
74
|
const disposer = createDisposer();
|
|
75
|
-
|
|
75
|
+
// `browse` (ShellStateUnit) is a *passed-in* dependency owned by the caller
|
|
76
|
+
// (`useShellStateUnit`), not this unit — do NOT add it to the disposer (it's the
|
|
77
|
+
// shared, app-scoped shell). See packages/sdk/docs/STATE-UNITS.md (composition rule).
|
|
76
78
|
|
|
77
79
|
const isReferenceMode = Boolean(params.annotationUri && params.sourceDocumentId && params.name);
|
|
78
80
|
const isCloneMode = params.mode === 'clone' && Boolean(params.token);
|
|
@@ -199,6 +201,7 @@ export function createComposePageStateUnit(
|
|
|
199
201
|
cloneData$.complete();
|
|
200
202
|
referenceData$.complete();
|
|
201
203
|
gatheredContext$.complete();
|
|
204
|
+
uploadProgress$.complete();
|
|
202
205
|
disposer.dispose();
|
|
203
206
|
},
|
|
204
207
|
};
|
|
@@ -4,6 +4,7 @@ import { filter, skip, take, toArray } from 'rxjs/operators';
|
|
|
4
4
|
import type { SemiontClient } from '@semiont/sdk';
|
|
5
5
|
import type { ShellStateUnit } from '../../../../state/shell-state-unit';
|
|
6
6
|
import { createDiscoverStateUnit } from '../discover-state-unit';
|
|
7
|
+
import { assertStateUnitAxioms, disposeProbe } from '@semiont/core/testing';
|
|
7
8
|
|
|
8
9
|
function mockBrowse(): ShellStateUnit {
|
|
9
10
|
return { dispose: vi.fn() } as unknown as ShellStateUnit;
|
|
@@ -100,15 +101,6 @@ describe('createDiscoverStateUnit', () => {
|
|
|
100
101
|
stateUnit.dispose();
|
|
101
102
|
});
|
|
102
103
|
|
|
103
|
-
it('disposes browse and search on dispose', () => {
|
|
104
|
-
const browse = mockBrowse();
|
|
105
|
-
const { client } = mockClient();
|
|
106
|
-
const stateUnit = createDiscoverStateUnit(client, browse);
|
|
107
|
-
stateUnit.dispose();
|
|
108
|
-
|
|
109
|
-
expect(browse.dispose).toHaveBeenCalled();
|
|
110
|
-
});
|
|
111
|
-
|
|
112
104
|
it('initial selectedEntityType$ is empty and recent fetch carries no entityType', async () => {
|
|
113
105
|
const { client, resourceCalls } = mockClient();
|
|
114
106
|
const stateUnit = createDiscoverStateUnit(client, mockBrowse());
|
|
@@ -267,3 +259,17 @@ describe('createDiscoverStateUnit', () => {
|
|
|
267
259
|
stateUnit.dispose();
|
|
268
260
|
});
|
|
269
261
|
});
|
|
262
|
+
|
|
263
|
+
describe('DiscoverStateUnit — StateUnit axioms', () => {
|
|
264
|
+
it('satisfies the StateUnit axioms (incl. A7-passed: never disposes the injected browse)', () => {
|
|
265
|
+
assertStateUnitAxioms({
|
|
266
|
+
setup: () => {
|
|
267
|
+
const browse = disposeProbe();
|
|
268
|
+
const { client } = mockClient();
|
|
269
|
+
return { unit: createDiscoverStateUnit(client, browse as unknown as ShellStateUnit), passedIn: [browse] };
|
|
270
|
+
},
|
|
271
|
+
surfaces: (u) => [u.selectedEntityType$],
|
|
272
|
+
invocations: (u) => [() => u.setSelectedEntityType('')],
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
});
|