@semiont/react-ui 0.2.33-build.79 → 0.2.33-build.80
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/EventBusContext-7GvDyO0d.d.mts +414 -0
- package/dist/{PdfAnnotationCanvas.client-ADC4FFSE.mjs → PdfAnnotationCanvas.client-RAJRPQLU.mjs} +42 -27
- package/dist/PdfAnnotationCanvas.client-RAJRPQLU.mjs.map +1 -0
- package/dist/{ar-EMHEHPCJ.mjs → ar-4ZEORRW2.mjs} +7 -4
- package/dist/ar-4ZEORRW2.mjs.map +1 -0
- package/dist/{bn-OVCI4F6X.mjs → bn-SEDE5BQJ.mjs} +7 -4
- package/dist/bn-SEDE5BQJ.mjs.map +1 -0
- package/dist/{chunk-LIHZTECW.mjs → chunk-D7NBW4RV.mjs} +7 -4
- package/dist/chunk-D7NBW4RV.mjs.map +1 -0
- package/dist/{chunk-JZIO2A3B.mjs → chunk-ZR4ZV2LY.mjs} +206 -146
- package/dist/chunk-ZR4ZV2LY.mjs.map +1 -0
- package/dist/{cs-FAN66Q2F.mjs → cs-7W4WF5WD.mjs} +7 -4
- package/dist/cs-7W4WF5WD.mjs.map +1 -0
- package/dist/{da-YBBIHI2O.mjs → da-75XGBCBK.mjs} +7 -4
- package/dist/da-75XGBCBK.mjs.map +1 -0
- package/dist/{de-MAYU33LB.mjs → de-ODJVFLHM.mjs} +7 -4
- package/dist/de-ODJVFLHM.mjs.map +1 -0
- package/dist/{el-MKGSWN4O.mjs → el-C4PM4WB3.mjs} +7 -4
- package/dist/el-C4PM4WB3.mjs.map +1 -0
- package/dist/{en-DDLIXJCU.mjs → en-KJCJQ4OO.mjs} +2 -2
- package/dist/{es-52LHUWJD.mjs → es-WD33R7QL.mjs} +7 -4
- package/dist/es-WD33R7QL.mjs.map +1 -0
- package/dist/{fa-FJICRANB.mjs → fa-2BP6V56P.mjs} +7 -4
- package/dist/fa-2BP6V56P.mjs.map +1 -0
- package/dist/{fi-O455XFCR.mjs → fi-USRRW24J.mjs} +7 -4
- package/dist/fi-USRRW24J.mjs.map +1 -0
- package/dist/{fr-TXIXHOOE.mjs → fr-EC5S6WVF.mjs} +7 -4
- package/dist/fr-EC5S6WVF.mjs.map +1 -0
- package/dist/{he-JBSOX5IN.mjs → he-7TBVIKAA.mjs} +7 -4
- package/dist/he-7TBVIKAA.mjs.map +1 -0
- package/dist/{hi-KGHI3XVT.mjs → hi-FO4VIZLA.mjs} +7 -4
- package/dist/hi-FO4VIZLA.mjs.map +1 -0
- package/dist/{id-5OCPPZLO.mjs → id-7U7GGVWY.mjs} +7 -4
- package/dist/id-7U7GGVWY.mjs.map +1 -0
- package/dist/index.css +123 -85
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +645 -471
- package/dist/index.mjs +3461 -3025
- package/dist/index.mjs.map +1 -1
- package/dist/{it-PNBBZSM2.mjs → it-Y4OPL6I2.mjs} +7 -4
- package/dist/it-Y4OPL6I2.mjs.map +1 -0
- package/dist/{ja-LDD7R3TJ.mjs → ja-PK7SQL55.mjs} +7 -4
- package/dist/ja-PK7SQL55.mjs.map +1 -0
- package/dist/{ko-F47ZDEY3.mjs → ko-L25PXMYD.mjs} +7 -4
- package/dist/ko-L25PXMYD.mjs.map +1 -0
- package/dist/{ms-Z7LMXJWL.mjs → ms-STH777QM.mjs} +7 -4
- package/dist/ms-STH777QM.mjs.map +1 -0
- package/dist/{nl-6SJFBPJ3.mjs → nl-Y7LECDDR.mjs} +7 -4
- package/dist/nl-Y7LECDDR.mjs.map +1 -0
- package/dist/{no-YXPBPSGF.mjs → no-KEKCEWU6.mjs} +7 -4
- package/dist/no-KEKCEWU6.mjs.map +1 -0
- package/dist/{pl-P4AZ2QME.mjs → pl-7A7OC75O.mjs} +7 -4
- package/dist/pl-7A7OC75O.mjs.map +1 -0
- package/dist/{pt-LHWUS6U6.mjs → pt-35HTM7RA.mjs} +7 -4
- package/dist/pt-35HTM7RA.mjs.map +1 -0
- package/dist/{ro-EA5J2ZON.mjs → ro-VAWL5KQA.mjs} +7 -4
- package/dist/ro-VAWL5KQA.mjs.map +1 -0
- package/dist/{sv-DATBS3UQ.mjs → sv-7ZK5EQEB.mjs} +7 -4
- package/dist/sv-7ZK5EQEB.mjs.map +1 -0
- package/dist/test-utils.d.mts +18 -8
- package/dist/test-utils.mjs +36 -14
- package/dist/test-utils.mjs.map +1 -1
- package/dist/{th-WTFJRWPT.mjs → th-UDWZ4X34.mjs} +7 -4
- package/dist/th-UDWZ4X34.mjs.map +1 -0
- package/dist/{tr-IKO3RXOX.mjs → tr-4WMPK3UX.mjs} +7 -4
- package/dist/tr-4WMPK3UX.mjs.map +1 -0
- package/dist/{uk-CF6CTTRK.mjs → uk-SSLASQYJ.mjs} +7 -4
- package/dist/uk-SSLASQYJ.mjs.map +1 -0
- package/dist/{vi-AJLTXPZQ.mjs → vi-IF42Z5PU.mjs} +7 -4
- package/dist/vi-IF42Z5PU.mjs.map +1 -0
- package/dist/{zh-U3ORHHYH.mjs → zh-HRQTNTAI.mjs} +7 -4
- package/dist/zh-HRQTNTAI.mjs.map +1 -0
- package/package.json +3 -1
- package/src/components/CodeMirrorRenderer.tsx +66 -93
- package/src/components/DetectionProgressWidget.tsx +16 -5
- package/src/components/LiveRegion.tsx +18 -18
- package/src/components/ResizeHandle.tsx +10 -4
- package/src/components/SessionTimer.tsx +2 -2
- package/src/components/Toolbar.tsx +18 -9
- package/src/components/__tests__/SessionTimer.test.tsx +9 -9
- package/src/components/annotation/AnnotateToolbar.tsx +17 -15
- package/src/components/annotation/__tests__/AnnotateToolbar.test.tsx +165 -63
- package/src/components/annotation/annotation-entries.css +10 -0
- package/src/components/annotation-popups/JsonLdView.tsx +8 -2
- package/src/components/image-annotation/AnnotationOverlay.tsx +42 -22
- package/src/components/image-annotation/SvgDrawingCanvas.tsx +27 -30
- package/src/components/layout/__tests__/LeftSidebar.test.tsx +12 -33
- package/src/components/layout/__tests__/PageLayout.test.tsx +37 -32
- package/src/components/layout/__tests__/UnifiedHeader.test.tsx +21 -40
- package/src/components/modals/ResourceSearchModal.tsx +2 -2
- package/src/components/modals/SearchModal.tsx +1 -1
- package/src/components/navigation/CollapsibleResourceNavigation.tsx +14 -9
- package/src/components/navigation/NavigationTabs.css +36 -24
- package/src/components/navigation/ObservableLink.tsx +91 -0
- package/src/components/navigation/SimpleNavigation.tsx +20 -16
- package/src/components/navigation/SortableResourceTab.tsx +11 -5
- package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +51 -26
- package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +28 -22
- package/src/components/resource/AnnotateView.tsx +64 -134
- package/src/components/resource/BrowseView.tsx +86 -166
- package/src/components/resource/HistoryEvent.tsx +13 -7
- package/src/components/resource/ResourceViewer.tsx +122 -264
- package/src/components/resource/__tests__/BrowseView.test.tsx +631 -0
- package/src/components/resource/__tests__/ResourceViewer.mode-switch.test.tsx +231 -0
- package/src/components/resource/panels/AssessmentEntry.tsx +25 -33
- package/src/components/resource/panels/AssessmentPanel.tsx +106 -28
- package/src/components/resource/panels/CommentEntry.tsx +38 -32
- package/src/components/resource/panels/CommentsPanel.tsx +121 -28
- package/src/components/resource/panels/DetectSection.css +36 -1
- package/src/components/resource/panels/DetectSection.tsx +38 -10
- package/src/components/resource/panels/HighlightEntry.tsx +25 -33
- package/src/components/resource/panels/HighlightPanel.tsx +100 -25
- package/src/components/resource/panels/ReferenceEntry.tsx +61 -75
- package/src/components/resource/panels/ReferencesPanel.tsx +134 -42
- package/src/components/resource/panels/ResourceInfoPanel.tsx +47 -48
- package/src/components/resource/panels/TagEntry.tsx +25 -33
- package/src/components/resource/panels/TaggingPanel.tsx +119 -30
- package/src/components/resource/panels/UnifiedAnnotationsPanel.tsx +30 -92
- package/src/components/resource/panels/__tests__/AssessmentPanel.test.tsx +129 -110
- package/src/components/resource/panels/__tests__/CommentEntry.test.tsx +86 -78
- package/src/components/resource/panels/__tests__/CommentsPanel.test.tsx +144 -149
- package/src/components/resource/panels/__tests__/DetectSection.test.tsx +480 -0
- package/src/components/resource/panels/__tests__/HighlightPanel.detectionProgress.test.tsx +362 -0
- package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +226 -111
- package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +117 -61
- package/src/components/resource/panels/__tests__/TaggingPanel.test.tsx +128 -106
- package/src/components/settings/SettingsPanel.tsx +15 -12
- package/src/features/admin-devops/__tests__/AdminDevOpsPage.test.tsx +1 -46
- package/src/features/admin-devops/components/AdminDevOpsPage.tsx +0 -9
- package/src/features/admin-security/__tests__/AdminSecurityPage.test.tsx +0 -3
- package/src/features/admin-security/components/AdminSecurityPage.tsx +0 -9
- package/src/features/admin-users/__tests__/AdminUsersPage.test.tsx +0 -3
- package/src/features/admin-users/components/AdminUsersPage.tsx +0 -9
- package/src/features/moderate-entity-tags/__tests__/EntityTagsPage.test.tsx +0 -3
- package/src/features/moderate-entity-tags/components/EntityTagsPage.tsx +1 -9
- package/src/features/moderate-recent/__tests__/RecentDocumentsPage.test.tsx +0 -32
- package/src/features/moderate-recent/components/RecentDocumentsPage.tsx +1 -9
- package/src/features/moderate-tag-schemas/__tests__/TagSchemasPage.test.tsx +0 -32
- package/src/features/moderate-tag-schemas/components/TagSchemasPage.tsx +1 -9
- package/src/features/resource-compose/__tests__/ResourceComposePage.test.tsx +51 -54
- package/src/features/resource-compose/components/ResourceComposePage.tsx +3 -13
- package/src/features/resource-discovery/__tests__/ResourceDiscoveryPage.test.tsx +39 -45
- package/src/features/resource-discovery/components/ResourceDiscoveryPage.tsx +9 -13
- package/src/features/resource-viewer/__tests__/AnnotationDeletionIntegration.test.tsx +231 -0
- package/src/features/resource-viewer/__tests__/DetectionFlowBug.test.tsx +234 -0
- package/src/features/resource-viewer/__tests__/DetectionFlowIntegration.test.tsx +388 -0
- package/src/features/resource-viewer/__tests__/DetectionProgressDismissal.test.tsx +318 -0
- package/src/features/resource-viewer/__tests__/GenerationFlowIntegration.test.tsx +504 -0
- package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +135 -88
- package/src/features/resource-viewer/__tests__/detection-progress-flow.test.tsx +322 -0
- package/src/features/resource-viewer/components/ResourceViewerPage.tsx +308 -528
- package/translations/ar.json +6 -3
- package/translations/bn.json +6 -3
- package/translations/cs.json +6 -3
- package/translations/da.json +6 -3
- package/translations/de.json +6 -3
- package/translations/el.json +6 -3
- package/translations/en.json +6 -3
- package/translations/es.json +6 -3
- package/translations/fa.json +6 -3
- package/translations/fi.json +6 -3
- package/translations/fr.json +6 -3
- package/translations/he.json +6 -3
- package/translations/hi.json +6 -3
- package/translations/id.json +6 -3
- package/translations/it.json +6 -3
- package/translations/ja.json +6 -3
- package/translations/ko.json +6 -3
- package/translations/ms.json +6 -3
- package/translations/nl.json +6 -3
- package/translations/no.json +6 -3
- package/translations/pl.json +6 -3
- package/translations/pt.json +6 -3
- package/translations/ro.json +6 -3
- package/translations/sv.json +6 -3
- package/translations/th.json +6 -3
- package/translations/tr.json +6 -3
- package/translations/uk.json +6 -3
- package/translations/vi.json +6 -3
- package/translations/zh.json +6 -3
- package/dist/PdfAnnotationCanvas.client-ADC4FFSE.mjs.map +0 -1
- package/dist/TranslationManager-Co_5fSxl.d.mts +0 -118
- package/dist/ar-EMHEHPCJ.mjs.map +0 -1
- package/dist/bn-OVCI4F6X.mjs.map +0 -1
- package/dist/chunk-JZIO2A3B.mjs.map +0 -1
- package/dist/chunk-LIHZTECW.mjs.map +0 -1
- package/dist/cs-FAN66Q2F.mjs.map +0 -1
- package/dist/da-YBBIHI2O.mjs.map +0 -1
- package/dist/de-MAYU33LB.mjs.map +0 -1
- package/dist/el-MKGSWN4O.mjs.map +0 -1
- package/dist/es-52LHUWJD.mjs.map +0 -1
- package/dist/fa-FJICRANB.mjs.map +0 -1
- package/dist/fi-O455XFCR.mjs.map +0 -1
- package/dist/fr-TXIXHOOE.mjs.map +0 -1
- package/dist/he-JBSOX5IN.mjs.map +0 -1
- package/dist/hi-KGHI3XVT.mjs.map +0 -1
- package/dist/id-5OCPPZLO.mjs.map +0 -1
- package/dist/it-PNBBZSM2.mjs.map +0 -1
- package/dist/ja-LDD7R3TJ.mjs.map +0 -1
- package/dist/ko-F47ZDEY3.mjs.map +0 -1
- package/dist/ms-Z7LMXJWL.mjs.map +0 -1
- package/dist/nl-6SJFBPJ3.mjs.map +0 -1
- package/dist/no-YXPBPSGF.mjs.map +0 -1
- package/dist/pl-P4AZ2QME.mjs.map +0 -1
- package/dist/pt-LHWUS6U6.mjs.map +0 -1
- package/dist/ro-EA5J2ZON.mjs.map +0 -1
- package/dist/sv-DATBS3UQ.mjs.map +0 -1
- package/dist/th-WTFJRWPT.mjs.map +0 -1
- package/dist/tr-IKO3RXOX.mjs.map +0 -1
- package/dist/uk-CF6CTTRK.mjs.map +0 -1
- package/dist/vi-AJLTXPZQ.mjs.map +0 -1
- package/dist/zh-U3ORHHYH.mjs.map +0 -1
- /package/dist/{en-DDLIXJCU.mjs.map → en-KJCJQ4OO.mjs.map} +0 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bug Reproduction: Detection Progress Doesn't Dismiss
|
|
3
|
+
*
|
|
4
|
+
* USER SCENARIO:
|
|
5
|
+
* 1. User clicks "Detect References" button
|
|
6
|
+
* 2. Progress modal appears showing "Processing: Location"
|
|
7
|
+
* 3. Detection completes successfully
|
|
8
|
+
* 4. BUG: Progress modal stays visible showing "Processing: Location" indefinitely
|
|
9
|
+
*
|
|
10
|
+
* ROOT CAUSE:
|
|
11
|
+
* - useDetectionFlow.ts (line 54-62): detection:complete clears `detectingMotivation` but keeps `detectionProgress`
|
|
12
|
+
* - DetectSection.tsx (line 214): Shows progress UI whenever `detectionProgress` is not null
|
|
13
|
+
* - No mechanism to auto-dismiss or manually close the progress display
|
|
14
|
+
*
|
|
15
|
+
* FIX OPTIONS:
|
|
16
|
+
* A) Auto-dismiss after timeout (3s after completion)
|
|
17
|
+
* B) Add "Close" button to progress display
|
|
18
|
+
* C) Clear progress on next detection:start (already works but not ideal UX)
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
22
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
23
|
+
import { act } from 'react';
|
|
24
|
+
import { useDetectionFlow } from '../../../hooks/useDetectionFlow';
|
|
25
|
+
import { EventBusProvider, resetEventBusForTesting, useEventBus } from '../../../contexts/EventBusContext';
|
|
26
|
+
import { ApiClientProvider } from '../../../contexts/ApiClientContext';
|
|
27
|
+
import { AuthTokenProvider } from '../../../contexts/AuthTokenContext';
|
|
28
|
+
import { SSEClient, resourceUri } from '@semiont/api-client';
|
|
29
|
+
|
|
30
|
+
describe('Detection Progress Dismissal Bug', () => {
|
|
31
|
+
let mockStream: any;
|
|
32
|
+
const rUri = resourceUri('https://example.com/resources/test');
|
|
33
|
+
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
resetEventBusForTesting();
|
|
36
|
+
vi.clearAllMocks();
|
|
37
|
+
|
|
38
|
+
mockStream = {
|
|
39
|
+
onProgress: vi.fn().mockReturnThis(),
|
|
40
|
+
onComplete: vi.fn().mockReturnThis(),
|
|
41
|
+
onError: vi.fn().mockReturnThis(),
|
|
42
|
+
close: vi.fn(),
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
vi.spyOn(SSEClient.prototype, 'detectAnnotations').mockReturnValue(mockStream);
|
|
46
|
+
vi.spyOn(SSEClient.prototype, 'detectHighlights').mockReturnValue(mockStream);
|
|
47
|
+
vi.spyOn(SSEClient.prototype, 'detectComments').mockReturnValue(mockStream);
|
|
48
|
+
vi.spyOn(SSEClient.prototype, 'detectAssessments').mockReturnValue(mockStream);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
afterEach(() => {
|
|
52
|
+
vi.restoreAllMocks();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('FIXED: Progress auto-dismisses after detection completes', { timeout: 7000 }, async () => {
|
|
56
|
+
let eventBusInstance: any;
|
|
57
|
+
|
|
58
|
+
function TestHarness() {
|
|
59
|
+
eventBusInstance = useEventBus();
|
|
60
|
+
const { detectingMotivation, detectionProgress } = useDetectionFlow(rUri);
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<div>
|
|
64
|
+
<div data-testid="detecting">{detectingMotivation || 'none'}</div>
|
|
65
|
+
<div data-testid="progress">
|
|
66
|
+
{detectionProgress ? detectionProgress.message || 'has progress' : 'no progress'}
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
render(
|
|
73
|
+
<EventBusProvider>
|
|
74
|
+
<AuthTokenProvider token={null}>
|
|
75
|
+
<ApiClientProvider baseUrl="http://localhost:4000">
|
|
76
|
+
<TestHarness />
|
|
77
|
+
</ApiClientProvider>
|
|
78
|
+
</AuthTokenProvider>
|
|
79
|
+
</EventBusProvider>
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// Initial state
|
|
83
|
+
expect(screen.getByTestId('detecting')).toHaveTextContent('none');
|
|
84
|
+
expect(screen.getByTestId('progress')).toHaveTextContent('no progress');
|
|
85
|
+
|
|
86
|
+
// User clicks detect button (emits detection:start)
|
|
87
|
+
act(() => {
|
|
88
|
+
eventBusInstance.emit('detection:start', {
|
|
89
|
+
motivation: 'linking',
|
|
90
|
+
options: { entityTypes: ['Location'] }
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Detection started
|
|
95
|
+
await waitFor(() => {
|
|
96
|
+
expect(screen.getByTestId('detecting')).toHaveTextContent('linking');
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// SSE sends progress update
|
|
100
|
+
act(() => {
|
|
101
|
+
eventBusInstance.emit('detection:progress', {
|
|
102
|
+
status: 'scanning',
|
|
103
|
+
message: 'Processing: Location',
|
|
104
|
+
currentEntityType: 'Location',
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Progress is visible
|
|
109
|
+
await waitFor(() => {
|
|
110
|
+
expect(screen.getByTestId('progress')).toHaveTextContent('Processing: Location');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Detection completes (SSE finishes, backend emits detection:complete)
|
|
114
|
+
act(() => {
|
|
115
|
+
eventBusInstance.emit('detection:complete', { motivation: 'linking' });
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// detectingMotivation cleared immediately
|
|
119
|
+
await waitFor(() => {
|
|
120
|
+
expect(screen.getByTestId('detecting')).toHaveTextContent('none');
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// Wait 5 seconds - progress auto-dismissed after completion
|
|
124
|
+
await new Promise(resolve => setTimeout(resolve, 5100));
|
|
125
|
+
expect(screen.getByTestId('progress')).toHaveTextContent('no progress');
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('WORKAROUND: Starting new detection clears old progress', async () => {
|
|
129
|
+
let eventBusInstance: any;
|
|
130
|
+
|
|
131
|
+
function TestHarness() {
|
|
132
|
+
eventBusInstance = useEventBus();
|
|
133
|
+
const { detectionProgress } = useDetectionFlow(rUri);
|
|
134
|
+
|
|
135
|
+
return (
|
|
136
|
+
<div data-testid="progress">
|
|
137
|
+
{detectionProgress ? detectionProgress.message || 'has progress' : 'no progress'}
|
|
138
|
+
</div>
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
render(
|
|
143
|
+
<EventBusProvider>
|
|
144
|
+
<AuthTokenProvider token={null}>
|
|
145
|
+
<ApiClientProvider baseUrl="http://localhost:4000">
|
|
146
|
+
<TestHarness />
|
|
147
|
+
</ApiClientProvider>
|
|
148
|
+
</AuthTokenProvider>
|
|
149
|
+
</EventBusProvider>
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// First detection with stuck progress
|
|
153
|
+
act(() => {
|
|
154
|
+
eventBusInstance.emit('detection:start', { motivation: 'linking', options: {} });
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
act(() => {
|
|
158
|
+
eventBusInstance.emit('detection:progress', { message: 'Old progress stuck here' });
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
act(() => {
|
|
162
|
+
eventBusInstance.emit('detection:complete', { motivation: 'linking' });
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
await waitFor(() => {
|
|
166
|
+
expect(screen.getByTestId('progress')).toHaveTextContent('Old progress stuck here');
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// WORKAROUND: Start new detection clears old progress
|
|
170
|
+
act(() => {
|
|
171
|
+
eventBusInstance.emit('detection:start', { motivation: 'highlighting', options: {} });
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
await waitFor(() => {
|
|
175
|
+
expect(screen.getByTestId('progress')).toHaveTextContent('no progress');
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('NEW FEATURE: Progress should auto-dismiss after 5 seconds', { timeout: 7000 }, async () => {
|
|
180
|
+
// This test verifies the new auto-dismiss feature
|
|
181
|
+
|
|
182
|
+
let eventBusInstance: any;
|
|
183
|
+
|
|
184
|
+
function TestHarness() {
|
|
185
|
+
eventBusInstance = useEventBus();
|
|
186
|
+
const { detectionProgress } = useDetectionFlow(rUri);
|
|
187
|
+
|
|
188
|
+
return (
|
|
189
|
+
<div data-testid="progress">
|
|
190
|
+
{detectionProgress ? 'visible' : 'dismissed'}
|
|
191
|
+
</div>
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
render(
|
|
196
|
+
<EventBusProvider>
|
|
197
|
+
<AuthTokenProvider token={null}>
|
|
198
|
+
<ApiClientProvider baseUrl="http://localhost:4000">
|
|
199
|
+
<TestHarness />
|
|
200
|
+
</ApiClientProvider>
|
|
201
|
+
</AuthTokenProvider>
|
|
202
|
+
</EventBusProvider>
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
// Show progress
|
|
206
|
+
act(() => {
|
|
207
|
+
eventBusInstance.emit('detection:start', { motivation: 'linking', options: {} });
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
act(() => {
|
|
211
|
+
eventBusInstance.emit('detection:progress', {
|
|
212
|
+
status: 'complete',
|
|
213
|
+
message: 'Complete! Created 5 annotations'
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
act(() => {
|
|
218
|
+
eventBusInstance.emit('detection:complete', { motivation: 'linking' });
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// Progress visible initially
|
|
222
|
+
await waitFor(() => {
|
|
223
|
+
expect(screen.getByTestId('progress')).toHaveTextContent('visible');
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// Auto-dismiss after 5 seconds
|
|
227
|
+
await new Promise(resolve => setTimeout(resolve, 5100));
|
|
228
|
+
|
|
229
|
+
await waitFor(() => {
|
|
230
|
+
expect(screen.getByTestId('progress')).toHaveTextContent('dismissed');
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('FIXED: useEventOperations now forwards final completion chunk data', async () => {
|
|
235
|
+
/**
|
|
236
|
+
* This test verifies the fix for the useEventOperations bug.
|
|
237
|
+
*
|
|
238
|
+
* FIX: useEventOperations.ts stream.onComplete(finalChunk) now emits detection:progress
|
|
239
|
+
* with the final chunk data BEFORE emitting detection:complete.
|
|
240
|
+
*
|
|
241
|
+
* This ensures the UI can display the final completion message with status:'complete'.
|
|
242
|
+
*/
|
|
243
|
+
|
|
244
|
+
let eventBusInstance: any;
|
|
245
|
+
|
|
246
|
+
function TestHarness() {
|
|
247
|
+
eventBusInstance = useEventBus();
|
|
248
|
+
const { detectionProgress } = useDetectionFlow(rUri);
|
|
249
|
+
|
|
250
|
+
return (
|
|
251
|
+
<div>
|
|
252
|
+
<div data-testid="progress-status">{detectionProgress?.status || 'none'}</div>
|
|
253
|
+
<div data-testid="progress-message">{detectionProgress?.message || 'no message'}</div>
|
|
254
|
+
</div>
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Mock SSE stream to simulate backend behavior
|
|
259
|
+
let onProgressCallback: any;
|
|
260
|
+
let onCompleteCallback: any;
|
|
261
|
+
|
|
262
|
+
mockStream.onProgress.mockImplementation((cb: any) => {
|
|
263
|
+
onProgressCallback = cb;
|
|
264
|
+
return mockStream;
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
mockStream.onComplete.mockImplementation((cb: any) => {
|
|
268
|
+
onCompleteCallback = cb;
|
|
269
|
+
return mockStream;
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
render(
|
|
273
|
+
<EventBusProvider>
|
|
274
|
+
<AuthTokenProvider token={null}>
|
|
275
|
+
<ApiClientProvider baseUrl="http://localhost:4000">
|
|
276
|
+
<TestHarness />
|
|
277
|
+
</ApiClientProvider>
|
|
278
|
+
</AuthTokenProvider>
|
|
279
|
+
</EventBusProvider>
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
// Start detection (triggers SSE stream creation)
|
|
283
|
+
act(() => {
|
|
284
|
+
eventBusInstance.emit('detection:start', {
|
|
285
|
+
motivation: 'linking',
|
|
286
|
+
options: { entityTypes: ['Location'] }
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// Simulate SSE scanning chunk via stream.onProgress()
|
|
291
|
+
act(() => {
|
|
292
|
+
onProgressCallback?.({
|
|
293
|
+
status: 'scanning',
|
|
294
|
+
message: 'Processing: Location',
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
await waitFor(() => {
|
|
299
|
+
expect(screen.getByTestId('progress-status')).toHaveTextContent('scanning');
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// Simulate backend sending final chunk to stream.onComplete(finalChunk)
|
|
303
|
+
// useEventOperations should forward this as detection:progress
|
|
304
|
+
act(() => {
|
|
305
|
+
onCompleteCallback?.({
|
|
306
|
+
status: 'complete',
|
|
307
|
+
message: 'Complete! Found 5 entities',
|
|
308
|
+
foundCount: 5,
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
// Verify final chunk is now visible
|
|
313
|
+
await waitFor(() => {
|
|
314
|
+
expect(screen.getByTestId('progress-status')).toHaveTextContent('complete');
|
|
315
|
+
expect(screen.getByTestId('progress-message')).toHaveTextContent('Complete! Found 5 entities');
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
});
|