@semiont/react-ui 0.4.20 → 0.4.21

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.
Files changed (108) hide show
  1. package/README.md +8 -5
  2. package/dist/{PdfAnnotationCanvas.client-CHDCGQBR.mjs → PdfAnnotationCanvas.client-6ZGFEN2N.mjs} +9 -13
  3. package/dist/PdfAnnotationCanvas.client-6ZGFEN2N.mjs.map +1 -0
  4. package/dist/TranslationManager-9Xj3MIWQ.d.mts +16 -0
  5. package/dist/chunk-KEDFYI6N.mjs +7788 -0
  6. package/dist/chunk-KEDFYI6N.mjs.map +1 -0
  7. package/dist/index.d.mts +171 -1140
  8. package/dist/index.mjs +3263 -13644
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/test-utils.d.mts +46 -21
  11. package/dist/test-utils.mjs +2499 -87
  12. package/dist/test-utils.mjs.map +1 -1
  13. package/package.json +1 -2
  14. package/src/components/AnnotateReferencesProgressWidget.tsx +21 -28
  15. package/src/components/CodeMirrorRenderer.tsx +9 -11
  16. package/src/components/StatusDisplay.tsx +42 -16
  17. package/src/components/Toolbar.tsx +4 -4
  18. package/src/components/__tests__/AnnotateReferencesProgressWidget.test.tsx +34 -20
  19. package/src/components/__tests__/StatusDisplay.test.tsx +47 -64
  20. package/src/components/__tests__/Toolbar.test.tsx +4 -4
  21. package/src/components/annotation/AnnotateToolbar.tsx +8 -7
  22. package/src/components/annotation/__tests__/AnnotateToolbar.test.tsx +31 -77
  23. package/src/components/annotation-popups/__tests__/JsonLdView.test.tsx +0 -1
  24. package/src/components/image-annotation/AnnotationOverlay.tsx +12 -13
  25. package/src/components/image-annotation/SvgDrawingCanvas.tsx +7 -7
  26. package/src/components/modals/PermissionDeniedModal.tsx +11 -11
  27. package/src/components/modals/ReferenceWizardModal.tsx +14 -18
  28. package/src/components/modals/ResourceSearchModal.tsx +10 -6
  29. package/src/components/modals/SearchModal.tsx +10 -6
  30. package/src/components/modals/SessionExpiredModal.tsx +11 -11
  31. package/src/components/modals/__tests__/PermissionDeniedModal.test.tsx +7 -7
  32. package/src/components/modals/__tests__/ResourceSearchModal.test.tsx +10 -8
  33. package/src/components/modals/__tests__/SearchModal.search-wiring.test.tsx +10 -7
  34. package/src/components/modals/__tests__/SessionExpiredModal.test.tsx +5 -5
  35. package/src/components/navigation/CollapsibleResourceNavigation.tsx +10 -10
  36. package/src/components/navigation/ObservableLink.tsx +6 -6
  37. package/src/components/navigation/SimpleNavigation.tsx +4 -4
  38. package/src/components/navigation/__tests__/ObservableLink.test.tsx +4 -4
  39. package/src/components/navigation/__tests__/SimpleNavigation.test.tsx +4 -4
  40. package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +9 -11
  41. package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +0 -1
  42. package/src/components/resource/AnnotateView.tsx +7 -6
  43. package/src/components/resource/AnnotationHistory.tsx +9 -12
  44. package/src/components/resource/BrowseView.tsx +8 -7
  45. package/src/components/resource/ResourceViewer.tsx +17 -25
  46. package/src/components/resource/__tests__/AnnotationHistory.test.tsx +54 -192
  47. package/src/components/resource/__tests__/BrowseView.test.tsx +34 -83
  48. package/src/components/resource/__tests__/ResourceViewer.mode-switch.test.tsx +40 -31
  49. package/src/components/resource/panels/AssessmentEntry.tsx +5 -4
  50. package/src/components/resource/panels/AssessmentPanel.tsx +19 -15
  51. package/src/components/resource/panels/AssistSection.tsx +11 -13
  52. package/src/components/resource/panels/CollaborationPanel.tsx +29 -7
  53. package/src/components/resource/panels/CommentEntry.tsx +5 -4
  54. package/src/components/resource/panels/CommentsPanel.tsx +9 -11
  55. package/src/components/resource/panels/HighlightEntry.tsx +5 -4
  56. package/src/components/resource/panels/HighlightPanel.tsx +10 -11
  57. package/src/components/resource/panels/ReferenceEntry.tsx +8 -8
  58. package/src/components/resource/panels/ReferencesPanel.tsx +13 -12
  59. package/src/components/resource/panels/ResourceInfoPanel.tsx +7 -6
  60. package/src/components/resource/panels/TagEntry.tsx +5 -4
  61. package/src/components/resource/panels/TaggingPanel.tsx +10 -16
  62. package/src/components/resource/panels/UnifiedAnnotationsPanel.tsx +3 -2
  63. package/src/components/resource/panels/__tests__/AssessmentPanel.test.tsx +18 -52
  64. package/src/components/resource/panels/__tests__/CollaborationPanel.test.tsx +51 -20
  65. package/src/components/resource/panels/__tests__/CommentsPanel.test.tsx +18 -56
  66. package/src/components/resource/panels/__tests__/HighlightPanel.annotationProgress.test.tsx +0 -1
  67. package/src/components/resource/panels/__tests__/ReferenceEntry.test.tsx +4 -5
  68. package/src/components/resource/panels/__tests__/ReferencesPanel.observable-flow.test.tsx +153 -0
  69. package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +51 -106
  70. package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +15 -47
  71. package/src/components/resource/panels/__tests__/TaggingPanel.test.tsx +15 -47
  72. package/src/components/settings/SettingsPanel.tsx +8 -8
  73. package/src/components/settings/__tests__/SettingsPanel.test.tsx +12 -12
  74. package/src/features/admin-devops/components/AdminDevOpsPage.tsx +1 -1
  75. package/src/features/admin-exchange/components/AdminExchangePage.tsx +1 -1
  76. package/src/features/admin-exchange/components/ImportCard.tsx +2 -6
  77. package/src/features/admin-security/components/AdminSecurityPage.tsx +1 -1
  78. package/src/features/admin-users/components/AdminUsersPage.tsx +1 -1
  79. package/src/features/moderate-entity-tags/components/EntityTagsPage.tsx +1 -1
  80. package/src/features/moderate-recent/components/RecentDocumentsPage.tsx +1 -1
  81. package/src/features/moderate-tag-schemas/components/TagSchemasPage.tsx +1 -1
  82. package/src/features/moderation-linked-data/components/LinkedDataPage.tsx +1 -1
  83. package/src/features/resource-compose/__tests__/ResourceComposePage.test.tsx +5 -3
  84. package/src/features/resource-compose/components/ResourceComposePage.tsx +5 -22
  85. package/src/features/resource-discovery/__tests__/ResourceDiscoveryPage.test.tsx +4 -3
  86. package/src/features/resource-discovery/components/ResourceDiscoveryPage.tsx +1 -1
  87. package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +38 -45
  88. package/src/features/resource-viewer/components/ResourceViewerPage.tsx +123 -192
  89. package/dist/KnowledgeBaseSessionContext-BNNunwzO.d.mts +0 -175
  90. package/dist/PdfAnnotationCanvas.client-CHDCGQBR.mjs.map +0 -1
  91. package/dist/chunk-OZICDVH7.mjs +0 -62
  92. package/dist/chunk-OZICDVH7.mjs.map +0 -1
  93. package/dist/chunk-R4CCMFJH.mjs +0 -877
  94. package/dist/chunk-R4CCMFJH.mjs.map +0 -1
  95. package/dist/chunk-VN5NY4SN.mjs +0 -200
  96. package/dist/chunk-VN5NY4SN.mjs.map +0 -1
  97. package/src/components/modals/ProposeEntitiesModal.tsx +0 -179
  98. package/src/components/modals/__tests__/ProposeEntitiesModal.test.tsx +0 -129
  99. package/src/features/resource-viewer/__tests__/AnnotationCreationPending.test.tsx +0 -323
  100. package/src/features/resource-viewer/__tests__/AnnotationDeletionIntegration.test.tsx +0 -245
  101. package/src/features/resource-viewer/__tests__/AnnotationProgressDismissal.test.tsx +0 -303
  102. package/src/features/resource-viewer/__tests__/BindFlowIntegration.test.tsx +0 -150
  103. package/src/features/resource-viewer/__tests__/DetectionFlowBug.test.tsx +0 -243
  104. package/src/features/resource-viewer/__tests__/DetectionFlowIntegration.test.tsx +0 -383
  105. package/src/features/resource-viewer/__tests__/ResourceMutations.test.tsx +0 -299
  106. package/src/features/resource-viewer/__tests__/ToastNotifications.test.tsx +0 -186
  107. package/src/features/resource-viewer/__tests__/YieldFlowIntegration.test.tsx +0 -429
  108. package/src/features/resource-viewer/__tests__/annotation-progress-flow.test.tsx +0 -348
