@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.
- package/README.md +8 -5
- package/dist/{PdfAnnotationCanvas.client-CHDCGQBR.mjs → PdfAnnotationCanvas.client-6ZGFEN2N.mjs} +9 -13
- package/dist/PdfAnnotationCanvas.client-6ZGFEN2N.mjs.map +1 -0
- package/dist/TranslationManager-9Xj3MIWQ.d.mts +16 -0
- package/dist/chunk-KEDFYI6N.mjs +7788 -0
- package/dist/chunk-KEDFYI6N.mjs.map +1 -0
- package/dist/index.d.mts +171 -1140
- package/dist/index.mjs +3263 -13644
- package/dist/index.mjs.map +1 -1
- package/dist/test-utils.d.mts +46 -21
- package/dist/test-utils.mjs +2499 -87
- package/dist/test-utils.mjs.map +1 -1
- package/package.json +1 -2
- package/src/components/AnnotateReferencesProgressWidget.tsx +21 -28
- package/src/components/CodeMirrorRenderer.tsx +9 -11
- 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 +47 -64
- package/src/components/__tests__/Toolbar.test.tsx +4 -4
- package/src/components/annotation/AnnotateToolbar.tsx +8 -7
- package/src/components/annotation/__tests__/AnnotateToolbar.test.tsx +31 -77
- package/src/components/annotation-popups/__tests__/JsonLdView.test.tsx +0 -1
- package/src/components/image-annotation/AnnotationOverlay.tsx +12 -13
- package/src/components/image-annotation/SvgDrawingCanvas.tsx +7 -7
- package/src/components/modals/PermissionDeniedModal.tsx +11 -11
- package/src/components/modals/ReferenceWizardModal.tsx +14 -18
- package/src/components/modals/ResourceSearchModal.tsx +10 -6
- package/src/components/modals/SearchModal.tsx +10 -6
- 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.search-wiring.test.tsx +10 -7
- 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 +9 -11
- package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +0 -1
- package/src/components/resource/AnnotateView.tsx +7 -6
- package/src/components/resource/AnnotationHistory.tsx +9 -12
- package/src/components/resource/BrowseView.tsx +8 -7
- package/src/components/resource/ResourceViewer.tsx +17 -25
- package/src/components/resource/__tests__/AnnotationHistory.test.tsx +54 -192
- package/src/components/resource/__tests__/BrowseView.test.tsx +34 -83
- package/src/components/resource/__tests__/ResourceViewer.mode-switch.test.tsx +40 -31
- package/src/components/resource/panels/AssessmentEntry.tsx +5 -4
- package/src/components/resource/panels/AssessmentPanel.tsx +19 -15
- package/src/components/resource/panels/AssistSection.tsx +11 -13
- package/src/components/resource/panels/CollaborationPanel.tsx +29 -7
- package/src/components/resource/panels/CommentEntry.tsx +5 -4
- package/src/components/resource/panels/CommentsPanel.tsx +9 -11
- package/src/components/resource/panels/HighlightEntry.tsx +5 -4
- package/src/components/resource/panels/HighlightPanel.tsx +10 -11
- package/src/components/resource/panels/ReferenceEntry.tsx +8 -8
- package/src/components/resource/panels/ReferencesPanel.tsx +13 -12
- package/src/components/resource/panels/ResourceInfoPanel.tsx +7 -6
- package/src/components/resource/panels/TagEntry.tsx +5 -4
- package/src/components/resource/panels/TaggingPanel.tsx +10 -16
- package/src/components/resource/panels/UnifiedAnnotationsPanel.tsx +3 -2
- package/src/components/resource/panels/__tests__/AssessmentPanel.test.tsx +18 -52
- package/src/components/resource/panels/__tests__/CollaborationPanel.test.tsx +51 -20
- package/src/components/resource/panels/__tests__/CommentsPanel.test.tsx +18 -56
- package/src/components/resource/panels/__tests__/HighlightPanel.annotationProgress.test.tsx +0 -1
- package/src/components/resource/panels/__tests__/ReferenceEntry.test.tsx +4 -5
- 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 +15 -47
- package/src/components/resource/panels/__tests__/TaggingPanel.test.tsx +15 -47
- package/src/components/settings/SettingsPanel.tsx +8 -8
- package/src/components/settings/__tests__/SettingsPanel.test.tsx +12 -12
- package/src/features/admin-devops/components/AdminDevOpsPage.tsx +1 -1
- package/src/features/admin-exchange/components/AdminExchangePage.tsx +1 -1
- package/src/features/admin-exchange/components/ImportCard.tsx +2 -6
- package/src/features/admin-security/components/AdminSecurityPage.tsx +1 -1
- package/src/features/admin-users/components/AdminUsersPage.tsx +1 -1
- package/src/features/moderate-entity-tags/components/EntityTagsPage.tsx +1 -1
- package/src/features/moderate-recent/components/RecentDocumentsPage.tsx +1 -1
- 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 +5 -22
- package/src/features/resource-discovery/__tests__/ResourceDiscoveryPage.test.tsx +4 -3
- package/src/features/resource-discovery/components/ResourceDiscoveryPage.tsx +1 -1
- package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +38 -45
- package/src/features/resource-viewer/components/ResourceViewerPage.tsx +123 -192
- 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
|
@@ -5,8 +5,8 @@ import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
|
5
5
|
import userEvent from '@testing-library/user-event';
|
|
6
6
|
import '@testing-library/jest-dom';
|
|
7
7
|
import { TaggingPanel } from '../TaggingPanel';
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
8
|
+
import type { components, EventBus } from '@semiont/core';
|
|
9
|
+
import { createTestSemiontWrapper } from '../../../../test-utils';
|
|
10
10
|
|
|
11
11
|
type Annotation = components['schemas']['Annotation'];
|
|
12
12
|
|
|
@@ -18,59 +18,27 @@ interface TrackedEvent {
|
|
|
18
18
|
|
|
19
19
|
function createEventTracker() {
|
|
20
20
|
const events: TrackedEvent[] = [];
|
|
21
|
-
|
|
22
|
-
function EventTrackingWrapper({ children }: { children: React.ReactNode }) {
|
|
23
|
-
const eventBus = useEventBus();
|
|
24
|
-
|
|
25
|
-
React.useEffect(() => {
|
|
26
|
-
const handlers: Array<() => void> = [];
|
|
27
|
-
|
|
28
|
-
const trackEvent = (eventName: string) => (payload: any) => {
|
|
29
|
-
events.push({ event: eventName, payload });
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const panelEvents = ['mark:submit', 'mark:assist-request'] as const;
|
|
33
|
-
|
|
34
|
-
panelEvents.forEach(eventName => {
|
|
35
|
-
const handler = trackEvent(eventName);
|
|
36
|
-
const subscription = eventBus.get(eventName).subscribe(handler);
|
|
37
|
-
handlers.push(subscription);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
return () => {
|
|
41
|
-
handlers.forEach(sub => sub.unsubscribe());
|
|
42
|
-
};
|
|
43
|
-
}, [eventBus]);
|
|
44
|
-
|
|
45
|
-
return <>{children}</>;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
21
|
return {
|
|
49
|
-
EventTrackingWrapper,
|
|
50
22
|
events,
|
|
51
|
-
clear: () => {
|
|
52
|
-
|
|
23
|
+
clear: () => { events.length = 0; },
|
|
24
|
+
_attach(eventBus: EventBus) {
|
|
25
|
+
const panelEvents = ['mark:submit', 'mark:assist-request'] as const;
|
|
26
|
+
panelEvents.forEach((eventName) => {
|
|
27
|
+
eventBus.get(eventName).subscribe((payload: any) => {
|
|
28
|
+
events.push({ event: eventName, payload });
|
|
29
|
+
});
|
|
30
|
+
});
|
|
53
31
|
},
|
|
54
32
|
};
|
|
55
33
|
}
|
|
56
34
|
|
|
57
|
-
// Helper to render with EventBusProvider
|
|
58
35
|
const renderWithEventBus = (component: React.ReactElement, tracker?: ReturnType<typeof createEventTracker>) => {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
{component}
|
|
64
|
-
</tracker.EventTrackingWrapper>
|
|
65
|
-
</EventBusProvider>
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
return render(
|
|
70
|
-
<EventBusProvider>
|
|
71
|
-
{component}
|
|
72
|
-
</EventBusProvider>
|
|
36
|
+
const { SemiontWrapper, eventBus } = createTestSemiontWrapper();
|
|
37
|
+
if (tracker) tracker._attach(eventBus);
|
|
38
|
+
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
39
|
+
<SemiontWrapper>{children}</SemiontWrapper>
|
|
73
40
|
);
|
|
41
|
+
return render(component, { wrapper: Wrapper });
|
|
74
42
|
};
|
|
75
43
|
|
|
76
44
|
// Mock TranslationContext
|
|
@@ -4,7 +4,7 @@ import React, { useEffect } from 'react';
|
|
|
4
4
|
import { LOCALES } from '@semiont/api-client';
|
|
5
5
|
import { useTranslations } from '../../contexts/TranslationContext';
|
|
6
6
|
import { useLanguageChangeAnnouncements } from '../LiveRegion';
|
|
7
|
-
import {
|
|
7
|
+
import { useSemiont } from '../../session/SemiontProvider';
|
|
8
8
|
import './SettingsPanel.css';
|
|
9
9
|
|
|
10
10
|
interface SettingsPanelProps {
|
|
@@ -31,7 +31,7 @@ export function SettingsPanel({
|
|
|
31
31
|
hoverDelayMs
|
|
32
32
|
}: SettingsPanelProps) {
|
|
33
33
|
const t = useTranslations('Settings');
|
|
34
|
-
const
|
|
34
|
+
const semiont = useSemiont();
|
|
35
35
|
const { announceLanguageChanging, announceLanguageChanged } = useLanguageChangeAnnouncements();
|
|
36
36
|
|
|
37
37
|
// Track previous locale to detect changes
|
|
@@ -41,7 +41,7 @@ export function SettingsPanel({
|
|
|
41
41
|
const handleLocaleChange = (newLocale: string) => {
|
|
42
42
|
const localeName = LOCALES.find(l => l.code === newLocale)?.nativeName || newLocale;
|
|
43
43
|
announceLanguageChanging(localeName);
|
|
44
|
-
|
|
44
|
+
semiont.emit('settings:locale-changed', { locale: newLocale });
|
|
45
45
|
};
|
|
46
46
|
|
|
47
47
|
// Announce when language has successfully changed
|
|
@@ -70,7 +70,7 @@ export function SettingsPanel({
|
|
|
70
70
|
type="button"
|
|
71
71
|
role="switch"
|
|
72
72
|
aria-checked={showLineNumbers}
|
|
73
|
-
onClick={() =>
|
|
73
|
+
onClick={() => semiont.emit('settings:line-numbers-toggled', undefined)}
|
|
74
74
|
className={`semiont-toggle ${
|
|
75
75
|
showLineNumbers ? 'semiont-toggle--active' : ''
|
|
76
76
|
}`}
|
|
@@ -94,7 +94,7 @@ export function SettingsPanel({
|
|
|
94
94
|
</label>
|
|
95
95
|
<div className="semiont-settings-panel__button-group">
|
|
96
96
|
<button
|
|
97
|
-
onClick={() =>
|
|
97
|
+
onClick={() => semiont.emit('settings:theme-changed', { theme: 'light' })}
|
|
98
98
|
className={`semiont-panel-button ${
|
|
99
99
|
theme === 'light' ? 'semiont-panel-button-active' : ''
|
|
100
100
|
}`}
|
|
@@ -103,7 +103,7 @@ export function SettingsPanel({
|
|
|
103
103
|
☀️ {t('themeLight')}
|
|
104
104
|
</button>
|
|
105
105
|
<button
|
|
106
|
-
onClick={() =>
|
|
106
|
+
onClick={() => semiont.emit('settings:theme-changed', { theme: 'dark' })}
|
|
107
107
|
className={`semiont-panel-button ${
|
|
108
108
|
theme === 'dark' ? 'semiont-panel-button-active' : ''
|
|
109
109
|
}`}
|
|
@@ -112,7 +112,7 @@ export function SettingsPanel({
|
|
|
112
112
|
🌙 {t('themeDark')}
|
|
113
113
|
</button>
|
|
114
114
|
<button
|
|
115
|
-
onClick={() =>
|
|
115
|
+
onClick={() => semiont.emit('settings:theme-changed', { theme: 'system' })}
|
|
116
116
|
className={`semiont-panel-button ${
|
|
117
117
|
theme === 'system' ? 'semiont-panel-button-active' : ''
|
|
118
118
|
}`}
|
|
@@ -170,7 +170,7 @@ export function SettingsPanel({
|
|
|
170
170
|
max="500"
|
|
171
171
|
step="50"
|
|
172
172
|
value={hoverDelayMs}
|
|
173
|
-
onChange={(e) =>
|
|
173
|
+
onChange={(e) => semiont.emit('settings:hover-delay-changed', { hoverDelayMs: Number(e.target.value) })}
|
|
174
174
|
className="semiont-slider"
|
|
175
175
|
aria-describedby="hover-delay-description"
|
|
176
176
|
/>
|
|
@@ -63,12 +63,12 @@ describe('SettingsPanel', () => {
|
|
|
63
63
|
|
|
64
64
|
it('emits settings:line-numbers-toggled on toggle click', () => {
|
|
65
65
|
const handler = vi.fn();
|
|
66
|
-
const {
|
|
66
|
+
const { shellBus } = renderWithProviders(
|
|
67
67
|
<SettingsPanel {...defaultProps} />,
|
|
68
|
-
{
|
|
68
|
+
{ returnShellBus: true }
|
|
69
69
|
);
|
|
70
70
|
|
|
71
|
-
const sub =
|
|
71
|
+
const sub = shellBus!.get('settings:line-numbers-toggled').subscribe(handler);
|
|
72
72
|
fireEvent.click(screen.getByRole('switch'));
|
|
73
73
|
expect(handler).toHaveBeenCalled();
|
|
74
74
|
sub.unsubscribe();
|
|
@@ -94,12 +94,12 @@ describe('SettingsPanel', () => {
|
|
|
94
94
|
|
|
95
95
|
it('emits settings:theme-changed on theme button click', () => {
|
|
96
96
|
const handler = vi.fn();
|
|
97
|
-
const {
|
|
97
|
+
const { shellBus } = renderWithProviders(
|
|
98
98
|
<SettingsPanel {...defaultProps} />,
|
|
99
|
-
{
|
|
99
|
+
{ returnShellBus: true }
|
|
100
100
|
);
|
|
101
101
|
|
|
102
|
-
const sub =
|
|
102
|
+
const sub = shellBus!.get('settings:theme-changed').subscribe(handler);
|
|
103
103
|
fireEvent.click(screen.getByText(/Settings.themeDark/));
|
|
104
104
|
expect(handler).toHaveBeenCalledWith({ theme: 'dark' });
|
|
105
105
|
sub.unsubscribe();
|
|
@@ -125,12 +125,12 @@ describe('SettingsPanel', () => {
|
|
|
125
125
|
|
|
126
126
|
it('emits settings:locale-changed on language change', () => {
|
|
127
127
|
const handler = vi.fn();
|
|
128
|
-
const {
|
|
128
|
+
const { shellBus } = renderWithProviders(
|
|
129
129
|
<SettingsPanel {...defaultProps} />,
|
|
130
|
-
{
|
|
130
|
+
{ returnShellBus: true }
|
|
131
131
|
);
|
|
132
132
|
|
|
133
|
-
const sub =
|
|
133
|
+
const sub = shellBus!.get('settings:locale-changed').subscribe(handler);
|
|
134
134
|
fireEvent.change(screen.getByLabelText('Settings.language'), {
|
|
135
135
|
target: { value: 'fr' },
|
|
136
136
|
});
|
|
@@ -173,12 +173,12 @@ describe('SettingsPanel', () => {
|
|
|
173
173
|
|
|
174
174
|
it('emits settings:hover-delay-changed on slider change', () => {
|
|
175
175
|
const handler = vi.fn();
|
|
176
|
-
const {
|
|
176
|
+
const { shellBus } = renderWithProviders(
|
|
177
177
|
<SettingsPanel {...defaultProps} />,
|
|
178
|
-
{
|
|
178
|
+
{ returnShellBus: true }
|
|
179
179
|
);
|
|
180
180
|
|
|
181
|
-
const sub =
|
|
181
|
+
const sub = shellBus!.get('settings:hover-delay-changed').subscribe(handler);
|
|
182
182
|
fireEvent.change(screen.getByLabelText('Settings.hoverDelay'), {
|
|
183
183
|
target: { value: '300' },
|
|
184
184
|
});
|
|
@@ -9,7 +9,7 @@ import React from 'react';
|
|
|
9
9
|
import {
|
|
10
10
|
CommandLineIcon
|
|
11
11
|
} from '@heroicons/react/24/outline';
|
|
12
|
-
import { COMMON_PANELS, type ToolbarPanelType } from '
|
|
12
|
+
import { COMMON_PANELS, type ToolbarPanelType } from '@semiont/api-client';
|
|
13
13
|
|
|
14
14
|
export interface DevOpsFeature {
|
|
15
15
|
title: string;
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import React from 'react';
|
|
8
|
-
import { COMMON_PANELS, type ToolbarPanelType } from '
|
|
8
|
+
import { COMMON_PANELS, type ToolbarPanelType } from '@semiont/api-client';
|
|
9
9
|
import { ExportCard, type ExportCardTranslations } from './ExportCard';
|
|
10
10
|
import { ImportCard, type ImportCardProps, type ImportCardTranslations } from './ImportCard';
|
|
11
11
|
import { ImportProgress, type ImportProgressTranslations } from './ImportProgress';
|
|
@@ -5,13 +5,9 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import React, { useRef, useState, useCallback } from 'react';
|
|
8
|
+
import type { ImportPreview } from '@semiont/api-client';
|
|
8
9
|
|
|
9
|
-
export
|
|
10
|
-
format: string;
|
|
11
|
-
version: number;
|
|
12
|
-
sourceUrl: string;
|
|
13
|
-
stats: Record<string, number>;
|
|
14
|
-
}
|
|
10
|
+
export type { ImportPreview };
|
|
15
11
|
|
|
16
12
|
export interface ImportCardTranslations {
|
|
17
13
|
title: string;
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
CheckCircleIcon,
|
|
13
13
|
InformationCircleIcon
|
|
14
14
|
} from '@heroicons/react/24/outline';
|
|
15
|
-
import { COMMON_PANELS, type ToolbarPanelType } from '
|
|
15
|
+
import { COMMON_PANELS, type ToolbarPanelType } from '@semiont/api-client';
|
|
16
16
|
|
|
17
17
|
export interface OAuthProvider {
|
|
18
18
|
name: string;
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
PlusIcon,
|
|
12
12
|
ExclamationCircleIcon
|
|
13
13
|
} from '@heroicons/react/24/outline';
|
|
14
|
-
import { COMMON_PANELS, type ToolbarPanelType } from '
|
|
14
|
+
import { COMMON_PANELS, type ToolbarPanelType } from '@semiont/api-client';
|
|
15
15
|
|
|
16
16
|
export interface EntityTagsPageProps {
|
|
17
17
|
// Data props
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import React from 'react';
|
|
9
9
|
import { ClockIcon } from '@heroicons/react/24/outline';
|
|
10
|
-
import { COMMON_PANELS, type ToolbarPanelType } from '
|
|
10
|
+
import { COMMON_PANELS, type ToolbarPanelType } from '@semiont/api-client';
|
|
11
11
|
|
|
12
12
|
export interface RecentDocumentsPageProps {
|
|
13
13
|
// Data props
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
ScaleIcon,
|
|
12
12
|
LightBulbIcon
|
|
13
13
|
} from '@heroicons/react/24/outline';
|
|
14
|
-
import { COMMON_PANELS, type ToolbarPanelType } from '
|
|
14
|
+
import { COMMON_PANELS, type ToolbarPanelType } from '@semiont/api-client';
|
|
15
15
|
import type { TagSchema } from '@semiont/react-ui';
|
|
16
16
|
|
|
17
17
|
export interface TagSchemasPageProps {
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import React from 'react';
|
|
9
|
-
import { COMMON_PANELS, type ToolbarPanelType } from '
|
|
9
|
+
import { COMMON_PANELS, type ToolbarPanelType } from '@semiont/api-client';
|
|
10
10
|
import { ExportCard, type ExportCardTranslations } from '../../admin-exchange/components/ExportCard';
|
|
11
11
|
import { ImportCard, type ImportCardProps, type ImportCardTranslations } from '../../admin-exchange/components/ImportCard';
|
|
12
12
|
import { ImportProgress, type ImportProgressTranslations } from '../../admin-exchange/components/ImportProgress';
|
|
@@ -9,7 +9,7 @@ import { describe, it, expect, vi } from 'vitest';
|
|
|
9
9
|
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
10
10
|
import { ResourceComposePage } from '../components/ResourceComposePage';
|
|
11
11
|
import type { ResourceComposePageProps, SaveResourceParams } from '../components/ResourceComposePage';
|
|
12
|
-
import {
|
|
12
|
+
import { createTestSemiontWrapper } from '../../../test-utils';
|
|
13
13
|
|
|
14
14
|
// Mock CodeMirrorRenderer to avoid CodeMirror dependencies
|
|
15
15
|
vi.mock('../../../components/CodeMirrorRenderer', () => ({
|
|
@@ -72,9 +72,11 @@ const createMockProps = (overrides?: Partial<ResourceComposePageProps>): Resourc
|
|
|
72
72
|
...overrides,
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
-
// Helper to render with
|
|
75
|
+
// Helper to render with a session-capable tree (provides the event bus the
|
|
76
|
+
// component reaches for via useSemiont/useObservable).
|
|
76
77
|
const renderWithProviders = (ui: React.ReactElement) => {
|
|
77
|
-
|
|
78
|
+
const { SemiontWrapper } = createTestSemiontWrapper();
|
|
79
|
+
return render(<SemiontWrapper>{ui}</SemiontWrapper>);
|
|
78
80
|
};
|
|
79
81
|
|
|
80
82
|
describe('ResourceComposePage', () => {
|
|
@@ -7,34 +7,17 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import React, { useState, useEffect } from 'react';
|
|
10
|
-
import type {
|
|
11
|
-
import { isImageMimeType, isPdfMimeType, LOCALES } from '@semiont/api-client';
|
|
12
|
-
import { COMMON_PANELS, type ToolbarPanelType } from '
|
|
10
|
+
import type { GatheredContext } from '@semiont/core';
|
|
11
|
+
import { isImageMimeType, isPdfMimeType, LOCALES, type CloneData, type ReferenceData } from '@semiont/api-client';
|
|
12
|
+
import { COMMON_PANELS, type ToolbarPanelType } from '@semiont/api-client';
|
|
13
13
|
import { buttonStyles } from '../../../lib/button-styles';
|
|
14
14
|
import { CodeMirrorRenderer } from '../../../components/CodeMirrorRenderer';
|
|
15
15
|
import { useFormAnnouncements } from '../../../components/LiveRegion';
|
|
16
16
|
|
|
17
|
-
type ResourceDescriptor = components['schemas']['ResourceDescriptor'];
|
|
18
|
-
|
|
19
17
|
export interface ResourceComposePageProps {
|
|
20
|
-
// Mode detection
|
|
21
18
|
mode: 'new' | 'clone' | 'reference';
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
cloneData?: {
|
|
25
|
-
sourceResource: ResourceDescriptor;
|
|
26
|
-
sourceContent: string;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
// Reference completion data
|
|
30
|
-
referenceData?: {
|
|
31
|
-
annotationUri: string;
|
|
32
|
-
sourceDocumentId: string;
|
|
33
|
-
name: string;
|
|
34
|
-
entityTypes: string[];
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
// Gathered context from wizard (optional, for reference mode)
|
|
19
|
+
cloneData?: CloneData | null;
|
|
20
|
+
referenceData?: ReferenceData | null;
|
|
38
21
|
gatheredContext?: GatheredContext | null;
|
|
39
22
|
|
|
40
23
|
// Available options
|
|
@@ -9,7 +9,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
|
9
9
|
import { render, screen, fireEvent } from '@testing-library/react';
|
|
10
10
|
import { ResourceDiscoveryPage } from '../components/ResourceDiscoveryPage';
|
|
11
11
|
import type { ResourceDiscoveryPageProps } from '../components/ResourceDiscoveryPage';
|
|
12
|
-
import {
|
|
12
|
+
import { createTestSemiontWrapper } from '../../../test-utils';
|
|
13
13
|
|
|
14
14
|
const createMockResource = (id: string, name: string, entityTypes: string[] = []) => ({
|
|
15
15
|
'@context': 'https://www.w3.org/ns/anno.jsonld',
|
|
@@ -58,9 +58,10 @@ const createMockProps = (overrides?: Partial<ResourceDiscoveryPageProps>): Resou
|
|
|
58
58
|
...overrides,
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
-
// Helper to render with
|
|
61
|
+
// Helper to render with SemiontProvider (gives components access to session.emit)
|
|
62
62
|
const renderWithProviders = (ui: React.ReactElement) => {
|
|
63
|
-
|
|
63
|
+
const { SemiontWrapper } = createTestSemiontWrapper();
|
|
64
|
+
return render(<SemiontWrapper>{ui}</SemiontWrapper>);
|
|
64
65
|
};
|
|
65
66
|
|
|
66
67
|
describe('ResourceDiscoveryPage', () => {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import React, { useState, useCallback, useRef } from 'react';
|
|
9
9
|
import type { components } from '@semiont/core';
|
|
10
10
|
import { getResourceId } from '@semiont/api-client';
|
|
11
|
-
import { COMMON_PANELS, type ToolbarPanelType } from '
|
|
11
|
+
import { COMMON_PANELS, type ToolbarPanelType } from '@semiont/api-client';
|
|
12
12
|
import { useRovingTabIndex } from '../../../hooks/useRovingTabIndex';
|
|
13
13
|
import { Toolbar } from '../../../components/Toolbar';
|
|
14
14
|
import { ResourceCard } from './ResourceCard';
|
|
@@ -10,12 +10,9 @@ import { render, screen, act } from '@testing-library/react';
|
|
|
10
10
|
import React from 'react';
|
|
11
11
|
import { ResourceViewerPage } from '../components/ResourceViewerPage';
|
|
12
12
|
import type { ResourceViewerPageProps } from '../components/ResourceViewerPage';
|
|
13
|
-
// Import directly from context file to bypass mocked barrel export
|
|
14
|
-
import { EventBusProvider } from '../../../contexts/EventBusContext';
|
|
15
|
-
import { ApiClientProvider } from '../../../contexts/ApiClientContext';
|
|
16
|
-
import { AuthTokenProvider } from '../../../contexts/AuthTokenContext';
|
|
17
13
|
import { ToastProvider } from '../../../components/Toast';
|
|
18
14
|
import { ThemeProvider } from '../../../contexts/ThemeContext';
|
|
15
|
+
import { createTestSemiontWrapper } from '../../../test-utils';
|
|
19
16
|
|
|
20
17
|
// jsdom doesn't implement window.matchMedia — mock it for useTheme
|
|
21
18
|
Object.defineProperty(window, 'matchMedia', {
|
|
@@ -37,32 +34,41 @@ vi.mock('../../../hooks/useResourceContent', () => ({
|
|
|
37
34
|
useResourceContent: () => ({ content: 'Test content', loading: false }),
|
|
38
35
|
}));
|
|
39
36
|
|
|
40
|
-
vi.mock('../../../lib/api-hooks', () => ({
|
|
41
|
-
useResources: () => ({
|
|
42
|
-
annotations: { useQuery: () => ({ data: { annotations: [] } }) },
|
|
43
|
-
referencedBy: { useQuery: () => ({ data: { referencedBy: [] }, isLoading: false }) },
|
|
44
|
-
mediaToken: { useQuery: () => ({ data: { token: 'mock-media-token' }, isLoading: false }) },
|
|
45
|
-
update: { useMutation: () => ({ mutateAsync: vi.fn() }) },
|
|
46
|
-
generateCloneToken: { useMutation: () => ({ mutateAsync: vi.fn() }) },
|
|
47
|
-
}),
|
|
48
|
-
useEntityTypes: () => ({
|
|
49
|
-
list: { useQuery: () => ({ data: { entityTypes: ['Document', 'Article', 'Book'] } }) },
|
|
50
|
-
}),
|
|
51
|
-
}));
|
|
52
37
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
38
|
+
// Stub SemiontBrowser whose activeSession$ emits a session carrying a real
|
|
39
|
+
// SemiontApiClient (wired to a dummy baseUrl). The real client surface lets
|
|
40
|
+
// createResourceViewerPageVM run against the full namespace API without us
|
|
41
|
+
// hand-stubbing every method it touches.
|
|
42
|
+
const { stubBrowser } = vi.hoisted(() => {
|
|
43
|
+
const { BehaviorSubject } = require('rxjs');
|
|
44
|
+
const { SemiontApiClient } = require('@semiont/api-client');
|
|
45
|
+
const { baseUrl } = require('@semiont/core');
|
|
46
|
+
const client = new SemiontApiClient({
|
|
47
|
+
baseUrl: baseUrl('http://localhost:4000'),
|
|
48
|
+
});
|
|
49
|
+
const stubActiveSession$ = new BehaviorSubject({ client });
|
|
50
|
+
const stubOpenResources$ = new BehaviorSubject([]);
|
|
51
|
+
const stubBrowser = {
|
|
52
|
+
activeSession$: stubActiveSession$,
|
|
53
|
+
openResources$: stubOpenResources$,
|
|
54
|
+
addOpenResource: vi.fn(),
|
|
55
|
+
removeOpenResource: vi.fn(),
|
|
56
|
+
updateOpenResourceName: vi.fn(),
|
|
57
|
+
reorderOpenResources: vi.fn(),
|
|
58
|
+
emit: vi.fn(),
|
|
59
|
+
on: vi.fn(() => () => {}),
|
|
60
|
+
stream: vi.fn(() => ({ subscribe: () => ({ unsubscribe: () => {} }) })),
|
|
61
|
+
};
|
|
62
|
+
return { stubBrowser };
|
|
63
|
+
});
|
|
56
64
|
|
|
57
|
-
|
|
58
|
-
vi.
|
|
59
|
-
|
|
65
|
+
vi.mock('../../../session/SemiontProvider', async () => {
|
|
66
|
+
const actual = await vi.importActual<typeof import('../../../session/SemiontProvider')>(
|
|
67
|
+
'../../../session/SemiontProvider'
|
|
68
|
+
);
|
|
60
69
|
return {
|
|
61
70
|
...actual,
|
|
62
|
-
|
|
63
|
-
invalidateQueries: vi.fn(),
|
|
64
|
-
setQueryData: vi.fn(),
|
|
65
|
-
}),
|
|
71
|
+
useSemiont: () => stubBrowser,
|
|
66
72
|
};
|
|
67
73
|
});
|
|
68
74
|
|
|
@@ -82,12 +88,10 @@ vi.mock('@semiont/react-ui', async () => {
|
|
|
82
88
|
createCancelDetectionHandler: () => vi.fn(),
|
|
83
89
|
useDebouncedCallback: (fn: any) => fn,
|
|
84
90
|
supportsDetection: () => false,
|
|
85
|
-
MakeMeaningEventBusProvider: ({ children }: any) => children,
|
|
86
91
|
useResourceLoadingAnnouncements: () => ({
|
|
87
92
|
announceResourceLoading: vi.fn(),
|
|
88
93
|
announceResourceLoaded: vi.fn(),
|
|
89
94
|
}),
|
|
90
|
-
// Don't mock EventBusProvider, useEventBus - let actual pass through via ...actual
|
|
91
95
|
useEventSubscriptions: vi.fn(),
|
|
92
96
|
useResourceAnnotations: () => ({
|
|
93
97
|
clearNewAnnotationId: vi.fn(),
|
|
@@ -99,15 +103,6 @@ useDebouncedCallback: (fn: any) => fn,
|
|
|
99
103
|
};
|
|
100
104
|
});
|
|
101
105
|
|
|
102
|
-
vi.mock('../../../contexts/OpenResourcesContext', () => ({
|
|
103
|
-
useOpenResources: () => ({
|
|
104
|
-
openResources: [],
|
|
105
|
-
addResource: vi.fn(),
|
|
106
|
-
removeResource: vi.fn(),
|
|
107
|
-
isResourceOpen: vi.fn().mockReturnValue(false),
|
|
108
|
-
}),
|
|
109
|
-
}));
|
|
110
|
-
|
|
111
106
|
vi.mock('../../../contexts/ResourceAnnotationsContext', () => ({
|
|
112
107
|
useResourceAnnotations: () => ({
|
|
113
108
|
clearNewAnnotationId: vi.fn(),
|
|
@@ -123,6 +118,7 @@ vi.mock('../../../contexts/ResourceAnnotationsContext', () => ({
|
|
|
123
118
|
// (the barrel export mock doesn't intercept direct context imports)
|
|
124
119
|
const mockUseEventSubscriptions = vi.fn();
|
|
125
120
|
vi.mock('../../../contexts/useEventSubscription', () => ({
|
|
121
|
+
useEventSubscription: vi.fn(),
|
|
126
122
|
useEventSubscriptions: (...args: unknown[]) => mockUseEventSubscriptions(...args),
|
|
127
123
|
}));
|
|
128
124
|
|
|
@@ -154,7 +150,7 @@ const createMockProps = (overrides?: Partial<ResourceViewerPageProps>): Resource
|
|
|
154
150
|
Link: ({ children }: any) => <a>{children}</a>,
|
|
155
151
|
routes: {},
|
|
156
152
|
refetchDocument: vi.fn().mockResolvedValue(undefined),
|
|
157
|
-
streamStatus: '
|
|
153
|
+
streamStatus: 'open' as const,
|
|
158
154
|
ToolbarPanels: ({ children, activePanel }: any) =>
|
|
159
155
|
!activePanel ? null : <div data-testid="toolbar-panels">{children}</div>,
|
|
160
156
|
...overrides,
|
|
@@ -162,16 +158,13 @@ const createMockProps = (overrides?: Partial<ResourceViewerPageProps>): Resource
|
|
|
162
158
|
|
|
163
159
|
// Test wrapper to provide all required providers
|
|
164
160
|
const renderWithProviders = (ui: React.ReactElement) => {
|
|
161
|
+
const { SemiontWrapper } = createTestSemiontWrapper();
|
|
165
162
|
return render(
|
|
166
163
|
<ThemeProvider>
|
|
167
164
|
<ToastProvider>
|
|
168
|
-
<
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
{ui}
|
|
172
|
-
</ApiClientProvider>
|
|
173
|
-
</EventBusProvider>
|
|
174
|
-
</AuthTokenProvider>
|
|
165
|
+
<SemiontWrapper>
|
|
166
|
+
{ui}
|
|
167
|
+
</SemiontWrapper>
|
|
175
168
|
</ToastProvider>
|
|
176
169
|
</ThemeProvider>
|
|
177
170
|
);
|