@semiont/react-ui 0.2.35-build.99 → 0.2.35
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 -0
- package/dist/{EventBusContext-DMI4uwYk.d.mts → EventBusContext-CLnb2LmB.d.mts} +5 -5
- package/dist/{PdfAnnotationCanvas.client-HNYRKFDS.mjs → PdfAnnotationCanvas.client-COQREPXU.mjs} +7 -7
- package/dist/PdfAnnotationCanvas.client-COQREPXU.mjs.map +1 -0
- package/dist/ar-7SUXNE34.mjs +376 -0
- package/dist/ar-7SUXNE34.mjs.map +1 -0
- package/dist/bn-XOET3DOI.mjs +376 -0
- package/dist/bn-XOET3DOI.mjs.map +1 -0
- package/dist/{chunk-YI5IX5ZA.mjs → chunk-2HGWOLVN.mjs} +1 -1
- package/dist/{chunk-YI5IX5ZA.mjs.map → chunk-2HGWOLVN.mjs.map} +1 -1
- package/dist/{chunk-3FIQXKQF.mjs → chunk-Q2KV6Y2J.mjs} +28 -28
- package/dist/{chunk-MWQ5CNKW.mjs → chunk-ZPV43WN2.mjs} +11 -11
- package/dist/chunk-ZPV43WN2.mjs.map +1 -0
- package/dist/cs-X63DXX7L.mjs +376 -0
- package/dist/cs-X63DXX7L.mjs.map +1 -0
- package/dist/da-OWTCV57A.mjs +376 -0
- package/dist/da-OWTCV57A.mjs.map +1 -0
- package/dist/de-77BMFDVF.mjs +376 -0
- package/dist/de-77BMFDVF.mjs.map +1 -0
- package/dist/el-FIBNLH2V.mjs +376 -0
- package/dist/el-FIBNLH2V.mjs.map +1 -0
- package/dist/fa-3N4CIWE6.mjs +376 -0
- package/dist/fa-3N4CIWE6.mjs.map +1 -0
- package/dist/fi-JOM3M7Z4.mjs +376 -0
- package/dist/fi-JOM3M7Z4.mjs.map +1 -0
- package/dist/fr-56QSXS7E.mjs +376 -0
- package/dist/fr-56QSXS7E.mjs.map +1 -0
- package/dist/he-SNAXPJEK.mjs +376 -0
- package/dist/he-SNAXPJEK.mjs.map +1 -0
- package/dist/hi-CRBRD5TB.mjs +376 -0
- package/dist/hi-CRBRD5TB.mjs.map +1 -0
- package/dist/id-BRCVLICF.mjs +376 -0
- package/dist/id-BRCVLICF.mjs.map +1 -0
- package/dist/index.d.mts +169 -165
- package/dist/index.mjs +317 -313
- package/dist/index.mjs.map +1 -1
- package/dist/it-M2Z27BNB.mjs +376 -0
- package/dist/it-M2Z27BNB.mjs.map +1 -0
- package/dist/ja-TZUKW7HD.mjs +376 -0
- package/dist/ja-TZUKW7HD.mjs.map +1 -0
- package/dist/ko-NKBGGOL6.mjs +376 -0
- package/dist/ko-NKBGGOL6.mjs.map +1 -0
- package/dist/ms-XFXPN6RX.mjs +376 -0
- package/dist/ms-XFXPN6RX.mjs.map +1 -0
- package/dist/nl-MVYXAS5C.mjs +379 -0
- package/dist/nl-MVYXAS5C.mjs.map +1 -0
- package/dist/no-XOLO4JPV.mjs +376 -0
- package/dist/no-XOLO4JPV.mjs.map +1 -0
- package/dist/pl-TRWLMMC4.mjs +376 -0
- package/dist/pl-TRWLMMC4.mjs.map +1 -0
- package/dist/pt-M3TE24UI.mjs +376 -0
- package/dist/pt-M3TE24UI.mjs.map +1 -0
- package/dist/ro-QBFG2T64.mjs +376 -0
- package/dist/ro-QBFG2T64.mjs.map +1 -0
- package/dist/sv-IUECBXWX.mjs +376 -0
- package/dist/sv-IUECBXWX.mjs.map +1 -0
- package/dist/test-utils.d.mts +2 -2
- package/dist/test-utils.mjs +2 -2
- package/dist/th-US7KIN5Q.mjs +376 -0
- package/dist/th-US7KIN5Q.mjs.map +1 -0
- package/dist/tr-DWJ2FFUK.mjs +376 -0
- package/dist/tr-DWJ2FFUK.mjs.map +1 -0
- package/dist/uk-M4ZE4DPZ.mjs +376 -0
- package/dist/uk-M4ZE4DPZ.mjs.map +1 -0
- package/dist/vi-FERZNPSH.mjs +376 -0
- package/dist/vi-FERZNPSH.mjs.map +1 -0
- package/dist/zh-3J2I3WYK.mjs +376 -0
- package/dist/zh-3J2I3WYK.mjs.map +1 -0
- package/package.json +1 -1
- package/src/components/AnnotateReferencesProgressWidget.tsx +5 -5
- package/src/components/CodeMirrorRenderer.tsx +5 -5
- package/src/components/Toolbar.tsx +2 -2
- package/src/components/annotation/AnnotateToolbar.tsx +9 -9
- package/src/components/annotation/__tests__/AnnotateToolbar.test.tsx +17 -17
- package/src/components/image-annotation/AnnotationOverlay.tsx +10 -10
- package/src/components/image-annotation/SvgDrawingCanvas.tsx +4 -4
- package/src/components/navigation/CollapsibleResourceNavigation.tsx +7 -7
- package/src/components/navigation/ObservableLink.tsx +3 -3
- package/src/components/navigation/SimpleNavigation.tsx +2 -2
- package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +8 -8
- package/src/components/resource/AnnotateView.tsx +12 -12
- package/src/components/resource/BrowseView.tsx +9 -9
- package/src/components/resource/ResourceViewer.tsx +23 -23
- package/src/components/resource/__tests__/BrowseView.test.tsx +27 -27
- package/src/components/resource/__tests__/ResourceViewer.mode-switch.test.tsx +1 -1
- package/src/components/resource/panels/AssessmentEntry.tsx +2 -2
- package/src/components/resource/panels/AssessmentPanel.tsx +7 -7
- package/src/components/resource/panels/AssistSection.tsx +5 -5
- package/src/components/resource/panels/CommentEntry.tsx +2 -2
- package/src/components/resource/panels/CommentsPanel.tsx +7 -7
- package/src/components/resource/panels/HighlightEntry.tsx +2 -2
- package/src/components/resource/panels/HighlightPanel.tsx +5 -5
- package/src/components/resource/panels/ReferenceEntry.tsx +8 -8
- package/src/components/resource/panels/ReferencesPanel.tsx +10 -10
- package/src/components/resource/panels/ResourceInfoPanel.tsx +6 -6
- package/src/components/resource/panels/TagEntry.tsx +2 -2
- package/src/components/resource/panels/TaggingPanel.tsx +8 -8
- package/src/components/resource/panels/UnifiedAnnotationsPanel.tsx +2 -2
- package/src/components/resource/panels/__tests__/AssessmentPanel.test.tsx +4 -4
- package/src/components/resource/panels/__tests__/AssistSection.test.tsx +4 -4
- package/src/components/resource/panels/__tests__/CommentEntry.test.tsx +8 -8
- package/src/components/resource/panels/__tests__/CommentsPanel.test.tsx +3 -3
- package/src/components/resource/panels/__tests__/HighlightPanel.annotationProgress.test.tsx +1 -1
- package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +3 -3
- package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +9 -9
- package/src/components/resource/panels/__tests__/TaggingPanel.test.tsx +5 -5
- package/src/features/admin-devops/components/AdminDevOpsPage.tsx +2 -1
- package/src/features/admin-security/components/AdminSecurityPage.tsx +2 -1
- package/src/features/admin-users/components/AdminUsersPage.tsx +2 -1
- package/src/features/moderate-entity-tags/components/EntityTagsPage.tsx +2 -1
- package/src/features/moderate-recent/components/RecentDocumentsPage.tsx +2 -1
- package/src/features/moderate-tag-schemas/components/TagSchemasPage.tsx +2 -1
- package/src/features/resource-compose/components/ResourceComposePage.tsx +2 -1
- package/src/features/resource-discovery/components/ResourceDiscoveryPage.tsx +2 -1
- package/src/features/resource-viewer/__tests__/AnnotationCreationPending.test.tsx +26 -26
- package/src/features/resource-viewer/__tests__/AnnotationDeletionIntegration.test.tsx +21 -21
- package/src/features/resource-viewer/__tests__/AnnotationProgressDismissal.test.tsx +23 -23
- package/src/features/resource-viewer/__tests__/{ResolutionFlowIntegration.test.tsx → BindFlowIntegration.test.tsx} +49 -49
- package/src/features/resource-viewer/__tests__/DetectionFlowBug.test.tsx +18 -18
- package/src/features/resource-viewer/__tests__/DetectionFlowIntegration.test.tsx +19 -19
- package/src/features/resource-viewer/__tests__/ResourceMutations.test.tsx +19 -19
- package/src/features/resource-viewer/__tests__/ToastNotifications.test.tsx +13 -13
- package/src/features/resource-viewer/__tests__/{GenerationFlowIntegration.test.tsx → YieldFlowIntegration.test.tsx} +34 -34
- package/src/features/resource-viewer/__tests__/annotation-progress-flow.test.tsx +11 -11
- package/src/features/resource-viewer/components/ResourceViewerPage.tsx +55 -55
- package/translations/ar.json +298 -298
- package/translations/bn.json +298 -298
- package/translations/cs.json +295 -295
- package/translations/da.json +282 -282
- package/translations/de.json +281 -281
- package/translations/el.json +298 -298
- package/translations/fa.json +298 -298
- package/translations/fi.json +298 -298
- package/translations/fr.json +279 -279
- package/translations/he.json +298 -298
- package/translations/hi.json +298 -298
- package/translations/id.json +295 -295
- package/translations/it.json +299 -299
- package/translations/ja.json +298 -298
- package/translations/ko.json +298 -298
- package/translations/ms.json +296 -296
- package/translations/nl.json +299 -296
- package/translations/no.json +292 -292
- package/translations/pl.json +297 -297
- package/translations/pt.json +294 -294
- package/translations/ro.json +298 -298
- package/translations/sv.json +293 -293
- package/translations/th.json +298 -298
- package/translations/tr.json +298 -298
- package/translations/uk.json +298 -298
- package/translations/vi.json +298 -298
- package/translations/zh.json +298 -298
- package/dist/PdfAnnotationCanvas.client-HNYRKFDS.mjs.map +0 -1
- package/dist/ar-MDB7HC5S.mjs +0 -376
- package/dist/ar-MDB7HC5S.mjs.map +0 -1
- package/dist/bn-3SAV2ZEM.mjs +0 -376
- package/dist/bn-3SAV2ZEM.mjs.map +0 -1
- package/dist/chunk-MWQ5CNKW.mjs.map +0 -1
- package/dist/cs-AWCETEUV.mjs +0 -376
- package/dist/cs-AWCETEUV.mjs.map +0 -1
- package/dist/da-UZZHXYLC.mjs +0 -376
- package/dist/da-UZZHXYLC.mjs.map +0 -1
- package/dist/de-LQFWN6S5.mjs +0 -376
- package/dist/de-LQFWN6S5.mjs.map +0 -1
- package/dist/el-IWOETBJ7.mjs +0 -376
- package/dist/el-IWOETBJ7.mjs.map +0 -1
- package/dist/fa-BVEJZT5S.mjs +0 -376
- package/dist/fa-BVEJZT5S.mjs.map +0 -1
- package/dist/fi-JBNCGGA6.mjs +0 -376
- package/dist/fi-JBNCGGA6.mjs.map +0 -1
- package/dist/fr-OLH7PNGI.mjs +0 -376
- package/dist/fr-OLH7PNGI.mjs.map +0 -1
- package/dist/he-KOJQ4HMA.mjs +0 -376
- package/dist/he-KOJQ4HMA.mjs.map +0 -1
- package/dist/hi-BKJFZXAY.mjs +0 -376
- package/dist/hi-BKJFZXAY.mjs.map +0 -1
- package/dist/id-DPLHJVNP.mjs +0 -376
- package/dist/id-DPLHJVNP.mjs.map +0 -1
- package/dist/it-JXHAM7NL.mjs +0 -376
- package/dist/it-JXHAM7NL.mjs.map +0 -1
- package/dist/ja-DQRAO3PU.mjs +0 -376
- package/dist/ja-DQRAO3PU.mjs.map +0 -1
- package/dist/ko-6IFCOP6F.mjs +0 -376
- package/dist/ko-6IFCOP6F.mjs.map +0 -1
- package/dist/ms-KF5S2TLL.mjs +0 -376
- package/dist/ms-KF5S2TLL.mjs.map +0 -1
- package/dist/nl-2GUUZLQM.mjs +0 -376
- package/dist/nl-2GUUZLQM.mjs.map +0 -1
- package/dist/no-2IBCZGEF.mjs +0 -376
- package/dist/no-2IBCZGEF.mjs.map +0 -1
- package/dist/pl-ZEUBJ7YU.mjs +0 -376
- package/dist/pl-ZEUBJ7YU.mjs.map +0 -1
- package/dist/pt-WLAFIZWQ.mjs +0 -376
- package/dist/pt-WLAFIZWQ.mjs.map +0 -1
- package/dist/ro-K56IXFGU.mjs +0 -376
- package/dist/ro-K56IXFGU.mjs.map +0 -1
- package/dist/sv-VFJLMJRY.mjs +0 -376
- package/dist/sv-VFJLMJRY.mjs.map +0 -1
- package/dist/th-RICLQ2GW.mjs +0 -376
- package/dist/th-RICLQ2GW.mjs.map +0 -1
- package/dist/tr-SALXWE2M.mjs +0 -376
- package/dist/tr-SALXWE2M.mjs.map +0 -1
- package/dist/uk-3U3T3O2E.mjs +0 -376
- package/dist/uk-3U3T3O2E.mjs.map +0 -1
- package/dist/vi-LIVNZXOB.mjs +0 -376
- package/dist/vi-LIVNZXOB.mjs.map +0 -1
- package/dist/zh-KDUAZPX3.mjs +0 -376
- package/dist/zh-KDUAZPX3.mjs.map +0 -1
- /package/dist/{chunk-3FIQXKQF.mjs.map → chunk-Q2KV6Y2J.mjs.map} +0 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This test verifies the fix for the issue identified in commit 9690806abc910bad490e684d6ef71d874a90579c.
|
|
5
5
|
*
|
|
6
6
|
* SOLUTION IMPLEMENTED:
|
|
7
|
-
* - Pattern B: Both
|
|
7
|
+
* - Pattern B: Both useMarkFlow and useYieldFlow call useToast internally
|
|
8
8
|
* - Toast notifications are shown from within the hooks (self-contained)
|
|
9
9
|
*
|
|
10
10
|
* EXPECTED BEHAVIOR (after fix):
|
|
@@ -20,8 +20,8 @@ import { EventBusProvider, resetEventBusForTesting, useEventBus } from '../../..
|
|
|
20
20
|
import { ApiClientProvider } from '../../../contexts/ApiClientContext';
|
|
21
21
|
import { AuthTokenProvider } from '../../../contexts/AuthTokenContext';
|
|
22
22
|
import { resourceUri } from '@semiont/core';
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
23
|
+
import { useMarkFlow } from '../../../hooks/useMarkFlow';
|
|
24
|
+
import { useYieldFlow } from '../../../hooks/useYieldFlow';
|
|
25
25
|
|
|
26
26
|
// Mock the toast hook to track calls
|
|
27
27
|
const mockShowSuccess = vi.fn();
|
|
@@ -51,13 +51,13 @@ describe('Toast Notifications - Verifies Toast Integration', () => {
|
|
|
51
51
|
*/
|
|
52
52
|
function TestComponentWithDetection() {
|
|
53
53
|
eventBusInstance = useEventBus();
|
|
54
|
-
|
|
54
|
+
useMarkFlow(rUri);
|
|
55
55
|
return <div data-testid="test">Test</div>;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
function TestComponentWithGeneration() {
|
|
59
59
|
eventBusInstance = useEventBus();
|
|
60
|
-
|
|
60
|
+
useYieldFlow('en', 'test-resource', vi.fn());
|
|
61
61
|
return <div data-testid="test">Test</div>;
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -86,7 +86,7 @@ describe('Toast Notifications - Verifies Toast Integration', () => {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
describe('Detection Events Trigger Toasts', () => {
|
|
89
|
-
it('
|
|
89
|
+
it('mark:assist-finished shows success toast', async () => {
|
|
90
90
|
renderDetectionTest();
|
|
91
91
|
|
|
92
92
|
// Clear any potential mount-related calls
|
|
@@ -95,7 +95,7 @@ describe('Toast Notifications - Verifies Toast Integration', () => {
|
|
|
95
95
|
|
|
96
96
|
// Emit detection finished event (what SSE would emit)
|
|
97
97
|
act(() => {
|
|
98
|
-
eventBusInstance.get('
|
|
98
|
+
eventBusInstance.get('mark:assist-finished').next({
|
|
99
99
|
motivation: 'linking' as any
|
|
100
100
|
});
|
|
101
101
|
});
|
|
@@ -106,7 +106,7 @@ describe('Toast Notifications - Verifies Toast Integration', () => {
|
|
|
106
106
|
});
|
|
107
107
|
});
|
|
108
108
|
|
|
109
|
-
it('
|
|
109
|
+
it('mark:assist-failed shows error toast', async () => {
|
|
110
110
|
renderDetectionTest();
|
|
111
111
|
|
|
112
112
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
@@ -114,7 +114,7 @@ describe('Toast Notifications - Verifies Toast Integration', () => {
|
|
|
114
114
|
|
|
115
115
|
// Emit detection failed event
|
|
116
116
|
act(() => {
|
|
117
|
-
eventBusInstance.get('
|
|
117
|
+
eventBusInstance.get('mark:assist-failed').next({
|
|
118
118
|
type: 'job.failed' as const,
|
|
119
119
|
resourceId: 'test' as any,
|
|
120
120
|
userId: 'user' as any,
|
|
@@ -137,7 +137,7 @@ describe('Toast Notifications - Verifies Toast Integration', () => {
|
|
|
137
137
|
});
|
|
138
138
|
|
|
139
139
|
describe('Generation Events Trigger Toasts', () => {
|
|
140
|
-
it('
|
|
140
|
+
it('yield:finished shows success toast', async () => {
|
|
141
141
|
renderGenerationTest();
|
|
142
142
|
|
|
143
143
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
@@ -145,7 +145,7 @@ describe('Toast Notifications - Verifies Toast Integration', () => {
|
|
|
145
145
|
|
|
146
146
|
// Emit generation finished event
|
|
147
147
|
act(() => {
|
|
148
|
-
eventBusInstance.get('
|
|
148
|
+
eventBusInstance.get('yield:finished').next({
|
|
149
149
|
status: 'complete',
|
|
150
150
|
message: 'Document generated successfully',
|
|
151
151
|
percentage: 100,
|
|
@@ -159,7 +159,7 @@ describe('Toast Notifications - Verifies Toast Integration', () => {
|
|
|
159
159
|
});
|
|
160
160
|
});
|
|
161
161
|
|
|
162
|
-
it('
|
|
162
|
+
it('yield:failed shows error toast', async () => {
|
|
163
163
|
renderGenerationTest();
|
|
164
164
|
|
|
165
165
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
@@ -167,7 +167,7 @@ describe('Toast Notifications - Verifies Toast Integration', () => {
|
|
|
167
167
|
|
|
168
168
|
// Emit generation failed event
|
|
169
169
|
act(() => {
|
|
170
|
-
eventBusInstance.get('
|
|
170
|
+
eventBusInstance.get('yield:failed').next({
|
|
171
171
|
error: new Error('Failed to generate document'),
|
|
172
172
|
});
|
|
173
173
|
});
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Tests the COMPLETE generation flow with real component composition:
|
|
5
5
|
* - EventBusProvider (REAL)
|
|
6
6
|
* - ApiClientProvider (REAL, with MOCKED client)
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
7
|
+
* - useYieldFlow (REAL, with inlined progress state)
|
|
8
|
+
* - useBindFlow (REAL)
|
|
9
9
|
* - useEventSubscriptions (REAL)
|
|
10
10
|
*
|
|
11
11
|
* This test focuses on ARCHITECTURE and EVENT WIRING:
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
22
22
|
import { render, screen, waitFor } from '@testing-library/react';
|
|
23
23
|
import { act } from 'react';
|
|
24
|
-
import {
|
|
24
|
+
import { useYieldFlow } from '../../../hooks/useYieldFlow';
|
|
25
25
|
import { EventBusProvider, useEventBus, resetEventBusForTesting } from '../../../contexts/EventBusContext';
|
|
26
26
|
import { ApiClientProvider } from '../../../contexts/ApiClientContext';
|
|
27
27
|
import { AuthTokenProvider } from '../../../contexts/AuthTokenContext';
|
|
28
|
-
import {
|
|
28
|
+
import { useBindFlow } from '../../../hooks/useBindFlow';
|
|
29
29
|
import { SSEClient } from '@semiont/api-client';
|
|
30
30
|
import type { ResourceUri, AnnotationUri } from '@semiont/core';
|
|
31
31
|
import { resourceUri, annotationUri } from '@semiont/core';
|
|
@@ -64,7 +64,7 @@ describe('Generation Flow - Feature Integration', () => {
|
|
|
64
64
|
mockStream = createMockGenerationStream();
|
|
65
65
|
|
|
66
66
|
// Spy on SSEClient prototype method
|
|
67
|
-
generateResourceSpy = vi.spyOn(SSEClient.prototype, '
|
|
67
|
+
generateResourceSpy = vi.spyOn(SSEClient.prototype, 'yieldResourceFromAnnotation').mockReturnValue(mockStream as any);
|
|
68
68
|
|
|
69
69
|
// Mock callbacks
|
|
70
70
|
mockShowSuccess = vi.fn();
|
|
@@ -76,11 +76,11 @@ describe('Generation Flow - Feature Integration', () => {
|
|
|
76
76
|
vi.restoreAllMocks();
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
-
it('should open modal when
|
|
79
|
+
it('should open modal when yield:modal-open event is emitted', async () => {
|
|
80
80
|
const testResourceUri = resourceUri('http://localhost:4000/resources/test-resource');
|
|
81
81
|
const testAnnotationUri = annotationUri('http://localhost:4000/resources/test-resource/annotations/test-annotation');
|
|
82
82
|
|
|
83
|
-
const { emitModalOpen } =
|
|
83
|
+
const { emitModalOpen } = renderYieldFlow(
|
|
84
84
|
testResourceUri
|
|
85
85
|
);
|
|
86
86
|
|
|
@@ -97,11 +97,11 @@ describe('Generation Flow - Feature Integration', () => {
|
|
|
97
97
|
});
|
|
98
98
|
});
|
|
99
99
|
|
|
100
|
-
it('should call
|
|
100
|
+
it('should call yieldResourceFromAnnotation exactly ONCE when generation starts', async () => {
|
|
101
101
|
const testResourceUri = resourceUri('http://localhost:4000/resources/test-resource');
|
|
102
102
|
const testAnnotationUri = annotationUri('http://localhost:4000/resources/test-resource/annotations/test-annotation');
|
|
103
103
|
|
|
104
|
-
const { emitGenerationStart, getEventBus } =
|
|
104
|
+
const { emitGenerationStart, getEventBus } = renderYieldFlow(
|
|
105
105
|
testResourceUri
|
|
106
106
|
);
|
|
107
107
|
|
|
@@ -144,11 +144,11 @@ describe('Generation Flow - Feature Integration', () => {
|
|
|
144
144
|
);
|
|
145
145
|
});
|
|
146
146
|
|
|
147
|
-
it('should propagate SSE progress events to
|
|
147
|
+
it('should propagate SSE progress events to useYieldProgress state', async () => {
|
|
148
148
|
const testResourceUri = resourceUri('http://localhost:4000/resources/test-resource');
|
|
149
149
|
const testAnnotationUri = annotationUri('http://localhost:4000/resources/test-resource/annotations/test-annotation');
|
|
150
150
|
|
|
151
|
-
const { emitGenerationStart, getEventBus } =
|
|
151
|
+
const { emitGenerationStart, getEventBus } = renderYieldFlow(
|
|
152
152
|
testResourceUri
|
|
153
153
|
);
|
|
154
154
|
|
|
@@ -167,7 +167,7 @@ describe('Generation Flow - Feature Integration', () => {
|
|
|
167
167
|
|
|
168
168
|
// Simulate SSE progress callback being invoked
|
|
169
169
|
act(() => {
|
|
170
|
-
getEventBus().get('
|
|
170
|
+
getEventBus().get('yield:progress').next({
|
|
171
171
|
status: 'generating',
|
|
172
172
|
message: 'Generating content...',
|
|
173
173
|
percentage: 25,
|
|
@@ -185,7 +185,7 @@ describe('Generation Flow - Feature Integration', () => {
|
|
|
185
185
|
const testResourceUri = resourceUri('http://localhost:4000/resources/test-resource');
|
|
186
186
|
const testAnnotationUri = annotationUri('http://localhost:4000/resources/test-resource/annotations/test-annotation');
|
|
187
187
|
|
|
188
|
-
const { emitGenerationStart, getEventBus } =
|
|
188
|
+
const { emitGenerationStart, getEventBus } = renderYieldFlow(
|
|
189
189
|
testResourceUri
|
|
190
190
|
);
|
|
191
191
|
|
|
@@ -203,7 +203,7 @@ describe('Generation Flow - Feature Integration', () => {
|
|
|
203
203
|
|
|
204
204
|
// First progress update
|
|
205
205
|
act(() => {
|
|
206
|
-
getEventBus().get('
|
|
206
|
+
getEventBus().get('yield:progress').next({
|
|
207
207
|
status: 'started',
|
|
208
208
|
message: 'Starting generation...',
|
|
209
209
|
percentage: 0,
|
|
@@ -216,7 +216,7 @@ describe('Generation Flow - Feature Integration', () => {
|
|
|
216
216
|
|
|
217
217
|
// Second progress update
|
|
218
218
|
act(() => {
|
|
219
|
-
getEventBus().get('
|
|
219
|
+
getEventBus().get('yield:progress').next({
|
|
220
220
|
status: 'generating',
|
|
221
221
|
message: 'Creating document structure...',
|
|
222
222
|
percentage: 50,
|
|
@@ -229,7 +229,7 @@ describe('Generation Flow - Feature Integration', () => {
|
|
|
229
229
|
|
|
230
230
|
// Final progress update via onComplete
|
|
231
231
|
act(() => {
|
|
232
|
-
getEventBus().get('
|
|
232
|
+
getEventBus().get('yield:finished').next({
|
|
233
233
|
status: 'complete',
|
|
234
234
|
referenceId: testAnnotationUri,
|
|
235
235
|
message: 'Document created successfully',
|
|
@@ -248,7 +248,7 @@ describe('Generation Flow - Feature Integration', () => {
|
|
|
248
248
|
const testResourceUri = resourceUri('http://localhost:4000/resources/test-resource');
|
|
249
249
|
const testAnnotationUri = annotationUri('http://localhost:4000/resources/test-resource/annotations/test-annotation');
|
|
250
250
|
|
|
251
|
-
const { emitGenerationStart, getEventBus } =
|
|
251
|
+
const { emitGenerationStart, getEventBus } = renderYieldFlow(
|
|
252
252
|
testResourceUri
|
|
253
253
|
);
|
|
254
254
|
|
|
@@ -266,7 +266,7 @@ describe('Generation Flow - Feature Integration', () => {
|
|
|
266
266
|
|
|
267
267
|
// Simulate completion with final chunk
|
|
268
268
|
act(() => {
|
|
269
|
-
getEventBus().get('
|
|
269
|
+
getEventBus().get('yield:progress').next({
|
|
270
270
|
status: 'complete',
|
|
271
271
|
message: 'Complete',
|
|
272
272
|
resourceName: 'Generated Document',
|
|
@@ -275,7 +275,7 @@ describe('Generation Flow - Feature Integration', () => {
|
|
|
275
275
|
|
|
276
276
|
// Emit completion event
|
|
277
277
|
act(() => {
|
|
278
|
-
getEventBus().get('
|
|
278
|
+
getEventBus().get('yield:finished').next({
|
|
279
279
|
status: 'complete',
|
|
280
280
|
referenceId: testAnnotationUri,
|
|
281
281
|
resourceName: 'Generated Document',
|
|
@@ -291,7 +291,7 @@ describe('Generation Flow - Feature Integration', () => {
|
|
|
291
291
|
const testResourceUri = resourceUri('http://localhost:4000/resources/test-resource');
|
|
292
292
|
const testAnnotationUri = annotationUri('http://localhost:4000/resources/test-resource/annotations/test-annotation');
|
|
293
293
|
|
|
294
|
-
const { emitGenerationStart, getEventBus } =
|
|
294
|
+
const { emitGenerationStart, getEventBus } = renderYieldFlow(
|
|
295
295
|
testResourceUri
|
|
296
296
|
);
|
|
297
297
|
|
|
@@ -305,7 +305,7 @@ describe('Generation Flow - Feature Integration', () => {
|
|
|
305
305
|
|
|
306
306
|
// Add some progress
|
|
307
307
|
act(() => {
|
|
308
|
-
getEventBus().get('
|
|
308
|
+
getEventBus().get('yield:progress').next({
|
|
309
309
|
status: 'generating',
|
|
310
310
|
message: 'Generating...',
|
|
311
311
|
});
|
|
@@ -317,7 +317,7 @@ describe('Generation Flow - Feature Integration', () => {
|
|
|
317
317
|
|
|
318
318
|
// Emit failure
|
|
319
319
|
act(() => {
|
|
320
|
-
getEventBus().get('
|
|
320
|
+
getEventBus().get('yield:failed').next({ error: new Error('Network error') });
|
|
321
321
|
});
|
|
322
322
|
|
|
323
323
|
// Verify: progress cleared and not generating
|
|
@@ -331,13 +331,13 @@ describe('Generation Flow - Feature Integration', () => {
|
|
|
331
331
|
const testResourceUri = resourceUri('http://localhost:4000/resources/test-resource');
|
|
332
332
|
const testAnnotationUri = annotationUri('http://localhost:4000/resources/test-resource/annotations/test-annotation');
|
|
333
333
|
|
|
334
|
-
const { emitGenerationStart, getEventBus } =
|
|
334
|
+
const { emitGenerationStart, getEventBus } = renderYieldFlow(
|
|
335
335
|
testResourceUri
|
|
336
336
|
);
|
|
337
337
|
|
|
338
338
|
// Add an additional event listener (simulating multiple subscribers)
|
|
339
339
|
const additionalListener = vi.fn();
|
|
340
|
-
const subscription = getEventBus().get('
|
|
340
|
+
const subscription = getEventBus().get('yield:request').subscribe(additionalListener);
|
|
341
341
|
|
|
342
342
|
// Trigger generation
|
|
343
343
|
act(() => {
|
|
@@ -365,7 +365,7 @@ describe('Generation Flow - Feature Integration', () => {
|
|
|
365
365
|
const testResourceUri = resourceUri('http://localhost:4000/resources/test-resource');
|
|
366
366
|
const testAnnotationUri = annotationUri('http://localhost:4000/resources/test-resource/annotations/test-annotation');
|
|
367
367
|
|
|
368
|
-
const { emitGenerationStart, getEventBus } =
|
|
368
|
+
const { emitGenerationStart, getEventBus } = renderYieldFlow(
|
|
369
369
|
testResourceUri
|
|
370
370
|
);
|
|
371
371
|
|
|
@@ -383,7 +383,7 @@ describe('Generation Flow - Feature Integration', () => {
|
|
|
383
383
|
|
|
384
384
|
// Simulate onComplete with final chunk
|
|
385
385
|
act(() => {
|
|
386
|
-
getEventBus().get('
|
|
386
|
+
getEventBus().get('yield:finished').next({
|
|
387
387
|
status: 'complete',
|
|
388
388
|
referenceId: testAnnotationUri,
|
|
389
389
|
message: 'Document created: My Document',
|
|
@@ -401,10 +401,10 @@ describe('Generation Flow - Feature Integration', () => {
|
|
|
401
401
|
});
|
|
402
402
|
|
|
403
403
|
/**
|
|
404
|
-
* Helper: Render
|
|
404
|
+
* Helper: Render useYieldFlow hook with real component composition
|
|
405
405
|
* Returns methods to interact with the rendered component
|
|
406
406
|
*/
|
|
407
|
-
function
|
|
407
|
+
function renderYieldFlow(
|
|
408
408
|
testResourceUri: ResourceUri
|
|
409
409
|
) {
|
|
410
410
|
let eventBusInstance: Emitter<EventMap>;
|
|
@@ -414,19 +414,19 @@ function renderGenerationFlow(
|
|
|
414
414
|
eventBusInstance = useEventBus();
|
|
415
415
|
|
|
416
416
|
// Set up resolution flow (resolve:update-body, resolve:link)
|
|
417
|
-
|
|
417
|
+
useBindFlow(testResourceUri);
|
|
418
418
|
|
|
419
419
|
return null;
|
|
420
420
|
}
|
|
421
421
|
|
|
422
422
|
// Test harness component that uses the hook
|
|
423
|
-
function
|
|
423
|
+
function YieldFlowTestHarness() {
|
|
424
424
|
const {
|
|
425
425
|
generationProgress,
|
|
426
426
|
generationModalOpen,
|
|
427
427
|
generationReferenceId,
|
|
428
428
|
generationDefaultTitle,
|
|
429
|
-
} =
|
|
429
|
+
} = useYieldFlow(
|
|
430
430
|
'en',
|
|
431
431
|
testResourceUri.split('/resources/')[1] || 'test-resource',
|
|
432
432
|
vi.fn()
|
|
@@ -452,7 +452,7 @@ function renderGenerationFlow(
|
|
|
452
452
|
<AuthTokenProvider token={null}>
|
|
453
453
|
<ApiClientProvider baseUrl="http://localhost:4000">
|
|
454
454
|
<EventBusCapture />
|
|
455
|
-
<
|
|
455
|
+
<YieldFlowTestHarness />
|
|
456
456
|
</ApiClientProvider>
|
|
457
457
|
</AuthTokenProvider>
|
|
458
458
|
</EventBusProvider>
|
|
@@ -464,7 +464,7 @@ function renderGenerationFlow(
|
|
|
464
464
|
resourceUri: ResourceUri,
|
|
465
465
|
defaultTitle: string
|
|
466
466
|
) => {
|
|
467
|
-
eventBusInstance.get('
|
|
467
|
+
eventBusInstance.get('yield:modal-open').next({
|
|
468
468
|
annotationUri,
|
|
469
469
|
resourceUri,
|
|
470
470
|
defaultTitle,
|
|
@@ -482,7 +482,7 @@ function renderGenerationFlow(
|
|
|
482
482
|
context: any;
|
|
483
483
|
}
|
|
484
484
|
) => {
|
|
485
|
-
eventBusInstance.get('
|
|
485
|
+
eventBusInstance.get('yield:request').next({
|
|
486
486
|
annotationUri,
|
|
487
487
|
resourceUri,
|
|
488
488
|
options,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Layer 3 Integration Test: Detection Progress Flow UI/UX
|
|
3
3
|
*
|
|
4
|
-
* Tests the complete data flow from UI → EventBus →
|
|
4
|
+
* Tests the complete data flow from UI → EventBus → useBindFlow → SSE (mocked)
|
|
5
5
|
*
|
|
6
6
|
* This test uses COMPOSITION instead of mocking:
|
|
7
|
-
* - Real React components composed together (
|
|
7
|
+
* - Real React components composed together (useMarkFlow + HighlightPanel + AssistSection)
|
|
8
8
|
* - Real EventBus (mitt) passed via context
|
|
9
|
-
* - Real
|
|
9
|
+
* - Real useBindFlow hook with mock API client passed as prop
|
|
10
10
|
* - Mock SSE stream (simulated API responses) provided via composition
|
|
11
11
|
*
|
|
12
12
|
* This test focuses on USER EXPERIENCE:
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* - That test verifies SYSTEM ARCHITECTURE (event wiring, API call count)
|
|
20
20
|
* - This test verifies USER EXPERIENCE (button clicks, UI feedback)
|
|
21
21
|
*
|
|
22
|
-
* UPDATED: Now tests
|
|
22
|
+
* UPDATED: Now tests useMarkFlow hook instead of DetectionFlowContainer
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
25
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
@@ -27,7 +27,7 @@ import { render, screen, waitFor } from '@testing-library/react';
|
|
|
27
27
|
import userEvent from '@testing-library/user-event';
|
|
28
28
|
import { act } from 'react';
|
|
29
29
|
import { HighlightPanel } from '../../../components/resource/panels/HighlightPanel';
|
|
30
|
-
import {
|
|
30
|
+
import { useMarkFlow } from '../../../hooks/useMarkFlow';
|
|
31
31
|
import { EventBusProvider, resetEventBusForTesting } from '../../../contexts/EventBusContext';
|
|
32
32
|
import { ApiClientProvider } from '../../../contexts/ApiClientContext';
|
|
33
33
|
import { AuthTokenProvider } from '../../../contexts/AuthTokenContext';
|
|
@@ -79,18 +79,18 @@ class MockSSEStream {
|
|
|
79
79
|
|
|
80
80
|
// Test helper methods that emit to EventBus
|
|
81
81
|
emitProgress(chunk: any) {
|
|
82
|
-
this.eventBus.get('
|
|
82
|
+
this.eventBus.get('mark:progress').next(chunk);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
emitComplete(finalChunk?: any, motivation: string = 'highlighting') {
|
|
86
86
|
if (finalChunk) {
|
|
87
|
-
this.eventBus.get('
|
|
87
|
+
this.eventBus.get('mark:progress').next(finalChunk);
|
|
88
88
|
}
|
|
89
|
-
this.eventBus.get('
|
|
89
|
+
this.eventBus.get('mark:assist-finished').next({ motivation });
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
emitError(error: Error) {
|
|
93
|
-
this.eventBus.get('
|
|
93
|
+
this.eventBus.get('mark:assist-failed').next({
|
|
94
94
|
type: 'job.failed' as const,
|
|
95
95
|
resourceId: 'test' as any,
|
|
96
96
|
userId: 'user' as any,
|
|
@@ -114,7 +114,7 @@ function DetectionFlowTestHarness({
|
|
|
114
114
|
rUri: string;
|
|
115
115
|
annotations: Annotation[];
|
|
116
116
|
}) {
|
|
117
|
-
const { assistingMotivation, progress } =
|
|
117
|
+
const { assistingMotivation, progress } = useMarkFlow(rUri as any);
|
|
118
118
|
|
|
119
119
|
return (
|
|
120
120
|
<HighlightPanel
|
|
@@ -305,7 +305,7 @@ describe('Detection Progress Flow Integration (Layer 3)', () => {
|
|
|
305
305
|
});
|
|
306
306
|
});
|
|
307
307
|
|
|
308
|
-
it('should clear progress on
|
|
308
|
+
it('should clear progress on mark:assist-failed', async () => {
|
|
309
309
|
const user = userEvent.setup();
|
|
310
310
|
|
|
311
311
|
renderDetectionFlow();
|
|
@@ -37,12 +37,12 @@ import { useEventBus } from '../../../contexts/EventBusContext';
|
|
|
37
37
|
import { useEventSubscriptions } from '../../../contexts/useEventSubscription';
|
|
38
38
|
import { useResourceAnnotations } from '../../../contexts/ResourceAnnotationsContext';
|
|
39
39
|
import { useApiClient } from '../../../contexts/ApiClientContext';
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
43
|
-
import {
|
|
44
|
-
import {
|
|
45
|
-
import {
|
|
40
|
+
import { useBindFlow } from '../../../hooks/useBindFlow';
|
|
41
|
+
import { useMarkFlow } from '../../../hooks/useMarkFlow';
|
|
42
|
+
import { useBeckonFlow } from '../../../hooks/useBeckonFlow';
|
|
43
|
+
import { usePanelBrowse } from '../../../hooks/usePanelBrowse';
|
|
44
|
+
import { useYieldFlow } from '../../../hooks/useYieldFlow';
|
|
45
|
+
import { useContextGatherFlow } from '../../../hooks/useContextGatherFlow';
|
|
46
46
|
|
|
47
47
|
type SemiontResource = components['schemas']['ResourceDescriptor'];
|
|
48
48
|
type Annotation = components['schemas']['Annotation'];
|
|
@@ -91,18 +91,18 @@ export interface ResourceViewerPageProps {
|
|
|
91
91
|
*
|
|
92
92
|
* Uses hooks directly (NO containers, NO render props, NO ResourceViewerPageContent wrapper)
|
|
93
93
|
*
|
|
94
|
-
* @emits
|
|
95
|
-
* @emits
|
|
96
|
-
* @emits
|
|
97
|
-
* @subscribes
|
|
98
|
-
* @subscribes
|
|
99
|
-
* @subscribes
|
|
100
|
-
* @subscribes
|
|
101
|
-
* @subscribes
|
|
102
|
-
* @subscribes
|
|
103
|
-
* @subscribes
|
|
104
|
-
* @subscribes
|
|
105
|
-
* @subscribes
|
|
94
|
+
* @emits browse:router-push - Navigate to a resource or filtered view
|
|
95
|
+
* @emits beckon:sparkle - Trigger sparkle animation on an annotation
|
|
96
|
+
* @emits bind:update-body - Update annotation body content
|
|
97
|
+
* @subscribes mark:archive - Archive the current resource
|
|
98
|
+
* @subscribes mark:unarchive - Unarchive the current resource
|
|
99
|
+
* @subscribes yield:clone - Clone the current resource
|
|
100
|
+
* @subscribes beckon:sparkle - Trigger sparkle animation
|
|
101
|
+
* @subscribes mark:added - Annotation was created
|
|
102
|
+
* @subscribes mark:removed - Annotation was deleted
|
|
103
|
+
* @subscribes mark:create-failed - Annotation creation failed
|
|
104
|
+
* @subscribes mark:delete-failed - Annotation deletion failed
|
|
105
|
+
* @subscribes mark:body-updated - Annotation body was updated
|
|
106
106
|
* @subscribes annotate:body-update-failed - Annotation body update failed
|
|
107
107
|
* @subscribes settings:theme-changed - UI theme changed
|
|
108
108
|
* @subscribes settings:line-numbers-toggled - Line numbers display toggled
|
|
@@ -110,8 +110,8 @@ export interface ResourceViewerPageProps {
|
|
|
110
110
|
* @subscribes detection:failed - Detection failed
|
|
111
111
|
* @subscribes generation:complete - Generation completed
|
|
112
112
|
* @subscribes generation:failed - Generation failed
|
|
113
|
-
* @subscribes
|
|
114
|
-
* @subscribes
|
|
113
|
+
* @subscribes browse:reference-navigate - Navigate to a referenced document
|
|
114
|
+
* @subscribes browse:entity-type-clicked - Navigate filtered by entity type
|
|
115
115
|
*/
|
|
116
116
|
export function ResourceViewerPage({
|
|
117
117
|
resource,
|
|
@@ -157,10 +157,10 @@ export function ResourceViewerPage({
|
|
|
157
157
|
const allEntityTypes = (entityTypesData as { entityTypes: string[] } | undefined)?.entityTypes || [];
|
|
158
158
|
|
|
159
159
|
// Flow state hooks (NO CONTAINERS)
|
|
160
|
-
const { hoveredAnnotationId } =
|
|
161
|
-
const { assistingMotivation, progress, pendingAnnotation } =
|
|
162
|
-
const { activePanel, scrollToAnnotationId, panelInitialTab, onScrollCompleted } =
|
|
163
|
-
const { searchModalOpen, pendingReferenceId, onCloseSearchModal } =
|
|
160
|
+
const { hoveredAnnotationId } = useBeckonFlow();
|
|
161
|
+
const { assistingMotivation, progress, pendingAnnotation } = useMarkFlow(rUri);
|
|
162
|
+
const { activePanel, scrollToAnnotationId, panelInitialTab, onScrollCompleted } = usePanelBrowse();
|
|
163
|
+
const { searchModalOpen, pendingReferenceId, onCloseSearchModal } = useBindFlow(rUri);
|
|
164
164
|
const {
|
|
165
165
|
generationProgress,
|
|
166
166
|
generationModalOpen,
|
|
@@ -168,8 +168,8 @@ export function ResourceViewerPage({
|
|
|
168
168
|
generationDefaultTitle,
|
|
169
169
|
onGenerateDocument,
|
|
170
170
|
onCloseGenerationModal,
|
|
171
|
-
} =
|
|
172
|
-
const {
|
|
171
|
+
} = useYieldFlow(locale, rUri.split('/').pop() || '', clearNewAnnotationId);
|
|
172
|
+
const { gatherContext, gatherLoading, gatherError } = useContextGatherFlow(eventBus, { client, resourceUri: rUri });
|
|
173
173
|
|
|
174
174
|
// Debounced invalidation for real-time events
|
|
175
175
|
const debouncedInvalidateAnnotations = useDebouncedCallback(
|
|
@@ -305,7 +305,7 @@ export function ResourceViewerPage({
|
|
|
305
305
|
try {
|
|
306
306
|
const result = await generateCloneTokenMutation.mutateAsync(rUri);
|
|
307
307
|
const token = result.token;
|
|
308
|
-
eventBus.get('
|
|
308
|
+
eventBus.get('browse:router-push').next({ path: `/know/compose?mode=clone&token=${token}`, reason: 'clone' });
|
|
309
309
|
} catch (err) {
|
|
310
310
|
console.error('Failed to generate clone token:', err);
|
|
311
311
|
showError('Failed to generate clone link');
|
|
@@ -331,56 +331,56 @@ export function ResourceViewerPage({
|
|
|
331
331
|
const handleSettingsThemeChanged = useCallback(({ theme }: { theme: any }) => setTheme(theme), [setTheme]);
|
|
332
332
|
|
|
333
333
|
const handleDetectionComplete = useCallback(() => {
|
|
334
|
-
// Toast notification is handled by
|
|
334
|
+
// Toast notification is handled by useMarkFlow
|
|
335
335
|
queryClient.invalidateQueries({ queryKey: QUERY_KEYS.resources.annotations(rUri) });
|
|
336
336
|
queryClient.invalidateQueries({ queryKey: QUERY_KEYS.resources.events(rUri) });
|
|
337
337
|
}, [queryClient, rUri]);
|
|
338
338
|
const handleDetectionFailed = useCallback(() => {
|
|
339
|
-
// Error notification is handled by
|
|
339
|
+
// Error notification is handled by useMarkFlow
|
|
340
340
|
queryClient.invalidateQueries({ queryKey: QUERY_KEYS.resources.annotations(rUri) });
|
|
341
341
|
queryClient.invalidateQueries({ queryKey: QUERY_KEYS.resources.events(rUri) });
|
|
342
342
|
}, [queryClient, rUri]);
|
|
343
343
|
const handleGenerationComplete = useCallback(() => {
|
|
344
|
-
// Toast notification is handled by
|
|
344
|
+
// Toast notification is handled by useYieldFlow
|
|
345
345
|
}, []);
|
|
346
346
|
const handleGenerationFailed = useCallback(() => {
|
|
347
|
-
// Error notification is handled by
|
|
347
|
+
// Error notification is handled by useYieldFlow
|
|
348
348
|
}, []);
|
|
349
349
|
|
|
350
350
|
const handleReferenceNavigate = useCallback(({ documentId }: { documentId: string }) => {
|
|
351
351
|
if (routes.resource) {
|
|
352
352
|
const path = routes.resource.replace('[resourceId]', encodeURIComponent(documentId));
|
|
353
|
-
eventBus.get('
|
|
353
|
+
eventBus.get('browse:router-push').next({ path, reason: 'reference-link' });
|
|
354
354
|
}
|
|
355
355
|
}, [routes.resource]); // eventBus is stable singleton - never in deps
|
|
356
356
|
|
|
357
357
|
const handleEntityTypeClicked = useCallback(({ entityType }: { entityType: string }) => {
|
|
358
358
|
if (routes.know) {
|
|
359
359
|
const path = `${routes.know}?entityType=${encodeURIComponent(entityType)}`;
|
|
360
|
-
eventBus.get('
|
|
360
|
+
eventBus.get('browse:router-push').next({ path, reason: 'entity-type-filter' });
|
|
361
361
|
}
|
|
362
362
|
}, [routes.know]); // eventBus is stable singleton - never in deps
|
|
363
363
|
|
|
364
364
|
// Event bus subscriptions (combined into single useEventSubscriptions call to prevent hook ordering issues)
|
|
365
365
|
useEventSubscriptions({
|
|
366
|
-
'
|
|
367
|
-
'
|
|
368
|
-
'
|
|
369
|
-
'
|
|
370
|
-
'
|
|
371
|
-
'
|
|
372
|
-
'
|
|
373
|
-
'
|
|
374
|
-
'
|
|
375
|
-
'
|
|
366
|
+
'mark:archive': handleResourceArchive,
|
|
367
|
+
'mark:unarchive': handleResourceUnarchive,
|
|
368
|
+
'yield:clone': handleResourceClone,
|
|
369
|
+
'beckon:sparkle': handleAnnotationSparkle,
|
|
370
|
+
'mark:added': handleAnnotationAdded,
|
|
371
|
+
'mark:removed': debouncedInvalidateAnnotations,
|
|
372
|
+
'mark:create-failed': handleAnnotationCreateFailed,
|
|
373
|
+
'mark:delete-failed': handleAnnotationDeleteFailed,
|
|
374
|
+
'mark:body-updated': handleAnnotateBodyUpdated,
|
|
375
|
+
'bind:body-update-failed': handleAnnotateBodyUpdateFailed,
|
|
376
376
|
'settings:theme-changed': handleSettingsThemeChanged,
|
|
377
377
|
'settings:line-numbers-toggled': toggleLineNumbers,
|
|
378
|
-
'
|
|
379
|
-
'
|
|
380
|
-
'
|
|
381
|
-
'
|
|
382
|
-
'
|
|
383
|
-
'
|
|
378
|
+
'mark:assist-finished': handleDetectionComplete,
|
|
379
|
+
'mark:assist-failed': handleDetectionFailed,
|
|
380
|
+
'yield:finished': handleGenerationComplete,
|
|
381
|
+
'yield:failed': handleGenerationFailed,
|
|
382
|
+
'browse:reference-navigate': handleReferenceNavigate,
|
|
383
|
+
'browse:entity-type-clicked': handleEntityTypeClicked,
|
|
384
384
|
});
|
|
385
385
|
|
|
386
386
|
// Resource loading announcements
|
|
@@ -443,7 +443,7 @@ export function ResourceViewerPage({
|
|
|
443
443
|
// Handlers for AnnotationHistory (legacy event-based interaction)
|
|
444
444
|
const handleEventHover = useCallback((annotationId: string | null) => {
|
|
445
445
|
if (annotationId) {
|
|
446
|
-
eventBus.get('
|
|
446
|
+
eventBus.get('beckon:sparkle').next({ annotationId });
|
|
447
447
|
}
|
|
448
448
|
}, []); // eventBus is stable singleton - never in deps
|
|
449
449
|
|
|
@@ -611,7 +611,7 @@ export function ResourceViewerPage({
|
|
|
611
611
|
const resourceIdSegment = rUri.split('/').pop() || '';
|
|
612
612
|
const nestedUri = `${window.location.origin}/resources/${resourceIdSegment}/annotations/${annotationIdShort}`;
|
|
613
613
|
|
|
614
|
-
eventBus.get('
|
|
614
|
+
eventBus.get('bind:update-body').next({
|
|
615
615
|
annotationUri: resourceAnnotationUri(nestedUri),
|
|
616
616
|
resourceId: resourceIdSegment,
|
|
617
617
|
operations: [{
|
|
@@ -624,7 +624,7 @@ export function ResourceViewerPage({
|
|
|
624
624
|
}],
|
|
625
625
|
});
|
|
626
626
|
showSuccess('Reference linked successfully');
|
|
627
|
-
// Cache invalidation now handled by
|
|
627
|
+
// Cache invalidation now handled by mark:body-updated event
|
|
628
628
|
onCloseSearchModal();
|
|
629
629
|
} catch (error) {
|
|
630
630
|
console.error('Failed to link reference:', error);
|
|
@@ -644,9 +644,9 @@ export function ResourceViewerPage({
|
|
|
644
644
|
}
|
|
645
645
|
}}
|
|
646
646
|
defaultTitle={generationDefaultTitle}
|
|
647
|
-
context={
|
|
648
|
-
contextLoading={
|
|
649
|
-
contextError={
|
|
647
|
+
context={gatherContext}
|
|
648
|
+
contextLoading={gatherLoading}
|
|
649
|
+
contextError={gatherError}
|
|
650
650
|
/>
|
|
651
651
|
</div>
|
|
652
652
|
);
|