@@ -1,348 +0,0 @@
1
- /**
2
- * Layer 3 Integration Test: Detection Progress Flow UI/UX
3
- *
4
- * Tests the complete data flow from UI → EventBus → useBindFlow → SSE (mocked)
5
- *
6
- * This test uses COMPOSITION instead of mocking:
7
- * - Real React components composed together (useMarkFlow + HighlightPanel + AssistSection)
8
- * - Real EventBus (mitt) passed via context
9
- * - Real useBindFlow hook with mock API client passed as prop
10
- * - Mock SSE stream (simulated API responses) provided via composition
11
- *
12
- * This test focuses on USER EXPERIENCE:
13
- * - Verifies user clicks "Detect" button and sees progress
14
- * - Tests progress messages appear and update correctly
15
- * - Validates final message stays visible after completion
16
- * - Ensures progress clears on error
17
- *
18
- * COMPLEMENTARY TEST: See DetectionFlowIntegration.test.tsx for architecture testing
19
- * - That test verifies SYSTEM ARCHITECTURE (event wiring, API call count)
20
- * - This test verifies USER EXPERIENCE (button clicks, UI feedback)
21
- *
22
- * UPDATED: Now tests useMarkFlow hook instead of DetectionFlowContainer
23
- */
24
-
25
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
26
- import { render, screen, waitFor } from '@testing-library/react';
27
- import userEvent from '@testing-library/user-event';
28
- import { act } from 'react';
29
- import { HighlightPanel } from '../../../components/resource/panels/HighlightPanel';
30
- import { useMarkFlow } from '../../../hooks/useMarkFlow';
31
- import { EventBusProvider, useEventBus } from '../../../contexts/EventBusContext';
32
- import { ApiClientProvider } from '../../../contexts/ApiClientContext';
33
- import { AuthTokenProvider } from '../../../contexts/AuthTokenContext';
34
- import { SemiontApiClient } from '@semiont/api-client';
35
- import type { components } from '@semiont/core';
36
-
37
- // Mock Toast module to prevent "useToast must be used within a ToastProvider" errors
38
- vi.mock('../../../components/Toast', () => ({
39
- useToast: () => ({
40
- showSuccess: vi.fn(),
41
- showError: vi.fn(),
42
- showInfo: vi.fn(),
43
- showWarning: vi.fn(),
44
- }),
45
- }));
46
-
47
- type Annotation = components['schemas']['Annotation'];
48
-
49
- // Mock translations
50
- const mockT = vi.fn((key: string) => {
51
- const translations: Record<string, string> = {
52
- title: 'Highlights',
53
- noHighlights: 'No highlights yet',
54
- annotateHighlights: 'Annotate Highlights',
55
- instructions: 'Instructions',
56
- optional: '(optional)',
57
- instructionsPlaceholder: 'Enter custom instructions...',
58
- densityLabel: 'Density',
59
- densitySparse: 'Sparse',
60
- densityDense: 'Dense',
61
- annotate: 'Annotate',
62
- annotating: 'Annotating...',
63
- };
64
- return translations[key] || key;
65
- });
66
-
67
- vi.mock('../../../contexts/TranslationContext', () => ({
68
- useTranslations: () => mockT,
69
- TranslationProvider: ({ children }: { children: React.ReactNode }) => children,
70
- }));
71
-
72
- // Create a mock SSE stream that we can control
73
- class MockSSEStream {
74
- private eventBus: any = null;
75
-
76
- setEventBus(eventBus: any) {
77
- this.eventBus = eventBus;
78
- }
79
-
80
- close() {
81
- // Mock close method
82
- }
83
-
84
- // Test helper methods that emit to EventBus
85
- emitProgress(chunk: any) {
86
- this.eventBus.get('mark:progress').next(chunk);
87
- }
88
-
89
- emitComplete(finalChunk?: any, motivation: string = 'highlighting') {
90
- if (finalChunk) {
91
- this.eventBus.get('mark:progress').next(finalChunk);
92
- }
93
- this.eventBus.get('mark:assist-finished').next({ motivation });
94
- }
95
-
96
- emitError(error: Error) {
97
- this.eventBus.get('mark:assist-failed').next({
98
- type: 'job.failed' as const,
99
- resourceId: 'test' as any,
100
- userId: 'user' as any,
101
- id: 'evt-1' as any,
102
- timestamp: new Date().toISOString(),
103
- version: 1,
104
- payload: {
105
- jobId: 'job-1' as any,
106
- jobType: 'detection',
107
- error: error.message,
108
- },
109
- });
110
- }
111
- }
112
-
113
- // Composition: Test component that wires together the pieces we're testing
114
- function DetectionFlowTestHarness({
115
- rUri,
116
- annotations,
117
- }: {
118
- rUri: string;
119
- annotations: Annotation[];
120
- }) {
121
- const { assistingMotivation, progress } = useMarkFlow(rUri as any);
122
-
123
- return (
124
- <HighlightPanel
125
- annotations={annotations}
126
- pendingAnnotation={null}
127
- hoveredAnnotationId={null}
128
- isAssisting={assistingMotivation === 'highlighting'}
129
- progress={progress}
130
- annotateMode={true}
131
- />
132
- );
133
- }
134
-
135
- describe('Detection Progress Flow Integration (Layer 3)', () => {
136
- let mockAnnotations: Annotation[];
137
- let mockStream: MockSSEStream;
138
- const rUri = 'https://example.com/resources/test-resource-1';
139
-
140
- // Helper component that captures the EventBus and wires it into mockStream
141
- function EventBusCapturer() {
142
- const eventBus = useEventBus();
143
- mockStream.setEventBus(eventBus);
144
- return null;
145
- }
146
-
147
- // Helper to render test harness with composition
148
- const renderDetectionFlow = () => {
149
- return render(
150
- <EventBusProvider>
151
- <EventBusCapturer />
152
- <AuthTokenProvider token={null}>
153
- <ApiClientProvider baseUrl="http://localhost:4000">
154
- <DetectionFlowTestHarness
155
- rUri={rUri}
156
- annotations={mockAnnotations}
157
- />
158
- </ApiClientProvider>
159
- </AuthTokenProvider>
160
- </EventBusProvider>
161
- );
162
- };
163
-
164
- beforeEach(() => {
165
- vi.clearAllMocks();
166
-
167
- // Create fresh stream for each test
168
- mockStream = new MockSSEStream();
169
-
170
- // Spy on SemiontApiClient prototype HTTP methods (namespace methods call these)
171
- vi.spyOn(SemiontApiClient.prototype, 'annotateHighlights').mockResolvedValue({ correlationId: 'c1', jobId: 'j1' });
172
- vi.spyOn(SemiontApiClient.prototype, 'annotateAssessments').mockResolvedValue({ correlationId: 'c1', jobId: 'j1' });
173
- vi.spyOn(SemiontApiClient.prototype, 'annotateComments').mockResolvedValue({ correlationId: 'c1', jobId: 'j1' });
174
- vi.spyOn(SemiontApiClient.prototype, 'annotateReferences').mockResolvedValue({ correlationId: 'c1', jobId: 'j1' });
175
-
176
- mockAnnotations = [];
177
- });
178
-
179
- afterEach(() => {
180
- vi.restoreAllMocks();
181
- });
182
-
183
- it('should display detection progress from button click to completion', async () => {
184
- const user = userEvent.setup();
185
-
186
- // Render composed components with real EventBus and mock API client
187
- renderDetectionFlow();
188
-
189
- // Initial state: no progress visible
190
- expect(screen.queryByText(/Analyzing/)).not.toBeInTheDocument();
191
-
192
- // Click annotate button
193
- const annotateButton = screen.getByRole('button', { name: /✨\s*Annotate/ });
194
- await user.click(annotateButton);
195
-
196
- // Simulate SSE progress chunk #1: Starting
197
- act(() => {
198
- mockStream.emitProgress({
199
- status: 'started',
200
- percentage: 0,
201
- message: 'Starting detection...',
202
- });
203
- });
204
-
205
- // Verify progress message appears
206
- await waitFor(() => {
207
- expect(screen.getByText('Starting detection...')).toBeInTheDocument();
208
- });
209
-
210
- // Simulate SSE progress chunk #2: Analyzing
211
- act(() => {
212
- mockStream.emitProgress({
213
- status: 'analyzing',
214
- percentage: 30,
215
- message: 'Analyzing text...',
216
- });
217
- });
218
-
219
- await waitFor(() => {
220
- expect(screen.getByText('Analyzing text...')).toBeInTheDocument();
221
- });
222
-
223
- // Simulate SSE progress chunk #3: Creating annotations
224
- act(() => {
225
- mockStream.emitProgress({
226
- status: 'creating',
227
- percentage: 60,
228
- message: 'Creating 14 annotations...',
229
- });
230
- });
231
-
232
- await waitFor(() => {
233
- expect(screen.getByText('Creating 14 annotations...')).toBeInTheDocument();
234
- });
235
-
236
- // Simulate stream completion with final chunk (onComplete receives the final progress)
237
- act(() => {
238
- mockStream.emitComplete({
239
- status: 'complete',
240
- percentage: 100,
241
- message: 'Complete! Created 14 highlights',
242
- });
243
- });
244
-
245
- // CRITICAL TEST: Final message should still be visible after completion
246
- await waitFor(() => {
247
- expect(screen.getByText('Complete! Created 14 highlights')).toBeInTheDocument();
248
- });
249
- });
250
-
251
- it('should handle out-of-order SSE events (complete before final progress)', async () => {
252
- const user = userEvent.setup();
253
-
254
- renderDetectionFlow();
255
-
256
- // Click annotate button
257
- const annotateButton = screen.getByRole('button', { name: /✨\s*Annotate/ });
258
- await user.click(annotateButton);
259
-
260
- // Simulate initial progress
261
- act(() => {
262
- mockStream.emitProgress({
263
- status: 'analyzing',
264
- message: 'Analyzing...',
265
- });
266
- });
267
-
268
- await waitFor(() => {
269
- expect(screen.getByText('Analyzing...')).toBeInTheDocument();
270
- });
271
-
272
- // Simulate race condition: complete arrives BEFORE final progress
273
- act(() => {
274
- mockStream.emitComplete();
275
- });
276
-
277
- // Then final progress chunk arrives
278
- act(() => {
279
- mockStream.emitProgress({
280
- status: 'complete',
281
- percentage: 100,
282
- message: 'Complete! Created 5 highlights',
283
- });
284
- });
285
-
286
- // Final message should still be visible
287
- await waitFor(() => {
288
- expect(screen.getByText('Complete! Created 5 highlights')).toBeInTheDocument();
289
- });
290
- });
291
-
292
- it('should show progress with request parameters', async () => {
293
- const user = userEvent.setup();
294
-
295
- renderDetectionFlow();
296
-
297
- const annotateButton = screen.getByRole('button', { name: /✨\s*Annotate/ });
298
- await user.click(annotateButton);
299
-
300
- // Simulate progress with request parameters
301
- act(() => {
302
- mockStream.emitProgress({
303
- status: 'analyzing',
304
- message: 'Analyzing with custom instructions...',
305
- requestParams: [
306
- { label: 'Instructions', value: 'Find important points' },
307
- { label: 'Density', value: '5' },
308
- ],
309
- });
310
- });
311
-
312
- await waitFor(() => {
313
- expect(screen.getByText('Find important points')).toBeInTheDocument();
314
- expect(screen.getByText('5')).toBeInTheDocument();
315
- });
316
- });
317
-
318
- it('should clear progress on mark:assist-failed', async () => {
319
- const user = userEvent.setup();
320
-
321
- renderDetectionFlow();
322
-
323
- const annotateButton = screen.getByRole('button', { name: /✨\s*Annotate/ });
324
- await user.click(annotateButton);
325
-
326
- // Show progress
327
- act(() => {
328
- mockStream.emitProgress({
329
- status: 'analyzing',
330
- message: 'Analyzing...',
331
- });
332
- });
333
-
334
- await waitFor(() => {
335
- expect(screen.getByText('Analyzing...')).toBeInTheDocument();
336
- });
337
-
338
- // Simulate error
339
- act(() => {
340
- mockStream.emitError(new Error('Network timeout'));
341
- });
342
-
343
- // Progress should be cleared
344
- await waitFor(() => {
345
- expect(screen.queryByText('Analyzing...')).not.toBeInTheDocument();
346
- });
347
- });
348
- });