@semiont/react-ui 0.4.7 → 0.4.10
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/{PdfAnnotationCanvas.client-LF6DDTCV.mjs → PdfAnnotationCanvas.client-CW6SKH2U.mjs} +7 -25
- package/dist/PdfAnnotationCanvas.client-CW6SKH2U.mjs.map +1 -0
- package/dist/{EventBusContext-DUIMowqQ.d.mts → TranslationManager-CudgH3gw.d.mts} +1 -74
- package/dist/{ar-3URRW77J.mjs → ar-R4CRNXEF.mjs} +3 -2
- package/dist/ar-R4CRNXEF.mjs.map +1 -0
- package/dist/{bn-DCQD3XZ5.mjs → bn-CZKGRHTA.mjs} +3 -2
- package/dist/bn-CZKGRHTA.mjs.map +1 -0
- package/dist/{chunk-XMCUHQ2Y.mjs → chunk-BQJWOK4C.mjs} +15 -34
- package/dist/chunk-BQJWOK4C.mjs.map +1 -0
- package/dist/{chunk-5JZFKRLW.mjs → chunk-HNZOXH4L.mjs} +33 -35
- package/dist/chunk-HNZOXH4L.mjs.map +1 -0
- package/dist/{chunk-PWIVZQ4X.mjs → chunk-HVMAGUFA.mjs} +3 -2
- package/dist/chunk-HVMAGUFA.mjs.map +1 -0
- package/dist/{chunk-4RMWYJUJ.mjs → chunk-OL5UST25.mjs} +31 -31
- package/dist/{cs-23KOZUFE.mjs → cs-4WIB2IHH.mjs} +3 -2
- package/dist/cs-4WIB2IHH.mjs.map +1 -0
- package/dist/{da-OIQ66A42.mjs → da-JWYEUYPX.mjs} +3 -2
- package/dist/da-JWYEUYPX.mjs.map +1 -0
- package/dist/{de-FCCLKE2X.mjs → de-GWUQZGER.mjs} +3 -2
- package/dist/de-GWUQZGER.mjs.map +1 -0
- package/dist/{el-3ADITCGI.mjs → el-DM2GT7P5.mjs} +3 -2
- package/dist/el-DM2GT7P5.mjs.map +1 -0
- package/dist/{en-LNW2A3RA.mjs → en-IUV4ZXKH.mjs} +2 -2
- package/dist/{es-POQEEYIW.mjs → es-6LVQIM3D.mjs} +3 -2
- package/dist/es-6LVQIM3D.mjs.map +1 -0
- package/dist/{fa-RQPXVELG.mjs → fa-IRUJY3QI.mjs} +3 -2
- package/dist/fa-IRUJY3QI.mjs.map +1 -0
- package/dist/{fi-UXOVOUGT.mjs → fi-53FBOEVT.mjs} +3 -2
- package/dist/fi-53FBOEVT.mjs.map +1 -0
- package/dist/{fr-6W2T3R7G.mjs → fr-Q5KY7QL6.mjs} +3 -2
- package/dist/fr-Q5KY7QL6.mjs.map +1 -0
- package/dist/{he-65UHPZIU.mjs → he-HJNKULBY.mjs} +3 -2
- package/dist/he-HJNKULBY.mjs.map +1 -0
- package/dist/{hi-SGJIVPTN.mjs → hi-UYZ4X6CR.mjs} +3 -2
- package/dist/hi-UYZ4X6CR.mjs.map +1 -0
- package/dist/{id-EYJJQCS2.mjs → id-UAQMH6U2.mjs} +3 -2
- package/dist/id-UAQMH6U2.mjs.map +1 -0
- package/dist/index.css +48 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +176 -125
- package/dist/index.mjs +556 -781
- package/dist/index.mjs.map +1 -1
- package/dist/{it-IZGQEDO7.mjs → it-C7QEBNFA.mjs} +3 -2
- package/dist/it-C7QEBNFA.mjs.map +1 -0
- package/dist/{ja-SR272JSY.mjs → ja-THS6AOSJ.mjs} +3 -2
- package/dist/ja-THS6AOSJ.mjs.map +1 -0
- package/dist/{ko-YWTXVVXE.mjs → ko-XKK3TWQG.mjs} +3 -2
- package/dist/ko-XKK3TWQG.mjs.map +1 -0
- package/dist/{ms-3K2XSJGM.mjs → ms-GSK7LIF7.mjs} +3 -2
- package/dist/ms-GSK7LIF7.mjs.map +1 -0
- package/dist/{nl-YIGP4SLE.mjs → nl-KUBWITGY.mjs} +3 -2
- package/dist/nl-KUBWITGY.mjs.map +1 -0
- package/dist/{no-IFYIL3ND.mjs → no-ECWZUHT6.mjs} +3 -2
- package/dist/no-ECWZUHT6.mjs.map +1 -0
- package/dist/{pl-6MWSASJR.mjs → pl-PLVWSZWS.mjs} +3 -2
- package/dist/pl-PLVWSZWS.mjs.map +1 -0
- package/dist/{pt-NZNN6WUN.mjs → pt-AL74ZTKB.mjs} +3 -2
- package/dist/pt-AL74ZTKB.mjs.map +1 -0
- package/dist/{ro-NF3SMUJS.mjs → ro-WTPHLHGS.mjs} +3 -2
- package/dist/ro-WTPHLHGS.mjs.map +1 -0
- package/dist/{sv-ZHM7GSTD.mjs → sv-QCLI7SG4.mjs} +3 -2
- package/dist/sv-QCLI7SG4.mjs.map +1 -0
- package/dist/test-utils.d.mts +1 -4
- package/dist/test-utils.mjs +4 -6
- package/dist/test-utils.mjs.map +1 -1
- package/dist/{th-LX4NO5BJ.mjs → th-WCKVZU6U.mjs} +3 -2
- package/dist/th-WCKVZU6U.mjs.map +1 -0
- package/dist/{tr-DZ4GDSRR.mjs → tr-2CAFS2XS.mjs} +3 -2
- package/dist/tr-2CAFS2XS.mjs.map +1 -0
- package/dist/{uk-KC5KVVBY.mjs → uk-TDE4JLCY.mjs} +3 -2
- package/dist/uk-TDE4JLCY.mjs.map +1 -0
- package/dist/{vi-KNCR3OXZ.mjs → vi-KKXZ4PCX.mjs} +3 -2
- package/dist/vi-KKXZ4PCX.mjs.map +1 -0
- package/dist/{zh-M2HV2A27.mjs → zh-VH4XN5PV.mjs} +3 -2
- package/dist/zh-VH4XN5PV.mjs.map +1 -0
- package/package.json +1 -1
- package/src/components/Toolbar.tsx +15 -0
- package/src/components/__tests__/AnnotateReferencesProgressWidget.test.tsx +2 -6
- package/src/components/__tests__/Toolbar.test.tsx +2 -6
- package/src/components/annotation/__tests__/AnnotateToolbar.test.tsx +1 -2
- package/src/components/image-annotation/SvgDrawingCanvas.tsx +4 -7
- package/src/components/modals/ConfigureGenerationStep.tsx +54 -60
- package/src/components/modals/ReferenceWizardModal.tsx +3 -3
- package/src/components/navigation/__tests__/ObservableLink.test.tsx +2 -6
- package/src/components/navigation/__tests__/SimpleNavigation.test.tsx +2 -6
- package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +3 -9
- package/src/components/resource/AnnotateView.tsx +4 -5
- package/src/components/resource/AnnotationHistory.tsx +2 -5
- package/src/components/resource/BrowseView.tsx +2 -3
- package/src/components/resource/HistoryEvent.tsx +3 -3
- package/src/components/resource/__tests__/BrowseView.test.tsx +1 -2
- package/src/components/resource/__tests__/ResourceViewer.mode-switch.test.tsx +8 -8
- package/src/components/resource/event-formatting.ts +22 -19
- package/src/components/resource/panels/__tests__/AssessmentEntry.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/AssessmentPanel.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/AssistSection.test.tsx +0 -2
- package/src/components/resource/panels/__tests__/CommentEntry.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/CommentsPanel.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/HighlightEntry.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/HighlightPanel.annotationProgress.test.tsx +0 -2
- package/src/components/resource/panels/__tests__/ReferenceEntry.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/TagEntry.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/TaggingPanel.test.tsx +1 -2
- package/src/components/settings/__tests__/SettingsPanel.test.tsx +1 -2
- package/src/components/viewers/ImageViewer.tsx +2 -8
- package/src/components/viewers/__tests__/ImageViewer.test.tsx +3 -16
- package/src/features/auth/__tests__/SignInForm.a11y.test.tsx +8 -0
- package/src/features/auth/auth.css +62 -0
- package/src/features/auth/components/SignInForm.tsx +139 -29
- package/src/features/resource-compose/__tests__/ResourceComposePage.test.tsx +2 -6
- package/src/features/resource-discovery/__tests__/ResourceDiscoveryPage.test.tsx +1 -2
- package/src/features/resource-viewer/__tests__/AnnotationCreationPending.test.tsx +1 -2
- package/src/features/resource-viewer/__tests__/AnnotationDeletionIntegration.test.tsx +1 -2
- package/src/features/resource-viewer/__tests__/AnnotationProgressDismissal.test.tsx +1 -2
- package/src/features/resource-viewer/__tests__/BindFlowIntegration.test.tsx +1 -2
- package/src/features/resource-viewer/__tests__/DetectionFlowBug.test.tsx +1 -2
- package/src/features/resource-viewer/__tests__/DetectionFlowIntegration.test.tsx +1 -2
- package/src/features/resource-viewer/__tests__/ResourceMutations.test.tsx +9 -10
- package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +9 -6
- package/src/features/resource-viewer/__tests__/ToastNotifications.test.tsx +2 -12
- package/src/features/resource-viewer/__tests__/YieldFlowIntegration.test.tsx +1 -2
- package/src/features/resource-viewer/__tests__/annotation-progress-flow.test.tsx +16 -6
- package/src/features/resource-viewer/components/ResourceViewerPage.tsx +45 -75
- package/src/styles/core/forms.css +32 -0
- package/src/styles/core/sliders.css +5 -0
- package/translations/ar.json +3 -2
- package/translations/bn.json +3 -2
- package/translations/cs.json +3 -2
- package/translations/da.json +3 -2
- package/translations/de.json +3 -2
- package/translations/el.json +3 -2
- package/translations/en.json +4 -3
- package/translations/es.json +3 -2
- package/translations/fa.json +3 -2
- package/translations/fi.json +3 -2
- package/translations/fr.json +3 -2
- package/translations/he.json +3 -2
- package/translations/hi.json +3 -2
- package/translations/id.json +3 -2
- package/translations/it.json +3 -2
- package/translations/ja.json +3 -2
- package/translations/ko.json +3 -2
- package/translations/ms.json +3 -2
- package/translations/nl.json +3 -2
- package/translations/no.json +3 -2
- package/translations/pl.json +3 -2
- package/translations/pt.json +3 -2
- package/translations/ro.json +3 -2
- package/translations/sv.json +3 -2
- package/translations/th.json +3 -2
- package/translations/tr.json +3 -2
- package/translations/uk.json +3 -2
- package/translations/vi.json +3 -2
- package/translations/zh.json +3 -2
- package/dist/PdfAnnotationCanvas.client-LF6DDTCV.mjs.map +0 -1
- package/dist/ar-3URRW77J.mjs.map +0 -1
- package/dist/bn-DCQD3XZ5.mjs.map +0 -1
- package/dist/chunk-5JZFKRLW.mjs.map +0 -1
- package/dist/chunk-PWIVZQ4X.mjs.map +0 -1
- package/dist/chunk-XMCUHQ2Y.mjs.map +0 -1
- package/dist/cs-23KOZUFE.mjs.map +0 -1
- package/dist/da-OIQ66A42.mjs.map +0 -1
- package/dist/de-FCCLKE2X.mjs.map +0 -1
- package/dist/el-3ADITCGI.mjs.map +0 -1
- package/dist/es-POQEEYIW.mjs.map +0 -1
- package/dist/fa-RQPXVELG.mjs.map +0 -1
- package/dist/fi-UXOVOUGT.mjs.map +0 -1
- package/dist/fr-6W2T3R7G.mjs.map +0 -1
- package/dist/he-65UHPZIU.mjs.map +0 -1
- package/dist/hi-SGJIVPTN.mjs.map +0 -1
- package/dist/id-EYJJQCS2.mjs.map +0 -1
- package/dist/it-IZGQEDO7.mjs.map +0 -1
- package/dist/ja-SR272JSY.mjs.map +0 -1
- package/dist/ko-YWTXVVXE.mjs.map +0 -1
- package/dist/ms-3K2XSJGM.mjs.map +0 -1
- package/dist/nl-YIGP4SLE.mjs.map +0 -1
- package/dist/no-IFYIL3ND.mjs.map +0 -1
- package/dist/pl-6MWSASJR.mjs.map +0 -1
- package/dist/pt-NZNN6WUN.mjs.map +0 -1
- package/dist/ro-NF3SMUJS.mjs.map +0 -1
- package/dist/sv-ZHM7GSTD.mjs.map +0 -1
- package/dist/th-LX4NO5BJ.mjs.map +0 -1
- package/dist/tr-DZ4GDSRR.mjs.map +0 -1
- package/dist/uk-KC5KVVBY.mjs.map +0 -1
- package/dist/vi-KNCR3OXZ.mjs.map +0 -1
- package/dist/zh-M2HV2A27.mjs.map +0 -1
- /package/dist/{chunk-4RMWYJUJ.mjs.map → chunk-OL5UST25.mjs.map} +0 -0
- /package/dist/{en-LNW2A3RA.mjs.map → en-IUV4ZXKH.mjs.map} +0 -0
|
@@ -22,7 +22,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
|
22
22
|
import { render, screen, waitFor } from '@testing-library/react';
|
|
23
23
|
import { act } from 'react';
|
|
24
24
|
import { useMarkFlow } from '../../../hooks/useMarkFlow';
|
|
25
|
-
import { EventBusProvider,
|
|
25
|
+
import { EventBusProvider, useEventBus } from '../../../contexts/EventBusContext';
|
|
26
26
|
import { ApiClientProvider } from '../../../contexts/ApiClientContext';
|
|
27
27
|
import { AuthTokenProvider } from '../../../contexts/AuthTokenContext';
|
|
28
28
|
import { SSEClient } from '@semiont/api-client';
|
|
@@ -43,7 +43,6 @@ describe('Detection Progress Dismissal Bug', () => {
|
|
|
43
43
|
const rUri = resourceId('test');
|
|
44
44
|
|
|
45
45
|
beforeEach(() => {
|
|
46
|
-
resetEventBusForTesting();
|
|
47
46
|
vi.clearAllMocks();
|
|
48
47
|
|
|
49
48
|
mockStream = {
|
|
@@ -18,7 +18,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
|
18
18
|
import { render, waitFor } from '@testing-library/react';
|
|
19
19
|
import { act } from 'react';
|
|
20
20
|
import { useBindFlow } from '../../../hooks/useBindFlow';
|
|
21
|
-
import { EventBusProvider, useEventBus
|
|
21
|
+
import { EventBusProvider, useEventBus } from '../../../contexts/EventBusContext';
|
|
22
22
|
import { ApiClientProvider } from '../../../contexts/ApiClientContext';
|
|
23
23
|
import { AuthTokenProvider } from '../../../contexts/AuthTokenContext';
|
|
24
24
|
import { SSEClient } from '@semiont/api-client';
|
|
@@ -42,7 +42,6 @@ describe('Bind Flow - Body Update Integration', () => {
|
|
|
42
42
|
|
|
43
43
|
beforeEach(() => {
|
|
44
44
|
vi.clearAllMocks();
|
|
45
|
-
resetEventBusForTesting();
|
|
46
45
|
|
|
47
46
|
bindAnnotationSpy = vi.fn().mockImplementation((_rId: any, annId: any, _req: any, opts: any) => {
|
|
48
47
|
queueMicrotask(() => opts.eventBus.get('bind:finished').next({ annotationId: annId }));
|
|
@@ -14,7 +14,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
|
14
14
|
import { render, screen, waitFor } from '@testing-library/react';
|
|
15
15
|
import { act } from 'react';
|
|
16
16
|
import { useMarkFlow } from '../../../hooks/useMarkFlow';
|
|
17
|
-
import { EventBusProvider, useEventBus
|
|
17
|
+
import { EventBusProvider, useEventBus } from '../../../contexts/EventBusContext';
|
|
18
18
|
import { ApiClientProvider } from '../../../contexts/ApiClientContext';
|
|
19
19
|
import { AuthTokenProvider } from '../../../contexts/AuthTokenContext';
|
|
20
20
|
import { SSEClient } from '@semiont/api-client';
|
|
@@ -31,7 +31,6 @@ vi.mock('../../../components/Toast', () => ({
|
|
|
31
31
|
|
|
32
32
|
describe('REPRODUCING BUG: Detection state not updating', () => {
|
|
33
33
|
beforeEach(() => {
|
|
34
|
-
resetEventBusForTesting();
|
|
35
34
|
vi.clearAllMocks();
|
|
36
35
|
|
|
37
36
|
// Minimal mock - SSE streams not needed for this test
|
|
@@ -26,7 +26,7 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
|
26
26
|
import { render, screen, waitFor } from '@testing-library/react';
|
|
27
27
|
import { act } from 'react';
|
|
28
28
|
import { useMarkFlow } from '../../../hooks/useMarkFlow';
|
|
29
|
-
import { EventBusProvider, useEventBus
|
|
29
|
+
import { EventBusProvider, useEventBus } from '../../../contexts/EventBusContext';
|
|
30
30
|
import { ApiClientProvider } from '../../../contexts/ApiClientContext';
|
|
31
31
|
import { AuthTokenProvider } from '../../../contexts/AuthTokenContext';
|
|
32
32
|
import { SSEClient } from '@semiont/api-client';
|
|
@@ -60,7 +60,6 @@ describe('Detection Flow - Feature Integration', () => {
|
|
|
60
60
|
|
|
61
61
|
beforeEach(() => {
|
|
62
62
|
vi.clearAllMocks();
|
|
63
|
-
resetEventBusForTesting();
|
|
64
63
|
|
|
65
64
|
// Create fresh mock stream for each test
|
|
66
65
|
mockStream = createMockSSEStream();
|
|
@@ -27,7 +27,7 @@ import { act } from 'react';
|
|
|
27
27
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
28
28
|
import { SemiontApiClient } from '@semiont/api-client';
|
|
29
29
|
import { resourceId, accessToken } from '@semiont/core';
|
|
30
|
-
import { EventBusProvider, useEventBus
|
|
30
|
+
import { EventBusProvider, useEventBus } from '../../../contexts/EventBusContext';
|
|
31
31
|
import { useEventSubscriptions } from '../../../contexts/useEventSubscription';
|
|
32
32
|
import { ApiClientProvider } from '../../../contexts/ApiClientContext';
|
|
33
33
|
import { AuthTokenProvider } from '../../../contexts/AuthTokenContext';
|
|
@@ -101,15 +101,15 @@ function renderHarness() {
|
|
|
101
101
|
});
|
|
102
102
|
|
|
103
103
|
render(
|
|
104
|
-
<
|
|
105
|
-
<
|
|
106
|
-
<
|
|
107
|
-
<
|
|
104
|
+
<EventBusProvider>
|
|
105
|
+
<AuthTokenProvider token={TEST_TOKEN}>
|
|
106
|
+
<ApiClientProvider baseUrl={BASE_URL}>
|
|
107
|
+
<QueryClientProvider client={queryClient}>
|
|
108
108
|
<ResourceMutationHarness onEventBus={(eventBus) => { capturedEventBus = eventBus; }} />
|
|
109
|
-
</
|
|
110
|
-
</
|
|
111
|
-
</
|
|
112
|
-
</
|
|
109
|
+
</QueryClientProvider>
|
|
110
|
+
</ApiClientProvider>
|
|
111
|
+
</AuthTokenProvider>
|
|
112
|
+
</EventBusProvider>
|
|
113
113
|
);
|
|
114
114
|
|
|
115
115
|
const emit = <K extends keyof EventMap>(event: K, payload: EventMap[K]) => {
|
|
@@ -128,7 +128,6 @@ describe('Resource mutations — hooks hoisted to top level', () => {
|
|
|
128
128
|
|
|
129
129
|
beforeEach(() => {
|
|
130
130
|
vi.clearAllMocks();
|
|
131
|
-
resetEventBusForTesting();
|
|
132
131
|
|
|
133
132
|
generateCloneTokenSpy = vi
|
|
134
133
|
.spyOn(SemiontApiClient.prototype, 'generateCloneToken')
|
|
@@ -11,7 +11,7 @@ import React from 'react';
|
|
|
11
11
|
import { ResourceViewerPage } from '../components/ResourceViewerPage';
|
|
12
12
|
import type { ResourceViewerPageProps } from '../components/ResourceViewerPage';
|
|
13
13
|
// Import directly from context file to bypass mocked barrel export
|
|
14
|
-
import { EventBusProvider
|
|
14
|
+
import { EventBusProvider } from '../../../contexts/EventBusContext';
|
|
15
15
|
import { ApiClientProvider } from '../../../contexts/ApiClientContext';
|
|
16
16
|
import { AuthTokenProvider } from '../../../contexts/AuthTokenContext';
|
|
17
17
|
import { ToastProvider } from '../../../components/Toast';
|
|
@@ -41,6 +41,7 @@ vi.mock('../../../lib/api-hooks', () => ({
|
|
|
41
41
|
useResources: () => ({
|
|
42
42
|
annotations: { useQuery: () => ({ data: { annotations: [] } }) },
|
|
43
43
|
referencedBy: { useQuery: () => ({ data: { referencedBy: [] }, isLoading: false }) },
|
|
44
|
+
mediaToken: { useQuery: () => ({ data: { token: 'mock-media-token' }, isLoading: false }) },
|
|
44
45
|
update: { useMutation: () => ({ mutateAsync: vi.fn() }) },
|
|
45
46
|
generateCloneToken: { useMutation: () => ({ mutateAsync: vi.fn() }) },
|
|
46
47
|
}),
|
|
@@ -86,7 +87,7 @@ useDebouncedCallback: (fn: any) => fn,
|
|
|
86
87
|
announceResourceLoading: vi.fn(),
|
|
87
88
|
announceResourceLoaded: vi.fn(),
|
|
88
89
|
}),
|
|
89
|
-
// Don't mock EventBusProvider, useEventBus
|
|
90
|
+
// Don't mock EventBusProvider, useEventBus - let actual pass through via ...actual
|
|
90
91
|
useEventSubscriptions: vi.fn(),
|
|
91
92
|
useResourceAnnotations: () => ({
|
|
92
93
|
clearNewAnnotationId: vi.fn(),
|
|
@@ -153,6 +154,7 @@ const createMockProps = (overrides?: Partial<ResourceViewerPageProps>): Resource
|
|
|
153
154
|
Link: ({ children }: any) => <a>{children}</a>,
|
|
154
155
|
routes: {},
|
|
155
156
|
refetchDocument: vi.fn().mockResolvedValue(undefined),
|
|
157
|
+
streamStatus: 'connected' as const,
|
|
156
158
|
ToolbarPanels: ({ children, activePanel }: any) =>
|
|
157
159
|
!activePanel ? null : <div data-testid="toolbar-panels">{children}</div>,
|
|
158
160
|
...overrides,
|
|
@@ -164,9 +166,11 @@ const renderWithProviders = (ui: React.ReactElement) => {
|
|
|
164
166
|
<ThemeProvider>
|
|
165
167
|
<ToastProvider>
|
|
166
168
|
<AuthTokenProvider token={null}>
|
|
167
|
-
<
|
|
168
|
-
<
|
|
169
|
-
|
|
169
|
+
<EventBusProvider>
|
|
170
|
+
<ApiClientProvider baseUrl="http://localhost:4000">
|
|
171
|
+
{ui}
|
|
172
|
+
</ApiClientProvider>
|
|
173
|
+
</EventBusProvider>
|
|
170
174
|
</AuthTokenProvider>
|
|
171
175
|
</ToastProvider>
|
|
172
176
|
</ThemeProvider>
|
|
@@ -175,7 +179,6 @@ const renderWithProviders = (ui: React.ReactElement) => {
|
|
|
175
179
|
|
|
176
180
|
describe('ResourceViewerPage', () => {
|
|
177
181
|
beforeEach(() => {
|
|
178
|
-
resetEventBusForTesting();
|
|
179
182
|
});
|
|
180
183
|
|
|
181
184
|
describe('Basic Rendering', () => {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
18
18
|
import { render, waitFor, act } from '@testing-library/react';
|
|
19
|
-
import { EventBusProvider,
|
|
19
|
+
import { EventBusProvider, useEventBus } from '../../../contexts/EventBusContext';
|
|
20
20
|
import { ApiClientProvider } from '../../../contexts/ApiClientContext';
|
|
21
21
|
import { AuthTokenProvider } from '../../../contexts/AuthTokenContext';
|
|
22
22
|
import { resourceId } from '@semiont/core';
|
|
@@ -41,7 +41,6 @@ describe('Toast Notifications - Verifies Toast Integration', () => {
|
|
|
41
41
|
const rUri = resourceId('test');
|
|
42
42
|
|
|
43
43
|
beforeEach(() => {
|
|
44
|
-
resetEventBusForTesting();
|
|
45
44
|
mockShowSuccess.mockClear();
|
|
46
45
|
mockShowError.mockClear();
|
|
47
46
|
});
|
|
@@ -115,17 +114,8 @@ describe('Toast Notifications - Verifies Toast Integration', () => {
|
|
|
115
114
|
// Emit detection failed event
|
|
116
115
|
act(() => {
|
|
117
116
|
eventBusInstance.get('mark:assist-failed').next({
|
|
118
|
-
type: 'job.failed' as const,
|
|
119
117
|
resourceId: 'test' as any,
|
|
120
|
-
|
|
121
|
-
id: 'evt-1' as any,
|
|
122
|
-
timestamp: new Date().toISOString(),
|
|
123
|
-
version: 1,
|
|
124
|
-
payload: {
|
|
125
|
-
jobId: 'job-1' as any,
|
|
126
|
-
jobType: 'detection',
|
|
127
|
-
error: 'AI service unavailable',
|
|
128
|
-
},
|
|
118
|
+
message: 'AI service unavailable',
|
|
129
119
|
});
|
|
130
120
|
});
|
|
131
121
|
|
|
@@ -22,7 +22,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
|
22
22
|
import { render, screen, waitFor } from '@testing-library/react';
|
|
23
23
|
import { act } from 'react';
|
|
24
24
|
import { useYieldFlow } from '../../../hooks/useYieldFlow';
|
|
25
|
-
import { EventBusProvider, useEventBus
|
|
25
|
+
import { EventBusProvider, useEventBus } from '../../../contexts/EventBusContext';
|
|
26
26
|
import { ApiClientProvider } from '../../../contexts/ApiClientContext';
|
|
27
27
|
import { AuthTokenProvider } from '../../../contexts/AuthTokenContext';
|
|
28
28
|
import { useBindFlow } from '../../../hooks/useBindFlow';
|
|
@@ -58,7 +58,6 @@ describe('Generation Flow - Feature Integration', () => {
|
|
|
58
58
|
|
|
59
59
|
beforeEach(() => {
|
|
60
60
|
vi.clearAllMocks();
|
|
61
|
-
resetEventBusForTesting();
|
|
62
61
|
|
|
63
62
|
// Create fresh mock stream for each test
|
|
64
63
|
mockStream = createMockGenerationStream();
|
|
@@ -28,7 +28,7 @@ import userEvent from '@testing-library/user-event';
|
|
|
28
28
|
import { act } from 'react';
|
|
29
29
|
import { HighlightPanel } from '../../../components/resource/panels/HighlightPanel';
|
|
30
30
|
import { useMarkFlow } from '../../../hooks/useMarkFlow';
|
|
31
|
-
import { EventBusProvider,
|
|
31
|
+
import { EventBusProvider, useEventBus } from '../../../contexts/EventBusContext';
|
|
32
32
|
import { ApiClientProvider } from '../../../contexts/ApiClientContext';
|
|
33
33
|
import { AuthTokenProvider } from '../../../contexts/AuthTokenContext';
|
|
34
34
|
import { SSEClient } from '@semiont/api-client';
|
|
@@ -71,7 +71,11 @@ vi.mock('../../../contexts/TranslationContext', () => ({
|
|
|
71
71
|
|
|
72
72
|
// Create a mock SSE stream that we can control
|
|
73
73
|
class MockSSEStream {
|
|
74
|
-
|
|
74
|
+
private eventBus: any = null;
|
|
75
|
+
|
|
76
|
+
setEventBus(eventBus: any) {
|
|
77
|
+
this.eventBus = eventBus;
|
|
78
|
+
}
|
|
75
79
|
|
|
76
80
|
close() {
|
|
77
81
|
// Mock close method
|
|
@@ -133,10 +137,18 @@ describe('Detection Progress Flow Integration (Layer 3)', () => {
|
|
|
133
137
|
let mockStream: MockSSEStream;
|
|
134
138
|
const rUri = 'https://example.com/resources/test-resource-1';
|
|
135
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
|
+
|
|
136
147
|
// Helper to render test harness with composition
|
|
137
148
|
const renderDetectionFlow = () => {
|
|
138
149
|
return render(
|
|
139
150
|
<EventBusProvider>
|
|
151
|
+
<EventBusCapturer />
|
|
140
152
|
<AuthTokenProvider token={null}>
|
|
141
153
|
<ApiClientProvider baseUrl="http://localhost:4000">
|
|
142
154
|
<DetectionFlowTestHarness
|
|
@@ -150,12 +162,10 @@ describe('Detection Progress Flow Integration (Layer 3)', () => {
|
|
|
150
162
|
};
|
|
151
163
|
|
|
152
164
|
beforeEach(() => {
|
|
153
|
-
// Reset event bus for test isolation
|
|
154
|
-
const eventBus = resetEventBusForTesting();
|
|
155
165
|
vi.clearAllMocks();
|
|
156
166
|
|
|
157
|
-
//
|
|
158
|
-
mockStream = new MockSSEStream(
|
|
167
|
+
// Create fresh stream for each test
|
|
168
|
+
mockStream = new MockSSEStream();
|
|
159
169
|
|
|
160
170
|
// Spy on SSEClient prototype methods to inject mock stream
|
|
161
171
|
vi.spyOn(SSEClient.prototype, 'markHighlights').mockReturnValue(mockStream as any);
|
|
@@ -9,7 +9,7 @@ import React, { useState, useEffect, useCallback, useMemo } from 'react';
|
|
|
9
9
|
import { useQueryClient } from '@tanstack/react-query';
|
|
10
10
|
import type { components, ResourceId, ResourceEvent, GatheredContext } from '@semiont/core';
|
|
11
11
|
import { annotationId } from '@semiont/core';
|
|
12
|
-
import { getLanguage, getPrimaryRepresentation, getPrimaryMediaType } from '@semiont/api-client';
|
|
12
|
+
import { getLanguage, getPrimaryRepresentation, getPrimaryMediaType, getMimeCategory } from '@semiont/api-client';
|
|
13
13
|
import { ANNOTATORS } from '@semiont/react-ui';
|
|
14
14
|
import { ErrorBoundary } from '@semiont/react-ui';
|
|
15
15
|
import { AnnotationHistory } from '@semiont/react-ui';
|
|
@@ -20,15 +20,16 @@ import { JsonLdPanel } from '@semiont/react-ui';
|
|
|
20
20
|
import { Toolbar } from '@semiont/react-ui';
|
|
21
21
|
import { useResourceLoadingAnnouncements } from '@semiont/react-ui';
|
|
22
22
|
import { ResourceViewer } from '@semiont/react-ui';
|
|
23
|
+
import { useObservable } from '@semiont/react-ui';
|
|
23
24
|
import { QUERY_KEYS } from '../../../lib/query-keys';
|
|
24
25
|
import { useResources, useEntityTypes } from '../../../lib/api-hooks';
|
|
25
26
|
import { useResourceContent } from '../../../hooks/useResourceContent';
|
|
27
|
+
import { useMediaToken } from '../../../hooks/useMediaToken';
|
|
26
28
|
import { useToast } from '../../../components/Toast';
|
|
27
29
|
import { useTheme } from '../../../contexts/ThemeContext';
|
|
28
30
|
import { useLineNumbers } from '../../../hooks/useLineNumbers';
|
|
29
31
|
import { useHoverDelay } from '../../../hooks/useHoverDelay';
|
|
30
32
|
import { useResourceEvents } from '../../../hooks/useResourceEvents';
|
|
31
|
-
import { useDebouncedCallback } from '../../../hooks/useDebounce';
|
|
32
33
|
import { useOpenResources } from '../../../contexts/OpenResourcesContext';
|
|
33
34
|
// Import EventBus hooks directly from context to avoid mocking issues in tests
|
|
34
35
|
import { useEventBus } from '../../../contexts/EventBusContext';
|
|
@@ -38,6 +39,7 @@ import { useApiClient } from '../../../contexts/ApiClientContext';
|
|
|
38
39
|
import { useBindFlow } from '../../../hooks/useBindFlow';
|
|
39
40
|
import { useMarkFlow } from '../../../hooks/useMarkFlow';
|
|
40
41
|
import { useBeckonFlow } from '../../../hooks/useBeckonFlow';
|
|
42
|
+
import type { StreamStatus } from '../../../hooks/useResourceEvents';
|
|
41
43
|
import { usePanelBrowse } from '../../../hooks/usePanelBrowse';
|
|
42
44
|
import { useYieldFlow } from '../../../hooks/useYieldFlow';
|
|
43
45
|
import { useContextGatherFlow } from '../../../hooks/useContextGatherFlow';
|
|
@@ -83,6 +85,11 @@ export interface ResourceViewerPageProps {
|
|
|
83
85
|
* Callback to refetch document from parent
|
|
84
86
|
*/
|
|
85
87
|
refetchDocument: () => Promise<unknown>;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* SSE attention stream connection status for the active workspace
|
|
91
|
+
*/
|
|
92
|
+
streamStatus: StreamStatus;
|
|
86
93
|
}
|
|
87
94
|
|
|
88
95
|
/**
|
|
@@ -120,6 +127,7 @@ export function ResourceViewerPage({
|
|
|
120
127
|
routes,
|
|
121
128
|
ToolbarPanels,
|
|
122
129
|
refetchDocument,
|
|
130
|
+
streamStatus,
|
|
123
131
|
}: ResourceViewerPageProps) {
|
|
124
132
|
// Translations
|
|
125
133
|
const tw = useTranslations('ReferenceWizard');
|
|
@@ -127,7 +135,7 @@ export function ResourceViewerPage({
|
|
|
127
135
|
// Get unified event bus for subscribing to UI events
|
|
128
136
|
const eventBus = useEventBus();
|
|
129
137
|
const client = useApiClient();
|
|
130
|
-
const queryClient = useQueryClient();
|
|
138
|
+
const queryClient = useQueryClient(); // retained for non-store queries (events log)
|
|
131
139
|
|
|
132
140
|
// UI state hooks
|
|
133
141
|
const { showError, showSuccess } = useToast();
|
|
@@ -141,10 +149,23 @@ export function ResourceViewerPage({
|
|
|
141
149
|
const resources = useResources();
|
|
142
150
|
const entityTypesAPI = useEntityTypes();
|
|
143
151
|
|
|
144
|
-
//
|
|
145
|
-
const
|
|
152
|
+
// Determine MIME category to choose content path
|
|
153
|
+
const resourceMediaType = getPrimaryMediaType(resource) || 'text/plain';
|
|
154
|
+
const isBinary = getMimeCategory(resourceMediaType) === 'image';
|
|
155
|
+
|
|
156
|
+
// Text path: fetch and decode representation (disabled for binary — mediaToken path handles those)
|
|
157
|
+
const { content: textContent, loading: textLoading } = useResourceContent(rUri, resource, !isBinary);
|
|
146
158
|
|
|
147
|
-
|
|
159
|
+
// Binary path: fetch short-lived media token, construct URL
|
|
160
|
+
const { token: mediaToken, loading: mediaTokenLoading } = useMediaToken(rUri);
|
|
161
|
+
const binaryContent = (isBinary && mediaToken && client)
|
|
162
|
+
? `${client.baseUrl}/api/resources/${rUri}?token=${mediaToken}`
|
|
163
|
+
: '';
|
|
164
|
+
|
|
165
|
+
const content = isBinary ? binaryContent : textContent;
|
|
166
|
+
const contentLoading = isBinary ? mediaTokenLoading : textLoading;
|
|
167
|
+
|
|
168
|
+
const annotationsData = useObservable(client.stores.annotations.listForResource(rUri));
|
|
148
169
|
const annotations = useMemo(
|
|
149
170
|
() => annotationsData?.annotations || [],
|
|
150
171
|
[annotationsData?.annotations]
|
|
@@ -165,7 +186,7 @@ export function ResourceViewerPage({
|
|
|
165
186
|
generationProgress,
|
|
166
187
|
onGenerateDocument,
|
|
167
188
|
} = useYieldFlow(locale, rUri, clearNewAnnotationId);
|
|
168
|
-
const { gatherContext, gatherLoading, gatherError } = useContextGatherFlow(
|
|
189
|
+
const { gatherContext, gatherLoading, gatherError } = useContextGatherFlow({ resourceId: rUri });
|
|
169
190
|
|
|
170
191
|
// Wizard state — driven by bind:initiate from ReferenceEntry
|
|
171
192
|
const [wizardOpen, setWizardOpen] = useState(false);
|
|
@@ -183,7 +204,7 @@ export function ResourceViewerPage({
|
|
|
183
204
|
setWizardOpen(true);
|
|
184
205
|
|
|
185
206
|
// Trigger context gathering
|
|
186
|
-
eventBus.get('gather:requested').next({ annotationId: event.annotationId, resourceId: event.resourceId });
|
|
207
|
+
eventBus.get('gather:requested').next({ correlationId: crypto.randomUUID(), annotationId: event.annotationId, resourceId: event.resourceId });
|
|
187
208
|
});
|
|
188
209
|
return () => subscription.unsubscribe();
|
|
189
210
|
}, [eventBus]);
|
|
@@ -241,15 +262,6 @@ export function ResourceViewerPage({
|
|
|
241
262
|
});
|
|
242
263
|
}, []); // eventBus is stable singleton
|
|
243
264
|
|
|
244
|
-
// Debounced invalidation for real-time events
|
|
245
|
-
const debouncedInvalidateAnnotations = useDebouncedCallback(
|
|
246
|
-
() => {
|
|
247
|
-
queryClient.invalidateQueries({ queryKey: QUERY_KEYS.resources.annotations(rUri) });
|
|
248
|
-
queryClient.invalidateQueries({ queryKey: QUERY_KEYS.resources.events(rUri) });
|
|
249
|
-
},
|
|
250
|
-
500
|
|
251
|
-
);
|
|
252
|
-
|
|
253
265
|
// Add resource to open tabs when it loads
|
|
254
266
|
useEffect(() => {
|
|
255
267
|
if (resource && rUri) {
|
|
@@ -262,56 +274,22 @@ export function ResourceViewerPage({
|
|
|
262
274
|
}, [resource, rUri, addResource]);
|
|
263
275
|
|
|
264
276
|
// Real-time document events (SSE)
|
|
277
|
+
// Annotation updates are handled by AnnotationStore reacting to EventBus events.
|
|
278
|
+
// Callbacks here only handle non-annotation side effects.
|
|
265
279
|
useResourceEvents({
|
|
266
280
|
rUri,
|
|
267
281
|
autoConnect: true,
|
|
268
282
|
|
|
269
|
-
// Annotation events - use debounced invalidation to batch rapid updates
|
|
270
283
|
onAnnotationAdded: useCallback((_event: any) => {
|
|
271
|
-
|
|
272
|
-
|
|
284
|
+
// Store handles annotation refresh; events log needs explicit invalidation
|
|
285
|
+
queryClient.invalidateQueries({ queryKey: QUERY_KEYS.resources.events(rUri) });
|
|
286
|
+
}, [queryClient, rUri]),
|
|
273
287
|
|
|
274
288
|
onAnnotationRemoved: useCallback((_event: any) => {
|
|
275
|
-
|
|
276
|
-
}, [
|
|
277
|
-
|
|
278
|
-
onAnnotationBodyUpdated: useCallback((event: any) => {
|
|
279
|
-
// Optimistically update annotations cache with body operations
|
|
280
|
-
queryClient.setQueryData(QUERY_KEYS.resources.annotations(rUri), (old: any) => {
|
|
281
|
-
if (!old) return old;
|
|
282
|
-
return {
|
|
283
|
-
...old,
|
|
284
|
-
annotations: old.annotations.map((annotation: any) => {
|
|
285
|
-
if (annotation.id === event.payload.annotationId) {
|
|
286
|
-
let bodyArray = Array.isArray(annotation.body) ? [...annotation.body] : [];
|
|
287
|
-
|
|
288
|
-
for (const op of event.payload.operations || []) {
|
|
289
|
-
if (op.op === 'add') {
|
|
290
|
-
bodyArray.push(op.item);
|
|
291
|
-
} else if (op.op === 'remove') {
|
|
292
|
-
bodyArray = bodyArray.filter((item: any) =>
|
|
293
|
-
JSON.stringify(item) !== JSON.stringify(op.item)
|
|
294
|
-
);
|
|
295
|
-
} else if (op.op === 'replace') {
|
|
296
|
-
const index = bodyArray.findIndex((item: any) =>
|
|
297
|
-
JSON.stringify(item) === JSON.stringify(op.oldItem)
|
|
298
|
-
);
|
|
299
|
-
if (index !== -1) {
|
|
300
|
-
bodyArray[index] = op.newItem;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
return {
|
|
306
|
-
...annotation,
|
|
307
|
-
body: bodyArray,
|
|
308
|
-
};
|
|
309
|
-
}
|
|
310
|
-
return annotation;
|
|
311
|
-
}),
|
|
312
|
-
};
|
|
313
|
-
});
|
|
289
|
+
queryClient.invalidateQueries({ queryKey: QUERY_KEYS.resources.events(rUri) });
|
|
290
|
+
}, [queryClient, rUri]),
|
|
314
291
|
|
|
292
|
+
onAnnotationBodyUpdated: useCallback((_event: any) => {
|
|
315
293
|
queryClient.invalidateQueries({ queryKey: QUERY_KEYS.resources.events(rUri) });
|
|
316
294
|
}, [queryClient, rUri]),
|
|
317
295
|
|
|
@@ -319,25 +297,21 @@ export function ResourceViewerPage({
|
|
|
319
297
|
onDocumentArchived: useCallback((_event: any) => {
|
|
320
298
|
refetchDocument();
|
|
321
299
|
showSuccess('This document has been archived');
|
|
322
|
-
|
|
323
|
-
}, [refetchDocument, showSuccess, debouncedInvalidateAnnotations]),
|
|
300
|
+
}, [refetchDocument, showSuccess]),
|
|
324
301
|
|
|
325
302
|
onDocumentUnarchived: useCallback((_event: any) => {
|
|
326
303
|
refetchDocument();
|
|
327
304
|
showSuccess('This document has been unarchived');
|
|
328
|
-
|
|
329
|
-
}, [refetchDocument, showSuccess, debouncedInvalidateAnnotations]),
|
|
305
|
+
}, [refetchDocument, showSuccess]),
|
|
330
306
|
|
|
331
307
|
// Entity tag events
|
|
332
308
|
onEntityTagAdded: useCallback((_event: any) => {
|
|
333
309
|
refetchDocument();
|
|
334
|
-
|
|
335
|
-
}, [refetchDocument, debouncedInvalidateAnnotations]),
|
|
310
|
+
}, [refetchDocument]),
|
|
336
311
|
|
|
337
312
|
onEntityTagRemoved: useCallback((_event: any) => {
|
|
338
313
|
refetchDocument();
|
|
339
|
-
|
|
340
|
-
}, [refetchDocument, debouncedInvalidateAnnotations]),
|
|
314
|
+
}, [refetchDocument]),
|
|
341
315
|
|
|
342
316
|
onError: useCallback((error: any) => {
|
|
343
317
|
console.error('[RealTime] Event stream error:', error);
|
|
@@ -386,8 +360,7 @@ export function ResourceViewerPage({
|
|
|
386
360
|
|
|
387
361
|
const handleAnnotationAdded = useCallback((event: Extract<ResourceEvent, { type: 'annotation.added' }>) => {
|
|
388
362
|
triggerSparkleAnimation(event.payload.annotation.id);
|
|
389
|
-
|
|
390
|
-
}, [triggerSparkleAnimation, debouncedInvalidateAnnotations]);
|
|
363
|
+
}, [triggerSparkleAnimation]);
|
|
391
364
|
|
|
392
365
|
const handleAnnotationCreateFailed = useCallback(() => showError('Failed to create annotation'), [showError]);
|
|
393
366
|
const handleAnnotationDeleteFailed = useCallback(() => showError('Failed to delete annotation'), [showError]);
|
|
@@ -399,13 +372,11 @@ export function ResourceViewerPage({
|
|
|
399
372
|
const handleSettingsThemeChanged = useCallback(({ theme }: { theme: any }) => setTheme(theme), [setTheme]);
|
|
400
373
|
|
|
401
374
|
const handleDetectionComplete = useCallback(() => {
|
|
402
|
-
// Toast notification is handled by useMarkFlow
|
|
403
|
-
queryClient.invalidateQueries({ queryKey: QUERY_KEYS.resources.annotations(rUri) });
|
|
375
|
+
// Toast notification is handled by useMarkFlow; store handles annotation refresh
|
|
404
376
|
queryClient.invalidateQueries({ queryKey: QUERY_KEYS.resources.events(rUri) });
|
|
405
377
|
}, [queryClient, rUri]);
|
|
406
378
|
const handleDetectionFailed = useCallback(() => {
|
|
407
|
-
// Error notification is handled by useMarkFlow
|
|
408
|
-
queryClient.invalidateQueries({ queryKey: QUERY_KEYS.resources.annotations(rUri) });
|
|
379
|
+
// Error notification is handled by useMarkFlow; store handles annotation refresh
|
|
409
380
|
queryClient.invalidateQueries({ queryKey: QUERY_KEYS.resources.events(rUri) });
|
|
410
381
|
}, [queryClient, rUri]);
|
|
411
382
|
const handleGenerationComplete = useCallback(() => {
|
|
@@ -441,7 +412,6 @@ export function ResourceViewerPage({
|
|
|
441
412
|
'yield:clone': handleResourceClone,
|
|
442
413
|
'beckon:sparkle': handleAnnotationSparkle,
|
|
443
414
|
'mark:added': handleAnnotationAdded,
|
|
444
|
-
'mark:removed': debouncedInvalidateAnnotations,
|
|
445
415
|
'mark:create-failed': handleAnnotationCreateFailed,
|
|
446
416
|
'mark:delete-failed': handleAnnotationDeleteFailed,
|
|
447
417
|
'mark:body-updated': handleAnnotateBodyUpdated,
|
|
@@ -656,7 +626,7 @@ export function ResourceViewerPage({
|
|
|
656
626
|
{/* Collaboration Panel */}
|
|
657
627
|
{activePanel === 'collaboration' && (
|
|
658
628
|
<CollaborationPanel
|
|
659
|
-
isConnected={
|
|
629
|
+
isConnected={streamStatus === 'connected'}
|
|
660
630
|
eventCount={0}
|
|
661
631
|
/>
|
|
662
632
|
)}
|
|
@@ -252,3 +252,35 @@
|
|
|
252
252
|
/* Note: Basic form controls (.semiont-textarea, .semiont-select, .semiont-checkbox)
|
|
253
253
|
are now defined in /styles/core/ as they are fundamental UI elements.
|
|
254
254
|
See: core/textareas.css, core/selects.css, core/checkboxes.css */
|
|
255
|
+
|
|
256
|
+
/* Scrollable form body — keeps form within viewport height */
|
|
257
|
+
.semiont-form--scrollable {
|
|
258
|
+
overflow-y: auto;
|
|
259
|
+
max-height: 70vh;
|
|
260
|
+
padding-right: 0.25rem;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/* Inline row — lays out multiple fields side by side */
|
|
264
|
+
.semiont-form__inline-row {
|
|
265
|
+
display: flex;
|
|
266
|
+
flex-direction: row;
|
|
267
|
+
gap: 0.75rem;
|
|
268
|
+
align-items: flex-start;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/* Inline field variant — participates in an inline row */
|
|
272
|
+
.semiont-form__field--inline {
|
|
273
|
+
flex-shrink: 0;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/* Grow modifier — field takes remaining space */
|
|
277
|
+
.semiont-form__field--grow {
|
|
278
|
+
flex: 1;
|
|
279
|
+
min-width: 0;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* Narrow modifier — fixed compact width for short numeric inputs */
|
|
283
|
+
.semiont-form__field--narrow {
|
|
284
|
+
width: 5.5rem;
|
|
285
|
+
flex-shrink: 0;
|
|
286
|
+
}
|
|
@@ -216,6 +216,11 @@
|
|
|
216
216
|
color: var(--semiont-text-secondary);
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
+
/* Small labels variant — reduced font size for compact inline contexts */
|
|
220
|
+
.semiont-slider__labels--small {
|
|
221
|
+
font-size: 0.6875rem;
|
|
222
|
+
}
|
|
223
|
+
|
|
219
224
|
.semiont-slider__value {
|
|
220
225
|
text-align: center;
|
|
221
226
|
font-size: var(--semiont-text-sm);
|
package/translations/ar.json
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
"resourceInfo": "معلومات المورد",
|
|
6
6
|
"collaboration": "التعاون",
|
|
7
7
|
"userAccount": "حساب المستخدم",
|
|
8
|
-
"settings": "الإعدادات"
|
|
8
|
+
"settings": "الإعدادات",
|
|
9
|
+
"knowledgeBase": "قاعدة المعرفة"
|
|
9
10
|
},
|
|
10
11
|
"ResourceInfoPanel": {
|
|
11
12
|
"title": "معلومات المورد",
|
|
@@ -373,4 +374,4 @@
|
|
|
373
374
|
"searching": "جاري البحث...",
|
|
374
375
|
"search": "بحث"
|
|
375
376
|
}
|
|
376
|
-
}
|
|
377
|
+
}
|
package/translations/bn.json
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
"resourceInfo": "সম্পদের তথ্য",
|
|
6
6
|
"collaboration": "সহযোগিতা",
|
|
7
7
|
"userAccount": "ব্যবহারকারীর অ্যাকাউন্ট",
|
|
8
|
-
"settings": "সেটিংস"
|
|
8
|
+
"settings": "সেটিংস",
|
|
9
|
+
"knowledgeBase": "জ্ঞান ভান্ডার"
|
|
9
10
|
},
|
|
10
11
|
"ResourceInfoPanel": {
|
|
11
12
|
"title": "সম্পদের তথ্য",
|
|
@@ -373,4 +374,4 @@
|
|
|
373
374
|
"searching": "অনুসন্ধান করা হচ্ছে...",
|
|
374
375
|
"search": "অনুসন্ধান"
|
|
375
376
|
}
|
|
376
|
-
}
|
|
377
|
+
}
|
package/translations/cs.json
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
"resourceInfo": "Informace o zdroji",
|
|
6
6
|
"collaboration": "Spolupráce",
|
|
7
7
|
"userAccount": "Uživatelský účet",
|
|
8
|
-
"settings": "Nastavení"
|
|
8
|
+
"settings": "Nastavení",
|
|
9
|
+
"knowledgeBase": "Znalostní báze"
|
|
9
10
|
},
|
|
10
11
|
"ResourceInfoPanel": {
|
|
11
12
|
"title": "Informace o zdroji",
|
|
@@ -373,4 +374,4 @@
|
|
|
373
374
|
"searching": "Vyhledávání...",
|
|
374
375
|
"search": "Hledat"
|
|
375
376
|
}
|
|
376
|
-
}
|
|
377
|
+
}
|
package/translations/da.json
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
"resourceInfo": "Ressourceinfo",
|
|
6
6
|
"collaboration": "Samarbejde",
|
|
7
7
|
"userAccount": "Brugerkonto",
|
|
8
|
-
"settings": "Indstillinger"
|
|
8
|
+
"settings": "Indstillinger",
|
|
9
|
+
"knowledgeBase": "Vidensbase"
|
|
9
10
|
},
|
|
10
11
|
"ResourceInfoPanel": {
|
|
11
12
|
"title": "Ressourceinfo",
|
|
@@ -373,4 +374,4 @@
|
|
|
373
374
|
"searching": "Søger...",
|
|
374
375
|
"search": "Søg"
|
|
375
376
|
}
|
|
376
|
-
}
|
|
377
|
+
}
|