@semiont/react-ui 0.4.20 → 0.4.22
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 +8 -5
- package/dist/{PdfAnnotationCanvas.client-CHDCGQBR.mjs → PdfAnnotationCanvas.client-5QESNO5H.mjs} +13 -16
- package/dist/PdfAnnotationCanvas.client-5QESNO5H.mjs.map +1 -0
- package/dist/TranslationManager-9Xj3MIWQ.d.mts +16 -0
- package/dist/chunk-4NOUO3W6.mjs +7788 -0
- package/dist/chunk-4NOUO3W6.mjs.map +1 -0
- package/dist/index.d.mts +212 -1206
- package/dist/index.mjs +3332 -13712
- package/dist/index.mjs.map +1 -1
- package/dist/test-utils.d.mts +48 -21
- package/dist/test-utils.mjs +2505 -87
- package/dist/test-utils.mjs.map +1 -1
- package/package.json +2 -2
- package/src/components/AnnotateReferencesProgressWidget.tsx +21 -28
- package/src/components/CodeMirrorRenderer.tsx +12 -12
- package/src/components/LiveRegion.tsx +1 -2
- package/src/components/StatusDisplay.tsx +42 -16
- package/src/components/Toolbar.tsx +4 -4
- package/src/components/__tests__/AnnotateReferencesProgressWidget.test.tsx +34 -20
- package/src/components/__tests__/StatusDisplay.test.tsx +50 -65
- package/src/components/__tests__/Toolbar.test.tsx +4 -4
- package/src/components/annotation/AnnotateToolbar.tsx +8 -9
- package/src/components/annotation/__tests__/AnnotateToolbar.test.tsx +31 -77
- package/src/components/annotation-popups/JsonLdView.tsx +1 -2
- package/src/components/annotation-popups/__tests__/JsonLdView.test.tsx +1 -2
- package/src/components/image-annotation/AnnotationOverlay.tsx +15 -18
- package/src/components/image-annotation/SvgDrawingCanvas.tsx +12 -17
- package/src/components/modals/ConfigureGenerationStep.tsx +1 -2
- package/src/components/modals/PermissionDeniedModal.tsx +11 -11
- package/src/components/modals/ReferenceWizardModal.tsx +14 -18
- package/src/components/modals/ResourceSearchModal.tsx +12 -8
- package/src/components/modals/SearchModal.tsx +11 -6
- package/src/components/modals/SearchResultsStep.tsx +1 -3
- package/src/components/modals/SessionExpiredModal.tsx +11 -11
- package/src/components/modals/__tests__/PermissionDeniedModal.test.tsx +7 -7
- package/src/components/modals/__tests__/ResourceSearchModal.test.tsx +10 -8
- package/src/components/modals/__tests__/SearchModal.accessibility.test.tsx +6 -2
- package/src/components/modals/__tests__/SearchModal.basic.test.tsx +6 -2
- package/src/components/modals/__tests__/SearchModal.keyboard.test.tsx +6 -2
- package/src/components/modals/__tests__/SearchModal.search-wiring.test.tsx +10 -7
- package/src/components/modals/__tests__/SearchModal.visual.test.tsx +6 -2
- package/src/components/modals/__tests__/SessionExpiredModal.test.tsx +5 -5
- package/src/components/navigation/CollapsibleResourceNavigation.tsx +10 -10
- package/src/components/navigation/ObservableLink.tsx +6 -6
- package/src/components/navigation/SimpleNavigation.tsx +4 -4
- package/src/components/navigation/__tests__/ObservableLink.test.tsx +4 -4
- package/src/components/navigation/__tests__/SimpleNavigation.test.tsx +4 -4
- package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +15 -18
- package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +1 -2
- package/src/components/resource/AnnotateView.tsx +8 -10
- package/src/components/resource/AnnotationHistory.tsx +9 -12
- package/src/components/resource/BrowseView.tsx +11 -8
- package/src/components/resource/ResourceViewer.tsx +22 -34
- package/src/components/resource/__tests__/AnnotationHistory.test.tsx +54 -192
- package/src/components/resource/__tests__/BrowseView.test.tsx +38 -87
- package/src/components/resource/__tests__/ResourceViewer.mode-switch.test.tsx +41 -31
- package/src/components/resource/__tests__/event-formatting.test.ts +6 -2
- package/src/components/resource/event-formatting.ts +2 -3
- package/src/components/resource/panels/AssessmentEntry.tsx +7 -8
- package/src/components/resource/panels/AssessmentPanel.tsx +21 -17
- package/src/components/resource/panels/AssistSection.tsx +15 -21
- package/src/components/resource/panels/CollaborationPanel.tsx +29 -7
- package/src/components/resource/panels/CommentEntry.tsx +7 -8
- package/src/components/resource/panels/CommentsPanel.tsx +11 -13
- package/src/components/resource/panels/HighlightEntry.tsx +7 -8
- package/src/components/resource/panels/HighlightPanel.tsx +12 -13
- package/src/components/resource/panels/ReferenceEntry.tsx +13 -15
- package/src/components/resource/panels/ReferencesPanel.tsx +17 -19
- package/src/components/resource/panels/ResourceInfoPanel.tsx +8 -7
- package/src/components/resource/panels/StatisticsPanel.tsx +2 -3
- package/src/components/resource/panels/TagEntry.tsx +7 -8
- package/src/components/resource/panels/TaggingPanel.tsx +14 -23
- package/src/components/resource/panels/UnifiedAnnotationsPanel.tsx +4 -3
- package/src/components/resource/panels/__tests__/AssessmentEntry.test.tsx +4 -4
- package/src/components/resource/panels/__tests__/AssessmentPanel.test.tsx +22 -57
- package/src/components/resource/panels/__tests__/CollaborationPanel.test.tsx +51 -20
- package/src/components/resource/panels/__tests__/CommentEntry.test.tsx +4 -4
- package/src/components/resource/panels/__tests__/CommentsPanel.test.tsx +22 -61
- package/src/components/resource/panels/__tests__/HighlightEntry.test.tsx +4 -4
- package/src/components/resource/panels/__tests__/HighlightPanel.annotationProgress.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/ReferenceEntry.test.tsx +7 -8
- package/src/components/resource/panels/__tests__/ReferencesPanel.observable-flow.test.tsx +153 -0
- package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +51 -106
- package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +28 -53
- package/src/components/resource/panels/__tests__/StatisticsPanel.test.tsx +3 -3
- package/src/components/resource/panels/__tests__/TagEntry.test.tsx +4 -4
- package/src/components/resource/panels/__tests__/TaggingPanel.test.tsx +19 -52
- package/src/components/settings/SettingsPanel.tsx +9 -9
- package/src/components/settings/__tests__/SettingsPanel.test.tsx +15 -15
- package/src/features/admin-devops/components/AdminDevOpsPage.tsx +1 -2
- package/src/features/admin-exchange/components/AdminExchangePage.tsx +1 -1
- package/src/features/admin-exchange/components/ImportCard.tsx +2 -7
- package/src/features/admin-security/components/AdminSecurityPage.tsx +1 -2
- package/src/features/admin-users/components/AdminUsersPage.tsx +1 -1
- package/src/features/moderate-entity-tags/components/EntityTagsPage.tsx +1 -2
- package/src/features/moderate-recent/components/RecentDocumentsPage.tsx +1 -2
- package/src/features/moderate-tag-schemas/components/TagSchemasPage.tsx +1 -1
- package/src/features/moderation-linked-data/components/LinkedDataPage.tsx +1 -1
- package/src/features/resource-compose/__tests__/ResourceComposePage.test.tsx +5 -3
- package/src/features/resource-compose/components/ResourceComposePage.tsx +6 -22
- package/src/features/resource-discovery/__tests__/ResourceDiscoveryPage.test.tsx +4 -3
- package/src/features/resource-discovery/components/ResourceCard.tsx +1 -2
- package/src/features/resource-discovery/components/ResourceDiscoveryPage.tsx +3 -4
- package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +37 -45
- package/src/features/resource-viewer/components/ResourceViewerPage.tsx +129 -197
- package/dist/KnowledgeBaseSessionContext-BNNunwzO.d.mts +0 -175
- package/dist/PdfAnnotationCanvas.client-CHDCGQBR.mjs.map +0 -1
- package/dist/chunk-OZICDVH7.mjs +0 -62
- package/dist/chunk-OZICDVH7.mjs.map +0 -1
- package/dist/chunk-R4CCMFJH.mjs +0 -877
- package/dist/chunk-R4CCMFJH.mjs.map +0 -1
- package/dist/chunk-VN5NY4SN.mjs +0 -200
- package/dist/chunk-VN5NY4SN.mjs.map +0 -1
- package/src/components/modals/ProposeEntitiesModal.tsx +0 -179
- package/src/components/modals/__tests__/ProposeEntitiesModal.test.tsx +0 -129
- package/src/features/resource-viewer/__tests__/AnnotationCreationPending.test.tsx +0 -323
- package/src/features/resource-viewer/__tests__/AnnotationDeletionIntegration.test.tsx +0 -245
- package/src/features/resource-viewer/__tests__/AnnotationProgressDismissal.test.tsx +0 -303
- package/src/features/resource-viewer/__tests__/BindFlowIntegration.test.tsx +0 -150
- package/src/features/resource-viewer/__tests__/DetectionFlowBug.test.tsx +0 -243
- package/src/features/resource-viewer/__tests__/DetectionFlowIntegration.test.tsx +0 -383
- package/src/features/resource-viewer/__tests__/ResourceMutations.test.tsx +0 -299
- package/src/features/resource-viewer/__tests__/ToastNotifications.test.tsx +0 -186
- package/src/features/resource-viewer/__tests__/YieldFlowIntegration.test.tsx +0 -429
- package/src/features/resource-viewer/__tests__/annotation-progress-flow.test.tsx +0 -348
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@semiont/react-ui",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.22",
|
|
4
4
|
"description": "React components and hooks for Semiont",
|
|
5
5
|
"main": "./dist/index.mjs",
|
|
6
6
|
"types": "./dist/index.d.mts",
|
|
@@ -73,7 +73,6 @@
|
|
|
73
73
|
"test:split:coverage": "npm run test:coverage"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
|
-
"@tanstack/react-query": "^5.0.0",
|
|
77
76
|
"react": "^18.0.0 || ^19.0.0",
|
|
78
77
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
79
78
|
},
|
|
@@ -105,6 +104,7 @@
|
|
|
105
104
|
"dependencies": {
|
|
106
105
|
"@semiont/api-client": "*",
|
|
107
106
|
"@semiont/core": "*",
|
|
107
|
+
"@semiont/sdk": "*",
|
|
108
108
|
"react-error-boundary": "^4.1.2"
|
|
109
109
|
}
|
|
110
110
|
}
|
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useTranslations } from '../contexts/TranslationContext';
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
4
|
+
import { useSemiont } from '../session/SemiontProvider';
|
|
5
|
+
import { useObservable } from '../hooks/useObservable';
|
|
6
6
|
import type { components } from '@semiont/core';
|
|
7
7
|
|
|
8
8
|
type Motivation = components['schemas']['Motivation'];
|
|
9
|
-
|
|
10
|
-
// Extended MarkProgress with optional request parameters
|
|
11
|
-
interface EnrichedMarkProgress extends MarkProgress {
|
|
12
|
-
requestParams?: Array<{ label: string; value: string }>;
|
|
13
|
-
}
|
|
9
|
+
type JobProgress = components['schemas']['JobProgress'];
|
|
14
10
|
|
|
15
11
|
interface AnnotateReferencesProgressWidgetProps {
|
|
16
|
-
progress:
|
|
12
|
+
progress: JobProgress | null;
|
|
17
13
|
annotationType?: Motivation | 'reference';
|
|
18
14
|
}
|
|
19
15
|
|
|
@@ -24,11 +20,11 @@ interface AnnotateReferencesProgressWidgetProps {
|
|
|
24
20
|
*/
|
|
25
21
|
export function AnnotateReferencesProgressWidget({ progress, annotationType = 'reference' }: AnnotateReferencesProgressWidgetProps) {
|
|
26
22
|
const t = useTranslations('ReferencesPanel');
|
|
27
|
-
const
|
|
23
|
+
const session = useObservable(useSemiont().activeSession$);
|
|
28
24
|
|
|
29
25
|
const handleCancel = () => {
|
|
30
26
|
// Emit event for job cancellation
|
|
31
|
-
|
|
27
|
+
session?.client.job.cancelRequest('annotation');
|
|
32
28
|
};
|
|
33
29
|
|
|
34
30
|
if (!progress) return null;
|
|
@@ -36,7 +32,7 @@ export function AnnotateReferencesProgressWidget({ progress, annotationType = 'r
|
|
|
36
32
|
return (
|
|
37
33
|
<div
|
|
38
34
|
className="semiont-annotation-progress"
|
|
39
|
-
data-status={progress.
|
|
35
|
+
data-status={progress.stage}
|
|
40
36
|
data-type={annotationType}
|
|
41
37
|
>
|
|
42
38
|
{/* Header with pulsing sparkle */}
|
|
@@ -45,7 +41,7 @@ export function AnnotateReferencesProgressWidget({ progress, annotationType = 'r
|
|
|
45
41
|
<span className="semiont-annotation-sparkle">✨</span>
|
|
46
42
|
{t('annotationProgressTitle')}
|
|
47
43
|
</h3>
|
|
48
|
-
{progress.
|
|
44
|
+
{progress.stage !== 'complete' && (
|
|
49
45
|
<button
|
|
50
46
|
onClick={handleCancel}
|
|
51
47
|
className="semiont-annotation-cancel"
|
|
@@ -57,19 +53,16 @@ export function AnnotateReferencesProgressWidget({ progress, annotationType = 'r
|
|
|
57
53
|
</div>
|
|
58
54
|
|
|
59
55
|
{/* Request Parameters */}
|
|
60
|
-
{
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
<div className="semiont-annotation-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
</div>
|
|
71
|
-
);
|
|
72
|
-
})()}
|
|
56
|
+
{progress.requestParams && progress.requestParams.length > 0 && (
|
|
57
|
+
<div className="semiont-annotation-progress__params">
|
|
58
|
+
<div className="semiont-annotation-progress__params-title">Request Parameters:</div>
|
|
59
|
+
{progress.requestParams.map((param, idx) => (
|
|
60
|
+
<div key={idx} className="semiont-annotation-progress__param">
|
|
61
|
+
<span className="semiont-annotation-progress__param-label">{param.label}:</span> {param.value}
|
|
62
|
+
</div>
|
|
63
|
+
))}
|
|
64
|
+
</div>
|
|
65
|
+
)}
|
|
73
66
|
|
|
74
67
|
{/* Completed entity types log */}
|
|
75
68
|
{progress.completedEntityTypes && progress.completedEntityTypes.length > 0 && (
|
|
@@ -86,12 +79,12 @@ export function AnnotateReferencesProgressWidget({ progress, annotationType = 'r
|
|
|
86
79
|
|
|
87
80
|
{/* Status display with pulsing animation */}
|
|
88
81
|
<div className="semiont-annotation-progress__status">
|
|
89
|
-
{progress.
|
|
82
|
+
{progress.stage === 'complete' ? (
|
|
90
83
|
<div className="semiont-annotation-progress__message">
|
|
91
84
|
<span className="semiont-annotation-progress__icon">✅</span>
|
|
92
85
|
<span>{t('complete')}</span>
|
|
93
86
|
</div>
|
|
94
|
-
) : progress.
|
|
87
|
+
) : progress.stage === 'error' ? (
|
|
95
88
|
<div className="semiont-annotation-progress__message">
|
|
96
89
|
<span className="semiont-annotation-progress__icon">❌</span>
|
|
97
90
|
<span>{progress.message || t('failed')}</span>
|
|
@@ -102,7 +95,7 @@ export function AnnotateReferencesProgressWidget({ progress, annotationType = 'r
|
|
|
102
95
|
<span>{progress.message || (progress.currentEntityType ? t('current', { entityType: progress.currentEntityType }) : t('annotating'))}</span>
|
|
103
96
|
</div>
|
|
104
97
|
)}
|
|
105
|
-
{progress.currentEntityType && progress.
|
|
98
|
+
{progress.currentEntityType && progress.stage !== 'complete' && progress.stage !== 'error' && (
|
|
106
99
|
<div className="semiont-annotation-progress__details">
|
|
107
100
|
Processing: {progress.currentEntityType}
|
|
108
101
|
</div>
|
|
@@ -6,9 +6,9 @@ import { EditorState, RangeSetBuilder, StateField, StateEffect, Compartment } fr
|
|
|
6
6
|
import { markdown } from '@codemirror/lang-markdown';
|
|
7
7
|
import { ReferenceResolutionWidget, showWidgetPreview, hideWidgetPreview } from '../lib/codemirror-widgets';
|
|
8
8
|
import { scrollAnnotationIntoView } from '../lib/scroll-utils';
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
11
|
-
import { createHoverHandlers } from '
|
|
9
|
+
import { annotationId as toAnnotationId } from '@semiont/core';
|
|
10
|
+
import { isReference } from '@semiont/core';
|
|
11
|
+
import { createHoverHandlers, type SemiontSession } from '@semiont/sdk';
|
|
12
12
|
import {
|
|
13
13
|
convertSegmentPositions,
|
|
14
14
|
computeAnnotationDecorations,
|
|
@@ -43,7 +43,7 @@ interface Props {
|
|
|
43
43
|
sourceView?: boolean; // If true, show raw source (no markdown rendering)
|
|
44
44
|
showLineNumbers?: boolean; // If true, show line numbers
|
|
45
45
|
enableWidgets?: boolean; // If true, show inline widgets (reference previews, entity badges)
|
|
46
|
-
|
|
46
|
+
session?: SemiontSession | null | undefined;
|
|
47
47
|
getTargetResourceName?: (resourceId: string) => string | undefined;
|
|
48
48
|
generatingReferenceId?: string | null; // ID of reference currently generating a document
|
|
49
49
|
hoverDelayMs: number; // Hover delay in milliseconds for accessibility
|
|
@@ -179,7 +179,7 @@ export function CodeMirrorRenderer({
|
|
|
179
179
|
sourceView = false,
|
|
180
180
|
showLineNumbers = false,
|
|
181
181
|
enableWidgets = false,
|
|
182
|
-
|
|
182
|
+
session,
|
|
183
183
|
getTargetResourceName,
|
|
184
184
|
generatingReferenceId,
|
|
185
185
|
hoverDelayMs
|
|
@@ -196,7 +196,7 @@ export function CodeMirrorRenderer({
|
|
|
196
196
|
// Index segments by annotation ID for O(1) click lookups
|
|
197
197
|
const segmentsByIdRef = useRef(new Map<string, TextSegment>());
|
|
198
198
|
const lineNumbersCompartment = useRef(new Compartment());
|
|
199
|
-
const
|
|
199
|
+
const sessionRef = useRef(session);
|
|
200
200
|
const getTargetResourceNameRef = useRef(getTargetResourceName);
|
|
201
201
|
|
|
202
202
|
// Update refs when they change
|
|
@@ -206,7 +206,7 @@ export function CodeMirrorRenderer({
|
|
|
206
206
|
if (s.annotation) segmentsById.set(s.annotation.id, s);
|
|
207
207
|
}
|
|
208
208
|
segmentsByIdRef.current = segmentsById;
|
|
209
|
-
|
|
209
|
+
sessionRef.current = session;
|
|
210
210
|
getTargetResourceNameRef.current = getTargetResourceName;
|
|
211
211
|
|
|
212
212
|
// Initialize CodeMirror view once
|
|
@@ -238,7 +238,7 @@ export function CodeMirrorRenderer({
|
|
|
238
238
|
EditorView.domEventHandlers({
|
|
239
239
|
click: (event, _view) => {
|
|
240
240
|
const target = event.target as HTMLElement;
|
|
241
|
-
if (
|
|
241
|
+
if (sessionRef.current && handleAnnotationClick(target, segmentsByIdRef.current, sessionRef.current)) {
|
|
242
242
|
event.preventDefault();
|
|
243
243
|
return true;
|
|
244
244
|
}
|
|
@@ -303,7 +303,7 @@ export function CodeMirrorRenderer({
|
|
|
303
303
|
const container = view.dom;
|
|
304
304
|
|
|
305
305
|
const { handleMouseEnter, handleMouseLeave, cleanup: cleanupHover } = createHoverHandlers(
|
|
306
|
-
(
|
|
306
|
+
(id) => sessionRef.current?.client.beckon.hover(id),
|
|
307
307
|
hoverDelayMs
|
|
308
308
|
);
|
|
309
309
|
|
|
@@ -311,7 +311,7 @@ export function CodeMirrorRenderer({
|
|
|
311
311
|
const target = e.target as HTMLElement;
|
|
312
312
|
const annotationElement = target.closest('[data-annotation-id]');
|
|
313
313
|
const annotationId = annotationElement?.getAttribute('data-annotation-id');
|
|
314
|
-
if (annotationId) handleMouseEnter(annotationId);
|
|
314
|
+
if (annotationId) handleMouseEnter(toAnnotationId(annotationId));
|
|
315
315
|
};
|
|
316
316
|
|
|
317
317
|
const handleMouseOut = (e: MouseEvent) => {
|
|
@@ -329,8 +329,8 @@ export function CodeMirrorRenderer({
|
|
|
329
329
|
e.preventDefault();
|
|
330
330
|
e.stopPropagation();
|
|
331
331
|
|
|
332
|
-
if (
|
|
333
|
-
dispatchWidgetClick(result,
|
|
332
|
+
if (sessionRef.current) {
|
|
333
|
+
dispatchWidgetClick(result, sessionRef.current);
|
|
334
334
|
}
|
|
335
335
|
};
|
|
336
336
|
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import React, { useState, createContext, useContext, useCallback } from 'react';
|
|
4
|
-
import type { components } from '@semiont/core';
|
|
5
4
|
import type { Annotator } from '../lib/annotation-registry';
|
|
6
5
|
|
|
7
|
-
type Annotation
|
|
6
|
+
import type { Annotation } from '@semiont/core';
|
|
8
7
|
|
|
9
8
|
interface LiveRegionContextType {
|
|
10
9
|
announce: (message: string, priority?: 'polite' | 'assertive') => void;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
import { useSemiont } from '../session/SemiontProvider';
|
|
5
|
+
import { useObservable } from '../hooks/useObservable';
|
|
4
6
|
import './StatusDisplay.css';
|
|
5
7
|
|
|
6
8
|
interface StatusDisplayProps {
|
|
@@ -9,36 +11,61 @@ interface StatusDisplayProps {
|
|
|
9
11
|
hasValidBackendToken?: boolean;
|
|
10
12
|
}
|
|
11
13
|
|
|
14
|
+
interface StatusData {
|
|
15
|
+
status: string;
|
|
16
|
+
version: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
12
19
|
export function StatusDisplay({
|
|
13
20
|
isFullyAuthenticated = false,
|
|
14
21
|
isAuthenticated = false,
|
|
15
22
|
hasValidBackendToken = false
|
|
16
23
|
}: StatusDisplayProps) {
|
|
17
|
-
const
|
|
18
|
-
const
|
|
24
|
+
const semiont = useObservable(useSemiont().activeSession$)?.client;
|
|
25
|
+
const [data, setData] = useState<StatusData | null>(null);
|
|
26
|
+
const [loading, setLoading] = useState(true);
|
|
27
|
+
const [error, setError] = useState<Error | null>(null);
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (!semiont) { setLoading(false); return; }
|
|
31
|
+
|
|
32
|
+
const fetchStatus = () => {
|
|
33
|
+
semiont.admin.status()
|
|
34
|
+
.then((result) => {
|
|
35
|
+
setData(result as StatusData);
|
|
36
|
+
setError(null);
|
|
37
|
+
setLoading(false);
|
|
38
|
+
})
|
|
39
|
+
.catch((err) => {
|
|
40
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
41
|
+
setLoading(false);
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
fetchStatus();
|
|
46
|
+
const interval = setInterval(fetchStatus, 30000);
|
|
47
|
+
return () => clearInterval(interval);
|
|
48
|
+
}, [semiont]);
|
|
19
49
|
|
|
20
50
|
const getStatusContent = () => {
|
|
21
|
-
// Check for users who are logged in but missing backend token (old sessions)
|
|
22
51
|
if (isAuthenticated && !hasValidBackendToken) {
|
|
23
52
|
return '🚀 Frontend Status: Ready • Backend: Please sign out and sign in again to reconnect';
|
|
24
53
|
}
|
|
25
54
|
|
|
26
|
-
// If user is not authenticated at all, show appropriate message
|
|
27
55
|
if (!isFullyAuthenticated) {
|
|
28
56
|
return '🚀 Frontend Status: Ready • Backend: Authentication required';
|
|
29
57
|
}
|
|
30
58
|
|
|
31
|
-
if (
|
|
32
|
-
return `🚀 Frontend Status: Ready • Backend: ${
|
|
59
|
+
if (data) {
|
|
60
|
+
return `🚀 Frontend Status: Ready • Backend: ${data.status} (v${data.version})`;
|
|
33
61
|
}
|
|
34
62
|
|
|
35
|
-
if (
|
|
63
|
+
if (loading) {
|
|
36
64
|
return '🚀 Frontend Status: Ready • Backend: Connecting...';
|
|
37
65
|
}
|
|
38
66
|
|
|
39
|
-
if (
|
|
40
|
-
|
|
41
|
-
const errorMessage = status.error instanceof Error ? status.error.message : String(status.error);
|
|
67
|
+
if (error) {
|
|
68
|
+
const errorMessage = error.message;
|
|
42
69
|
if (errorMessage.includes('401') || errorMessage.includes('Unauthorized')) {
|
|
43
70
|
return '🚀 Frontend Status: Ready • Backend: Please sign out and sign in again';
|
|
44
71
|
}
|
|
@@ -49,7 +76,6 @@ export function StatusDisplay({
|
|
|
49
76
|
};
|
|
50
77
|
|
|
51
78
|
const getStatusType = (): 'warning' | 'info' | 'success' | 'loading' | 'error' => {
|
|
52
|
-
// Check for users who need to re-authenticate
|
|
53
79
|
if (isAuthenticated && !hasValidBackendToken) {
|
|
54
80
|
return 'warning';
|
|
55
81
|
}
|
|
@@ -58,11 +84,11 @@ export function StatusDisplay({
|
|
|
58
84
|
return 'info';
|
|
59
85
|
}
|
|
60
86
|
|
|
61
|
-
if (
|
|
87
|
+
if (data) {
|
|
62
88
|
return 'success';
|
|
63
89
|
}
|
|
64
90
|
|
|
65
|
-
if (
|
|
91
|
+
if (loading) {
|
|
66
92
|
return 'loading';
|
|
67
93
|
}
|
|
68
94
|
|
|
@@ -85,7 +111,7 @@ export function StatusDisplay({
|
|
|
85
111
|
<p className="semiont-status-hint">
|
|
86
112
|
Sign in to view backend status
|
|
87
113
|
</p>
|
|
88
|
-
) :
|
|
114
|
+
) : error ? (
|
|
89
115
|
<p className="semiont-status-hint semiont-status-error-hint" role="alert">
|
|
90
116
|
<span className="sr-only">Error: </span>
|
|
91
117
|
Check that the backend server is running and accessible
|
|
@@ -93,4 +119,4 @@ export function StatusDisplay({
|
|
|
93
119
|
) : null}
|
|
94
120
|
</section>
|
|
95
121
|
);
|
|
96
|
-
}
|
|
122
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useTranslations } from '../contexts/TranslationContext';
|
|
4
|
-
import {
|
|
4
|
+
import { useSemiont } from '../session/SemiontProvider';
|
|
5
5
|
import './toolbar/Toolbar.css';
|
|
6
6
|
|
|
7
7
|
type ToolbarContext = 'document' | 'simple';
|
|
@@ -17,7 +17,7 @@ interface Props<T extends string = string> {
|
|
|
17
17
|
/**
|
|
18
18
|
* Toolbar component for panel navigation
|
|
19
19
|
*
|
|
20
|
-
* @emits
|
|
20
|
+
* @emits panel:toggle - Toggle panel visibility. Payload: { panel: string }
|
|
21
21
|
*/
|
|
22
22
|
export function Toolbar<T extends string = string>({
|
|
23
23
|
context,
|
|
@@ -25,10 +25,10 @@ export function Toolbar<T extends string = string>({
|
|
|
25
25
|
isArchived = false
|
|
26
26
|
}: Props<T>) {
|
|
27
27
|
const t = useTranslations('Toolbar');
|
|
28
|
-
const
|
|
28
|
+
const semiont = useSemiont();
|
|
29
29
|
|
|
30
30
|
const handlePanelToggle = (panel: string) => {
|
|
31
|
-
|
|
31
|
+
semiont.emit('panel:toggle', { panel });
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
return (
|
|
@@ -4,7 +4,9 @@ import { screen, fireEvent } from '@testing-library/react';
|
|
|
4
4
|
import '@testing-library/jest-dom';
|
|
5
5
|
import { renderWithProviders } from '../../test-utils';
|
|
6
6
|
import { AnnotateReferencesProgressWidget } from '../AnnotateReferencesProgressWidget';
|
|
7
|
-
import type {
|
|
7
|
+
import type { components } from '@semiont/core';
|
|
8
|
+
|
|
9
|
+
type JobProgress = components['schemas']['JobProgress'];
|
|
8
10
|
|
|
9
11
|
describe('AnnotateReferencesProgressWidget', () => {
|
|
10
12
|
it('returns null when progress is null', () => {
|
|
@@ -15,9 +17,10 @@ describe('AnnotateReferencesProgressWidget', () => {
|
|
|
15
17
|
expect(container.firstChild).toBeNull();
|
|
16
18
|
});
|
|
17
19
|
|
|
18
|
-
it('renders progress with
|
|
19
|
-
const progress:
|
|
20
|
-
|
|
20
|
+
it('renders progress with stage message', () => {
|
|
21
|
+
const progress: JobProgress = {
|
|
22
|
+
stage: 'in-progress',
|
|
23
|
+
percentage: 50,
|
|
21
24
|
message: 'Processing entities...',
|
|
22
25
|
};
|
|
23
26
|
|
|
@@ -29,8 +32,9 @@ describe('AnnotateReferencesProgressWidget', () => {
|
|
|
29
32
|
});
|
|
30
33
|
|
|
31
34
|
it('shows cancel button when not complete', () => {
|
|
32
|
-
const progress:
|
|
33
|
-
|
|
35
|
+
const progress: JobProgress = {
|
|
36
|
+
stage: 'in-progress',
|
|
37
|
+
percentage: 30,
|
|
34
38
|
message: 'Working...',
|
|
35
39
|
};
|
|
36
40
|
|
|
@@ -43,8 +47,10 @@ describe('AnnotateReferencesProgressWidget', () => {
|
|
|
43
47
|
});
|
|
44
48
|
|
|
45
49
|
it('hides cancel button when complete', () => {
|
|
46
|
-
const progress:
|
|
47
|
-
|
|
50
|
+
const progress: JobProgress = {
|
|
51
|
+
stage: 'complete',
|
|
52
|
+
percentage: 100,
|
|
53
|
+
message: '',
|
|
48
54
|
};
|
|
49
55
|
|
|
50
56
|
renderWithProviders(
|
|
@@ -56,8 +62,9 @@ describe('AnnotateReferencesProgressWidget', () => {
|
|
|
56
62
|
|
|
57
63
|
it('emits job:cancel-requested on cancel click', () => {
|
|
58
64
|
const handler = vi.fn();
|
|
59
|
-
const progress:
|
|
60
|
-
|
|
65
|
+
const progress: JobProgress = {
|
|
66
|
+
stage: 'in-progress',
|
|
67
|
+
percentage: 40,
|
|
61
68
|
message: 'Working...',
|
|
62
69
|
};
|
|
63
70
|
|
|
@@ -77,8 +84,10 @@ describe('AnnotateReferencesProgressWidget', () => {
|
|
|
77
84
|
});
|
|
78
85
|
|
|
79
86
|
it('renders completed entity types', () => {
|
|
80
|
-
const progress:
|
|
81
|
-
|
|
87
|
+
const progress: JobProgress = {
|
|
88
|
+
stage: 'in-progress',
|
|
89
|
+
percentage: 60,
|
|
90
|
+
message: '',
|
|
82
91
|
completedEntityTypes: [
|
|
83
92
|
{ entityType: 'Person', foundCount: 5 },
|
|
84
93
|
{ entityType: 'Organization', foundCount: 3 },
|
|
@@ -96,9 +105,11 @@ describe('AnnotateReferencesProgressWidget', () => {
|
|
|
96
105
|
expect(foundLabels).toHaveLength(2);
|
|
97
106
|
});
|
|
98
107
|
|
|
99
|
-
it('shows complete icon for complete
|
|
100
|
-
const progress:
|
|
101
|
-
|
|
108
|
+
it('shows complete icon for complete stage', () => {
|
|
109
|
+
const progress: JobProgress = {
|
|
110
|
+
stage: 'complete',
|
|
111
|
+
percentage: 100,
|
|
112
|
+
message: '',
|
|
102
113
|
};
|
|
103
114
|
|
|
104
115
|
const { container } = renderWithProviders(
|
|
@@ -109,9 +120,10 @@ describe('AnnotateReferencesProgressWidget', () => {
|
|
|
109
120
|
expect(screen.getByText('ReferencesPanel.complete')).toBeInTheDocument();
|
|
110
121
|
});
|
|
111
122
|
|
|
112
|
-
it('shows error message for error
|
|
113
|
-
const progress:
|
|
114
|
-
|
|
123
|
+
it('shows error message for error stage', () => {
|
|
124
|
+
const progress: JobProgress = {
|
|
125
|
+
stage: 'error',
|
|
126
|
+
percentage: 0,
|
|
115
127
|
message: 'Something went wrong',
|
|
116
128
|
};
|
|
117
129
|
|
|
@@ -124,8 +136,10 @@ describe('AnnotateReferencesProgressWidget', () => {
|
|
|
124
136
|
});
|
|
125
137
|
|
|
126
138
|
it('shows current entity type processing details', () => {
|
|
127
|
-
const progress:
|
|
128
|
-
|
|
139
|
+
const progress: JobProgress = {
|
|
140
|
+
stage: 'in-progress',
|
|
141
|
+
percentage: 50,
|
|
142
|
+
message: '',
|
|
129
143
|
currentEntityType: 'Location',
|
|
130
144
|
};
|
|
131
145
|
|