@semiont/react-ui 0.5.22 → 0.5.24
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/{ar-ZHKO4XDR.js → ar-JRTKCMTF.js} +11 -4
- package/dist/ar-JRTKCMTF.js.map +1 -0
- package/dist/{bn-3BUDKAK5.js → bn-LO6EDSCC.js} +11 -4
- package/dist/bn-LO6EDSCC.js.map +1 -0
- package/dist/{chunk-PFUXQPWJ.js → chunk-4QMTEPQ3.js} +92 -60
- package/dist/chunk-4QMTEPQ3.js.map +1 -0
- package/dist/{chunk-R52YAGHK.js → chunk-5Y5JDCKC.js} +11 -4
- package/dist/chunk-5Y5JDCKC.js.map +1 -0
- package/dist/{cs-2EFEUKTW.js → cs-LCHHOR4O.js} +11 -4
- package/dist/cs-LCHHOR4O.js.map +1 -0
- package/dist/{da-SUD3Q44Q.js → da-TARGPMJR.js} +11 -4
- package/dist/da-TARGPMJR.js.map +1 -0
- package/dist/{de-6IC5QRX7.js → de-SBH4QBPJ.js} +11 -4
- package/dist/de-SBH4QBPJ.js.map +1 -0
- package/dist/{el-Q4NAXFRC.js → el-2D2OLGWB.js} +11 -4
- package/dist/el-2D2OLGWB.js.map +1 -0
- package/dist/{en-P2L4X27N.js → en-QFIEG3CA.js} +2 -2
- package/dist/{es-YUKZBD4W.js → es-U6YK2LX6.js} +11 -4
- package/dist/es-U6YK2LX6.js.map +1 -0
- package/dist/{fa-OJ47LILE.js → fa-S7SZE37M.js} +11 -4
- package/dist/fa-S7SZE37M.js.map +1 -0
- package/dist/{fi-QFFL5CUB.js → fi-CBL3NIXN.js} +11 -4
- package/dist/fi-CBL3NIXN.js.map +1 -0
- package/dist/{fr-BOQZZWP4.js → fr-EABUHV6S.js} +11 -4
- package/dist/fr-EABUHV6S.js.map +1 -0
- package/dist/{he-LXDY3TFA.js → he-THWD244Y.js} +11 -4
- package/dist/he-THWD244Y.js.map +1 -0
- package/dist/{hi-HOJER77V.js → hi-GHGFZJ44.js} +11 -4
- package/dist/hi-GHGFZJ44.js.map +1 -0
- package/dist/{id-I5WQ6EWD.js → id-POZOUMDW.js} +11 -4
- package/dist/id-POZOUMDW.js.map +1 -0
- package/dist/index.d.ts +269 -69
- package/dist/index.js +2080 -1861
- package/dist/index.js.map +1 -1
- package/dist/{it-UYH642IJ.js → it-KDYJADSH.js} +11 -4
- package/dist/it-KDYJADSH.js.map +1 -0
- package/dist/{ja-JTVWAC4L.js → ja-Z5Z6ZF3P.js} +11 -4
- package/dist/ja-Z5Z6ZF3P.js.map +1 -0
- package/dist/{ko-IHXFMOIZ.js → ko-7X3XUXRN.js} +11 -4
- package/dist/ko-7X3XUXRN.js.map +1 -0
- package/dist/{ms-JH25VFLO.js → ms-BTWEIW43.js} +11 -4
- package/dist/ms-BTWEIW43.js.map +1 -0
- package/dist/{nl-SURXW7IQ.js → nl-IS2CGF5I.js} +11 -4
- package/dist/nl-IS2CGF5I.js.map +1 -0
- package/dist/{no-HXIKQFDZ.js → no-AAMEVA26.js} +11 -4
- package/dist/no-AAMEVA26.js.map +1 -0
- package/dist/{pl-7A4KU6XK.js → pl-PVXUQYFT.js} +11 -4
- package/dist/pl-PVXUQYFT.js.map +1 -0
- package/dist/{pt-6MGYP7Q5.js → pt-3ITQ76TL.js} +11 -4
- package/dist/pt-3ITQ76TL.js.map +1 -0
- package/dist/{ro-IROCHNIA.js → ro-FRB4IIVS.js} +11 -4
- package/dist/ro-FRB4IIVS.js.map +1 -0
- package/dist/{sv-WDJD75CV.js → sv-DS3RO24M.js} +11 -4
- package/dist/sv-DS3RO24M.js.map +1 -0
- package/dist/test-utils.js +9 -3
- package/dist/test-utils.js.map +1 -1
- package/dist/{th-RIO2E6B3.js → th-AX66MWWB.js} +11 -4
- package/dist/th-AX66MWWB.js.map +1 -0
- package/dist/{tr-TZ7ERCIN.js → tr-7KTB67TT.js} +11 -4
- package/dist/tr-7KTB67TT.js.map +1 -0
- package/dist/{uk-ZFWDKLUE.js → uk-SMQS2MAQ.js} +11 -4
- package/dist/uk-SMQS2MAQ.js.map +1 -0
- package/dist/{vi-UIOSP2JG.js → vi-D3JXL2EZ.js} +11 -4
- package/dist/vi-D3JXL2EZ.js.map +1 -0
- package/dist/{zh-6R6YUY46.js → zh-S754AWFS.js} +11 -4
- package/dist/zh-S754AWFS.js.map +1 -0
- package/package.json +4 -4
- package/src/components/annotation-popups/JsonLdView.tsx +1 -1
- package/src/components/annotation-popups/__tests__/JsonLdView.test.tsx +8 -2
- package/src/components/modals/ReferenceWizardModal.tsx +2 -1
- package/src/components/modals/ResourceGenerateModal.tsx +10 -4
- package/src/components/modals/ResourceSearchModal.tsx +3 -1
- package/src/components/modals/SearchModal.tsx +3 -1
- package/src/components/modals/__tests__/ResourceGenerateModal.test.tsx +5 -0
- package/src/components/modals/__tests__/ResourceSearchModal.test.tsx +2 -1
- package/src/components/modals/__tests__/SearchModal.search-wiring.test.tsx +2 -1
- package/src/components/resource/AnnotateView.tsx +70 -138
- package/src/components/resource/AnnotationHistory.tsx +53 -17
- package/src/components/resource/BrowseView.tsx +3 -2
- package/src/components/resource/ResourceViewer.tsx +39 -22
- package/src/components/resource/__tests__/AnnotateView.registry.test.tsx +114 -0
- package/src/components/resource/__tests__/AnnotationHistory.test.tsx +63 -41
- package/src/components/resource/__tests__/BrowseView.reference-hover.test.tsx +2 -1
- package/src/components/resource/__tests__/ResourceViewer.multi-mount-invalidation.test.tsx +140 -0
- package/src/components/resource/__tests__/ResourceViewer.registry.test.tsx +89 -0
- package/src/components/resource/annotate-renderers.tsx +155 -0
- package/src/components/resource/panels/JsonLdPanel.tsx +1 -1
- package/src/components/resource/panels/ReferencesPanel.tsx +38 -3
- package/src/components/resource/panels/TagEntry.tsx +5 -1
- package/src/components/resource/panels/TaggingPanel.tsx +6 -1
- package/src/components/resource/panels/UnifiedAnnotationsPanel.tsx +41 -0
- package/src/components/resource/panels/__tests__/JsonLdPanel.test.tsx +8 -2
- package/src/components/resource/panels/__tests__/ReferencesPanel.headless.test.tsx +90 -0
- package/src/components/resource/panels/__tests__/TagEntry.test.tsx +2 -2
- package/src/components/resource/panels/__tests__/TaggingPanel.test.tsx +2 -2
- package/src/components/resource/panels/__tests__/UnifiedAnnotationsPanel.failure.test.tsx +78 -0
- package/src/components/settings/SettingsPanel.tsx +6 -2
- package/src/components/settings/__tests__/SettingsPanel.test.tsx +28 -3
- package/src/features/admin-devops/__tests__/AdminDevOpsPage.test.tsx +3 -11
- package/src/features/admin-devops/components/AdminDevOpsPage.tsx +0 -3
- package/src/features/admin-exchange/__tests__/AdminExchangePage.test.tsx +0 -1
- package/src/features/admin-exchange/components/AdminExchangePage.tsx +0 -3
- package/src/features/admin-exchange/state/__tests__/exchange-state-unit.test.ts +1 -1
- package/src/features/admin-security/__tests__/AdminSecurityPage.test.tsx +0 -8
- package/src/features/admin-security/components/AdminSecurityPage.tsx +0 -3
- package/src/features/admin-security/state/__tests__/admin-security-state-unit.test.ts +10 -9
- package/src/features/admin-security/state/admin-security-state-unit.ts +3 -2
- package/src/features/admin-users/__tests__/AdminUsersPage.test.tsx +0 -1
- package/src/features/admin-users/components/AdminUsersPage.tsx +0 -3
- package/src/features/admin-users/state/__tests__/admin-users-state-unit.test.ts +7 -6
- package/src/features/admin-users/state/admin-users-state-unit.ts +3 -2
- package/src/features/auth-welcome/state/__tests__/welcome-state-unit.test.ts +36 -26
- package/src/features/auth-welcome/state/welcome-state-unit.ts +7 -2
- package/src/features/moderate-entity-tags/__tests__/EntityTagsPage.test.tsx +0 -2
- package/src/features/moderate-entity-tags/components/EntityTagsPage.tsx +0 -3
- package/src/features/moderate-entity-tags/state/__tests__/entity-tags-state-unit.test.ts +37 -12
- package/src/features/moderate-entity-tags/state/entity-tags-state-unit.ts +9 -10
- package/src/features/moderate-recent/__tests__/RecentDocumentsPage.test.tsx +3 -5
- package/src/features/moderate-recent/components/RecentDocumentsPage.tsx +0 -3
- package/src/features/moderate-tag-schemas/__tests__/TagSchemasPage.test.tsx +3 -5
- package/src/features/moderate-tag-schemas/components/TagSchemasPage.tsx +0 -3
- package/src/features/moderation-linked-data/__tests__/LinkedDataPage.test.tsx +0 -1
- package/src/features/moderation-linked-data/components/LinkedDataPage.tsx +0 -3
- package/src/features/resource-compose/__tests__/ResourceComposePage.test.tsx +17 -7
- package/src/features/resource-compose/components/ResourceComposePage.tsx +5 -3
- package/src/features/resource-compose/state/__tests__/compose-page-state-unit.test.ts +33 -12
- package/src/features/resource-compose/state/compose-page-state-unit.ts +9 -8
- package/src/features/resource-discovery/__tests__/ResourceDiscoveryPage.test.tsx +3 -2
- package/src/features/resource-discovery/components/ResourceDiscoveryPage.tsx +25 -3
- package/src/features/resource-discovery/state/__tests__/discover-state-unit.test.ts +90 -25
- package/src/features/resource-discovery/state/discover-state-unit.ts +30 -30
- package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +9 -5
- package/src/features/resource-viewer/components/ResourceViewerPage.tsx +70 -40
- package/src/features/resource-viewer/state/__tests__/resource-loader-state-unit.test.ts +111 -8
- package/src/features/resource-viewer/state/__tests__/resource-viewer-page-state-unit.test.ts +167 -27
- package/src/features/resource-viewer/state/resource-loader-state-unit.ts +74 -9
- package/src/features/resource-viewer/state/resource-viewer-page-state-unit.ts +29 -28
- package/translations/ar.json +10 -3
- package/translations/bn.json +10 -3
- package/translations/cs.json +10 -3
- package/translations/da.json +10 -3
- package/translations/de.json +10 -3
- package/translations/el.json +10 -3
- package/translations/en.json +10 -3
- package/translations/es.json +10 -3
- package/translations/fa.json +10 -3
- package/translations/fi.json +10 -3
- package/translations/fr.json +10 -3
- package/translations/he.json +10 -3
- package/translations/hi.json +10 -3
- package/translations/id.json +10 -3
- package/translations/it.json +10 -3
- package/translations/ja.json +10 -3
- package/translations/ko.json +10 -3
- package/translations/ms.json +10 -3
- package/translations/nl.json +10 -3
- package/translations/no.json +10 -3
- package/translations/pl.json +10 -3
- package/translations/pt.json +10 -3
- package/translations/ro.json +10 -3
- package/translations/sv.json +10 -3
- package/translations/th.json +10 -3
- package/translations/tr.json +10 -3
- package/translations/uk.json +10 -3
- package/translations/vi.json +10 -3
- package/translations/zh.json +10 -3
- package/dist/ar-ZHKO4XDR.js.map +0 -1
- package/dist/bn-3BUDKAK5.js.map +0 -1
- package/dist/chunk-PFUXQPWJ.js.map +0 -1
- package/dist/chunk-R52YAGHK.js.map +0 -1
- package/dist/cs-2EFEUKTW.js.map +0 -1
- package/dist/da-SUD3Q44Q.js.map +0 -1
- package/dist/de-6IC5QRX7.js.map +0 -1
- package/dist/el-Q4NAXFRC.js.map +0 -1
- package/dist/es-YUKZBD4W.js.map +0 -1
- package/dist/fa-OJ47LILE.js.map +0 -1
- package/dist/fi-QFFL5CUB.js.map +0 -1
- package/dist/fr-BOQZZWP4.js.map +0 -1
- package/dist/he-LXDY3TFA.js.map +0 -1
- package/dist/hi-HOJER77V.js.map +0 -1
- package/dist/id-I5WQ6EWD.js.map +0 -1
- package/dist/it-UYH642IJ.js.map +0 -1
- package/dist/ja-JTVWAC4L.js.map +0 -1
- package/dist/ko-IHXFMOIZ.js.map +0 -1
- package/dist/ms-JH25VFLO.js.map +0 -1
- package/dist/nl-SURXW7IQ.js.map +0 -1
- package/dist/no-HXIKQFDZ.js.map +0 -1
- package/dist/pl-7A4KU6XK.js.map +0 -1
- package/dist/pt-6MGYP7Q5.js.map +0 -1
- package/dist/ro-IROCHNIA.js.map +0 -1
- package/dist/sv-WDJD75CV.js.map +0 -1
- package/dist/th-RIO2E6B3.js.map +0 -1
- package/dist/tr-TZ7ERCIN.js.map +0 -1
- package/dist/uk-ZFWDKLUE.js.map +0 -1
- package/dist/vi-UIOSP2JG.js.map +0 -1
- package/dist/zh-6R6YUY46.js.map +0 -1
- /package/dist/{en-P2L4X27N.js.map → en-QFIEG3CA.js.map} +0 -0
package/src/features/resource-viewer/state/__tests__/resource-viewer-page-state-unit.test.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { describe, it, expect, vi, afterEach } from 'vitest';
|
|
2
|
+
import { asStates } from '../../../../__tests__/test-client';
|
|
2
3
|
import { BehaviorSubject, Observable, firstValueFrom } from 'rxjs';
|
|
3
4
|
import { filter } from 'rxjs/operators';
|
|
4
5
|
import { annotationId, resourceId as makeResourceId } from '@semiont/core';
|
|
5
6
|
import type { ShellStateUnit } from '../../../../state/shell-state-unit';
|
|
6
|
-
import { createResourceViewerPageStateUnit } from '../resource-viewer-page-state-unit';
|
|
7
|
-
import { assertStateUnitAxioms, disposeProbe } from '@semiont/core/testing';
|
|
8
|
-
import {
|
|
7
|
+
import { createResourceViewerPageStateUnit, type ResourceViewerPageStateUnit } from '../resource-viewer-page-state-unit';
|
|
8
|
+
import { assertStateUnitAxioms, disposeProbe } from '@semiont/core/testing/axioms';
|
|
9
|
+
import { makeTestSession, type TestSession } from '../../../../__tests__/test-client';
|
|
9
10
|
|
|
10
11
|
const RID = makeResourceId('res-1');
|
|
11
12
|
|
|
@@ -28,18 +29,18 @@ function clientWithNamespaces(overrides: {
|
|
|
28
29
|
referencedBy$?: BehaviorSubject<unknown[] | undefined>;
|
|
29
30
|
resourceRepresentation?: ReturnType<typeof vi.fn>;
|
|
30
31
|
mediaToken?: ReturnType<typeof vi.fn>;
|
|
31
|
-
} = {}):
|
|
32
|
+
} = {}): TestSession {
|
|
32
33
|
const annotations$ = overrides.annotations$ ?? new BehaviorSubject<unknown[] | undefined>([]);
|
|
33
34
|
const entityTypes$ = overrides.entityTypes$ ?? new BehaviorSubject<string[] | undefined>(['Person']);
|
|
34
35
|
const events$ = overrides.events$ ?? new BehaviorSubject<unknown[] | undefined>([]);
|
|
35
36
|
const referencedBy$ = overrides.referencedBy$ ?? new BehaviorSubject<unknown[] | undefined>([]);
|
|
36
37
|
|
|
37
|
-
return
|
|
38
|
+
return makeTestSession({
|
|
38
39
|
browse: {
|
|
39
|
-
annotations: () => annotations$.asObservable(),
|
|
40
|
-
entityTypes: () => entityTypes$.asObservable(),
|
|
41
|
-
events: () => events$.asObservable(),
|
|
42
|
-
referencedBy: () => referencedBy$.asObservable(),
|
|
40
|
+
annotations: () => asStates(annotations$.asObservable()),
|
|
41
|
+
entityTypes: () => asStates(entityTypes$.asObservable()),
|
|
42
|
+
events: () => asStates(events$.asObservable()),
|
|
43
|
+
referencedBy: () => asStates(referencedBy$.asObservable()),
|
|
43
44
|
resourceRepresentation: overrides.resourceRepresentation ?? vi.fn().mockResolvedValue({
|
|
44
45
|
data: new TextEncoder().encode('hello').buffer,
|
|
45
46
|
contentType: 'text/plain',
|
|
@@ -61,13 +62,13 @@ function clientWithNamespaces(overrides: {
|
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
describe('createResourceViewerPageStateUnit', () => {
|
|
64
|
-
let tc:
|
|
65
|
+
let tc: TestSession;
|
|
65
66
|
|
|
66
67
|
afterEach(() => { tc?.bus.destroy(); });
|
|
67
68
|
|
|
68
69
|
it('exposes flow VMs', () => {
|
|
69
70
|
tc = clientWithNamespaces();
|
|
70
|
-
const stateUnit = createResourceViewerPageStateUnit(tc.
|
|
71
|
+
const stateUnit = createResourceViewerPageStateUnit(tc.session, RID, 'en', mockBrowse());
|
|
71
72
|
|
|
72
73
|
expect(stateUnit.beckon).toBeDefined();
|
|
73
74
|
expect(stateUnit.mark).toBeDefined();
|
|
@@ -83,9 +84,9 @@ describe('createResourceViewerPageStateUnit', () => {
|
|
|
83
84
|
{ id: 'a1', motivation: 'highlighting' },
|
|
84
85
|
]);
|
|
85
86
|
tc = clientWithNamespaces({ annotations$ });
|
|
86
|
-
const stateUnit = createResourceViewerPageStateUnit(tc.
|
|
87
|
+
const stateUnit = createResourceViewerPageStateUnit(tc.session, RID, 'en', mockBrowse());
|
|
87
88
|
|
|
88
|
-
const anns = await firstValueFrom(stateUnit.annotations$);
|
|
89
|
+
const anns = await firstValueFrom(stateUnit.annotations.value$);
|
|
89
90
|
expect(anns).toHaveLength(1);
|
|
90
91
|
|
|
91
92
|
stateUnit.dispose();
|
|
@@ -97,7 +98,7 @@ describe('createResourceViewerPageStateUnit', () => {
|
|
|
97
98
|
{ id: 'a2', motivation: 'commenting', body: [{ type: 'TextualBody', value: 'note' }], target: { selector: { type: 'TextQuoteSelector', exact: 'y' } } },
|
|
98
99
|
]);
|
|
99
100
|
tc = clientWithNamespaces({ annotations$ });
|
|
100
|
-
const stateUnit = createResourceViewerPageStateUnit(tc.
|
|
101
|
+
const stateUnit = createResourceViewerPageStateUnit(tc.session, RID, 'en', mockBrowse());
|
|
101
102
|
|
|
102
103
|
const groups = await firstValueFrom(stateUnit.annotationGroups$);
|
|
103
104
|
expect(groups.highlights.length + groups.comments.length).toBeGreaterThanOrEqual(1);
|
|
@@ -107,9 +108,9 @@ describe('createResourceViewerPageStateUnit', () => {
|
|
|
107
108
|
|
|
108
109
|
it('exposes entity types', async () => {
|
|
109
110
|
tc = clientWithNamespaces();
|
|
110
|
-
const stateUnit = createResourceViewerPageStateUnit(tc.
|
|
111
|
+
const stateUnit = createResourceViewerPageStateUnit(tc.session, RID, 'en', mockBrowse());
|
|
111
112
|
|
|
112
|
-
const types = await firstValueFrom(stateUnit.entityTypes$);
|
|
113
|
+
const types = await firstValueFrom(stateUnit.entityTypes.value$);
|
|
113
114
|
expect(types).toEqual(['Person']);
|
|
114
115
|
|
|
115
116
|
stateUnit.dispose();
|
|
@@ -118,9 +119,9 @@ describe('createResourceViewerPageStateUnit', () => {
|
|
|
118
119
|
it('exposes events from browse namespace', async () => {
|
|
119
120
|
const events$ = new BehaviorSubject<unknown[] | undefined>([{ id: 'e1', type: 'mark:added' }]);
|
|
120
121
|
tc = clientWithNamespaces({ events$ });
|
|
121
|
-
const stateUnit = createResourceViewerPageStateUnit(tc.
|
|
122
|
+
const stateUnit = createResourceViewerPageStateUnit(tc.session, RID, 'en', mockBrowse());
|
|
122
123
|
|
|
123
|
-
const events = await firstValueFrom(stateUnit.events$);
|
|
124
|
+
const events = await firstValueFrom(stateUnit.events.value$);
|
|
124
125
|
expect(events).toEqual([{ id: 'e1', type: 'mark:added' }]);
|
|
125
126
|
|
|
126
127
|
stateUnit.dispose();
|
|
@@ -129,9 +130,9 @@ describe('createResourceViewerPageStateUnit', () => {
|
|
|
129
130
|
it('exposes referencedBy from browse namespace', async () => {
|
|
130
131
|
const referencedBy$ = new BehaviorSubject<unknown[] | undefined>([{ resourceId: 'r2' }]);
|
|
131
132
|
tc = clientWithNamespaces({ referencedBy$ });
|
|
132
|
-
const stateUnit = createResourceViewerPageStateUnit(tc.
|
|
133
|
+
const stateUnit = createResourceViewerPageStateUnit(tc.session, RID, 'en', mockBrowse());
|
|
133
134
|
|
|
134
|
-
const refs = await firstValueFrom(stateUnit.referencedBy$);
|
|
135
|
+
const refs = await firstValueFrom(stateUnit.referencedBy.value$);
|
|
135
136
|
expect(refs).toEqual([{ resourceId: 'r2' }]);
|
|
136
137
|
|
|
137
138
|
stateUnit.dispose();
|
|
@@ -141,7 +142,7 @@ describe('createResourceViewerPageStateUnit', () => {
|
|
|
141
142
|
const mediaToken = vi.fn().mockResolvedValue({ token: 'tok-456' });
|
|
142
143
|
tc = clientWithNamespaces({ mediaToken });
|
|
143
144
|
const stateUnit = createResourceViewerPageStateUnit(
|
|
144
|
-
tc.
|
|
145
|
+
tc.session, RID, 'en', mockBrowse(),
|
|
145
146
|
{ mediaType: 'image/png' },
|
|
146
147
|
);
|
|
147
148
|
|
|
@@ -159,7 +160,7 @@ describe('createResourceViewerPageStateUnit', () => {
|
|
|
159
160
|
const resourceRepresentation = vi.fn();
|
|
160
161
|
tc = clientWithNamespaces({ mediaToken, resourceRepresentation });
|
|
161
162
|
const stateUnit = createResourceViewerPageStateUnit(
|
|
162
|
-
tc.
|
|
163
|
+
tc.session, RID, 'en', mockBrowse(),
|
|
163
164
|
{ mediaType: 'application/zip' },
|
|
164
165
|
);
|
|
165
166
|
|
|
@@ -178,7 +179,7 @@ describe('createResourceViewerPageStateUnit', () => {
|
|
|
178
179
|
});
|
|
179
180
|
tc = clientWithNamespaces({ mediaToken, resourceRepresentation });
|
|
180
181
|
const stateUnit = createResourceViewerPageStateUnit(
|
|
181
|
-
tc.
|
|
182
|
+
tc.session, RID, 'en', mockBrowse(),
|
|
182
183
|
{ mediaType: 'text/x-custom' },
|
|
183
184
|
);
|
|
184
185
|
|
|
@@ -190,7 +191,7 @@ describe('createResourceViewerPageStateUnit', () => {
|
|
|
190
191
|
|
|
191
192
|
it('wizard initializes closed', async () => {
|
|
192
193
|
tc = clientWithNamespaces();
|
|
193
|
-
const stateUnit = createResourceViewerPageStateUnit(tc.
|
|
194
|
+
const stateUnit = createResourceViewerPageStateUnit(tc.session, RID, 'en', mockBrowse());
|
|
194
195
|
|
|
195
196
|
const wizard = await firstValueFrom(stateUnit.wizard$);
|
|
196
197
|
expect(wizard.open).toBe(false);
|
|
@@ -200,7 +201,7 @@ describe('createResourceViewerPageStateUnit', () => {
|
|
|
200
201
|
|
|
201
202
|
it('bind:initiate opens wizard and fires gather:requested', async () => {
|
|
202
203
|
tc = clientWithNamespaces();
|
|
203
|
-
const stateUnit = createResourceViewerPageStateUnit(tc.
|
|
204
|
+
const stateUnit = createResourceViewerPageStateUnit(tc.session, RID, 'en', mockBrowse());
|
|
204
205
|
const gatherEvents: unknown[] = [];
|
|
205
206
|
tc.bus.get('gather:requested').subscribe((e) => gatherEvents.push(e));
|
|
206
207
|
|
|
@@ -220,7 +221,7 @@ describe('createResourceViewerPageStateUnit', () => {
|
|
|
220
221
|
|
|
221
222
|
it('closeWizard resets wizard state', async () => {
|
|
222
223
|
tc = clientWithNamespaces();
|
|
223
|
-
const stateUnit = createResourceViewerPageStateUnit(tc.
|
|
224
|
+
const stateUnit = createResourceViewerPageStateUnit(tc.session, RID, 'en', mockBrowse());
|
|
224
225
|
|
|
225
226
|
tc.bus.get('bind:initiate').next({
|
|
226
227
|
annotationId: annotationId('ann-1'),
|
|
@@ -239,6 +240,145 @@ describe('createResourceViewerPageStateUnit', () => {
|
|
|
239
240
|
});
|
|
240
241
|
});
|
|
241
242
|
|
|
243
|
+
describe('createResourceViewerPageStateUnit — list failure states', () => {
|
|
244
|
+
// A cache-backed list has three outcomes, not two. `browse.*()` delivers a
|
|
245
|
+
// terminal failure as an RxJS error (B15) once the B14 retry is exhausted
|
|
246
|
+
// with nothing stored — and a key that failed has no value either, so a
|
|
247
|
+
// (value | not-yet) model reports a dead request as an eternal spinner.
|
|
248
|
+
// Two panels do exactly that today: ReferencesPanel via
|
|
249
|
+
// `referencedByLoading = raw === undefined`, and AnnotationHistory via
|
|
250
|
+
// `loading = eventsData === undefined`.
|
|
251
|
+
// See .plans/PANEL-FAILURE-STATES.md
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* One case per cache-backed list. Each builds its OWN correctly-typed
|
|
255
|
+
* subject and returns the list off the unit, so the shared assertions below
|
|
256
|
+
* need no indexing by name and no cast.
|
|
257
|
+
*/
|
|
258
|
+
/** The slice of `ListState<T>` these shared assertions read. */
|
|
259
|
+
interface ListProbe {
|
|
260
|
+
value$: Observable<unknown>;
|
|
261
|
+
loading$: Observable<boolean>;
|
|
262
|
+
error$: Observable<Error | null>;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const LIST_CASES: ReadonlyArray<{
|
|
266
|
+
name: string;
|
|
267
|
+
start: () => {
|
|
268
|
+
subject: { next: (s: never) => void };
|
|
269
|
+
tc: TestSession;
|
|
270
|
+
unit: ResourceViewerPageStateUnit;
|
|
271
|
+
list: ListProbe;
|
|
272
|
+
};
|
|
273
|
+
}> = [
|
|
274
|
+
{
|
|
275
|
+
name: 'annotations',
|
|
276
|
+
start: () => {
|
|
277
|
+
const subject = new BehaviorSubject<unknown[] | undefined>(undefined);
|
|
278
|
+
const tc = clientWithNamespaces({ annotations$: subject });
|
|
279
|
+
const unit = createResourceViewerPageStateUnit(tc.session, RID, 'en', mockBrowse());
|
|
280
|
+
return { subject, tc, unit, list: unit.annotations };
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
name: 'entityTypes',
|
|
285
|
+
start: () => {
|
|
286
|
+
const subject = new BehaviorSubject<string[] | undefined>(undefined);
|
|
287
|
+
const tc = clientWithNamespaces({ entityTypes$: subject });
|
|
288
|
+
const unit = createResourceViewerPageStateUnit(tc.session, RID, 'en', mockBrowse());
|
|
289
|
+
return { subject, tc, unit, list: unit.entityTypes };
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
name: 'events',
|
|
294
|
+
start: () => {
|
|
295
|
+
const subject = new BehaviorSubject<unknown[] | undefined>(undefined);
|
|
296
|
+
const tc = clientWithNamespaces({ events$: subject });
|
|
297
|
+
const unit = createResourceViewerPageStateUnit(tc.session, RID, 'en', mockBrowse());
|
|
298
|
+
return { subject, tc, unit, list: unit.events };
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
name: 'referencedBy',
|
|
303
|
+
start: () => {
|
|
304
|
+
const subject = new BehaviorSubject<unknown[] | undefined>(undefined);
|
|
305
|
+
const tc = clientWithNamespaces({ referencedBy$: subject });
|
|
306
|
+
const unit = createResourceViewerPageStateUnit(tc.session, RID, 'en', mockBrowse());
|
|
307
|
+
return { subject, tc, unit, list: unit.referencedBy };
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
];
|
|
311
|
+
|
|
312
|
+
it.each(LIST_CASES)('$name: stops reporting loading and surfaces the reason on terminal failure', async ({ start }) => {
|
|
313
|
+
const { subject, tc, unit, list } = start();
|
|
314
|
+
|
|
315
|
+
expect(await firstValueFrom(list.loading$)).toBe(true);
|
|
316
|
+
expect(await firstValueFrom(list.error$)).toBeNull();
|
|
317
|
+
|
|
318
|
+
subject.next({ status: 'failed', error: new Error('Resource not found') } as never);
|
|
319
|
+
|
|
320
|
+
expect(await firstValueFrom(list.loading$)).toBe(false);
|
|
321
|
+
expect((await firstValueFrom(list.error$))?.message).toBe('Resource not found');
|
|
322
|
+
|
|
323
|
+
unit.dispose();
|
|
324
|
+
tc.bus.destroy();
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
it.each(LIST_CASES)('$name: keeps an empty value alongside the failure, so callers still render a list', async ({ start }) => {
|
|
328
|
+
const { subject, tc, unit, list } = start();
|
|
329
|
+
|
|
330
|
+
subject.next({ status: 'failed', error: new Error('boom') } as never);
|
|
331
|
+
|
|
332
|
+
expect(await firstValueFrom(list.value$)).toEqual([]);
|
|
333
|
+
unit.dispose();
|
|
334
|
+
tc.bus.destroy();
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
it('retry() clears the error, re-enters loading, and re-subscribes so a fresh attempt can succeed', async () => {
|
|
338
|
+
// D1/D3: failure is an EMISSION and recovery is a fresh SUBSCRIPTION —
|
|
339
|
+
// retry() re-attaches, and the new subscription's chain delivers.
|
|
340
|
+
const attempts: Array<BehaviorSubject<unknown>> = [];
|
|
341
|
+
const tc = makeTestSession({
|
|
342
|
+
browse: {
|
|
343
|
+
annotations: () => new BehaviorSubject<unknown>({ status: 'ready', value: [] }).asObservable(),
|
|
344
|
+
entityTypes: () => new BehaviorSubject<unknown>({ status: 'ready', value: [] }).asObservable(),
|
|
345
|
+
events: () => new BehaviorSubject<unknown>({ status: 'ready', value: [] }).asObservable(),
|
|
346
|
+
referencedBy: () => {
|
|
347
|
+
const s = new BehaviorSubject<unknown>({ status: 'pending' });
|
|
348
|
+
attempts.push(s);
|
|
349
|
+
return s.asObservable();
|
|
350
|
+
},
|
|
351
|
+
resourceRepresentation: vi.fn().mockResolvedValue({
|
|
352
|
+
data: new TextEncoder().encode('hello').buffer,
|
|
353
|
+
contentType: 'text/plain',
|
|
354
|
+
}),
|
|
355
|
+
},
|
|
356
|
+
auth: { mediaToken: vi.fn().mockResolvedValue({ token: 'tok' }) },
|
|
357
|
+
mark: { annotation: vi.fn(), delete: vi.fn(), assist: vi.fn(() => new Observable(() => {})) },
|
|
358
|
+
gather: { annotation: vi.fn(() => new Observable(() => {})) },
|
|
359
|
+
match: { search: vi.fn(() => new Observable(() => {})) },
|
|
360
|
+
yield: { fromAnnotation: vi.fn(() => new Observable(() => {})) },
|
|
361
|
+
bind: { body: vi.fn().mockResolvedValue(undefined) },
|
|
362
|
+
});
|
|
363
|
+
const unit = createResourceViewerPageStateUnit(tc.session, RID, 'en', mockBrowse());
|
|
364
|
+
|
|
365
|
+
attempts[0]!.next({ status: 'failed', error: new Error('nope') });
|
|
366
|
+
expect(await firstValueFrom(unit.referencedBy.error$)).not.toBeNull();
|
|
367
|
+
|
|
368
|
+
unit.referencedBy.retry();
|
|
369
|
+
expect(attempts.length).toBeGreaterThan(1);
|
|
370
|
+
expect(await firstValueFrom(unit.referencedBy.error$)).toBeNull();
|
|
371
|
+
expect(await firstValueFrom(unit.referencedBy.loading$)).toBe(true);
|
|
372
|
+
|
|
373
|
+
attempts[attempts.length - 1]!.next({ status: 'ready', value: [{ id: 'ref-1' }] });
|
|
374
|
+
expect(await firstValueFrom(unit.referencedBy.loading$)).toBe(false);
|
|
375
|
+
expect(await firstValueFrom(unit.referencedBy.value$)).toHaveLength(1);
|
|
376
|
+
|
|
377
|
+
unit.dispose();
|
|
378
|
+
tc.bus.destroy();
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
|
|
242
382
|
describe('ResourceViewerPageStateUnit — StateUnit axioms', () => {
|
|
243
383
|
it('satisfies the StateUnit axioms (A7-passed: browse survives; A7-owned: children disposed)', () => {
|
|
244
384
|
const RID = makeResourceId('res-ax');
|
|
@@ -247,7 +387,7 @@ describe('ResourceViewerPageStateUnit — StateUnit axioms', () => {
|
|
|
247
387
|
const browse = disposeProbe();
|
|
248
388
|
const tc = clientWithNamespaces();
|
|
249
389
|
return {
|
|
250
|
-
unit: createResourceViewerPageStateUnit(tc.
|
|
390
|
+
unit: createResourceViewerPageStateUnit(tc.session, RID, 'en', browse as unknown as ShellStateUnit),
|
|
251
391
|
passedIn: [browse],
|
|
252
392
|
teardown: () => tc.bus.destroy(),
|
|
253
393
|
};
|
|
@@ -1,26 +1,91 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readyValue } from '@semiont/sdk';
|
|
2
|
+
import {
|
|
3
|
+
BehaviorSubject,
|
|
4
|
+
combineLatest,
|
|
5
|
+
distinctUntilChanged,
|
|
6
|
+
map,
|
|
7
|
+
type Observable,
|
|
8
|
+
type Subscription,
|
|
9
|
+
} from 'rxjs';
|
|
2
10
|
import type { ResourceDescriptor, ResourceId } from '@semiont/core';
|
|
3
11
|
import type { StateUnit } from '@semiont/core';
|
|
4
|
-
import type {
|
|
12
|
+
import type { SemiontSession } from '@semiont/sdk';
|
|
5
13
|
|
|
6
14
|
export interface ResourceLoaderStateUnit extends StateUnit {
|
|
7
15
|
resource$: Observable<ResourceDescriptor | undefined>;
|
|
8
16
|
isLoading$: Observable<boolean>;
|
|
17
|
+
/** Terminal load failure (B15), or null. Cleared by any value or `invalidate()`. */
|
|
18
|
+
error$: Observable<Error | null>;
|
|
9
19
|
invalidate(): void;
|
|
10
20
|
}
|
|
11
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Load one resource, in three states: loading, loaded, failed.
|
|
24
|
+
*
|
|
25
|
+
* The third state is not optional. `browse.resource()` delivers a terminal
|
|
26
|
+
* failure as an RxJS *error* notification (B15) when the B14 retry is
|
|
27
|
+
* exhausted with nothing cached — and a key that failed has no value either,
|
|
28
|
+
* so a (value | no value) model reports a dead request as an eternal spinner
|
|
29
|
+
* and drops the reason entirely. This unit catches the notification here so
|
|
30
|
+
* that (a) consumers can render the failure and retry it, and (b) it never
|
|
31
|
+
* escapes to RxJS as an unhandled rethrow.
|
|
32
|
+
* See .plans/bugs/resource-page-frozen-on-disposed-client-after-kb-switch.md (D4)
|
|
33
|
+
*/
|
|
12
34
|
export function createResourceLoaderStateUnit(
|
|
13
|
-
|
|
35
|
+
session: SemiontSession,
|
|
14
36
|
resourceId: ResourceId,
|
|
15
37
|
): ResourceLoaderStateUnit {
|
|
16
|
-
const
|
|
17
|
-
const resource$ =
|
|
18
|
-
const
|
|
38
|
+
const { client } = session;
|
|
39
|
+
const resource$ = new BehaviorSubject<ResourceDescriptor | undefined>(undefined);
|
|
40
|
+
const error$ = new BehaviorSubject<Error | null>(null);
|
|
41
|
+
|
|
42
|
+
let subscription: Subscription | null = null;
|
|
43
|
+
let disposed = false;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* (Re)subscribe to this key. An errored observable is terminated, so
|
|
47
|
+
* recovery needs a fresh subscription — which is also what re-arms the
|
|
48
|
+
* cache: `observe()` clears the B15 failure marker and starts a new
|
|
49
|
+
* attempt chain for a key it is asked about again.
|
|
50
|
+
*/
|
|
51
|
+
const attach = (): void => {
|
|
52
|
+
if (disposed) return;
|
|
53
|
+
subscription?.unsubscribe();
|
|
54
|
+
subscription = client.browse.resource(resourceId).subscribe((st) => {
|
|
55
|
+
if (st.status === 'failed') {
|
|
56
|
+
// D1: failure is an emission — the subscription stays alive.
|
|
57
|
+
error$.next(st.error);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (st.status === 'ready' && error$.getValue() !== null) error$.next(null);
|
|
61
|
+
resource$.next(readyValue(st));
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
attach();
|
|
65
|
+
|
|
66
|
+
const isLoading$ = combineLatest([resource$, error$]).pipe(
|
|
67
|
+
map(([resource, error]) => resource === undefined && error === null),
|
|
68
|
+
distinctUntilChanged(),
|
|
69
|
+
);
|
|
19
70
|
|
|
20
71
|
return {
|
|
21
|
-
|
|
72
|
+
// X1: owned subjects are published read-only.
|
|
73
|
+
resource$: resource$.asObservable(),
|
|
22
74
|
isLoading$,
|
|
23
|
-
|
|
24
|
-
|
|
75
|
+
error$: error$.asObservable(),
|
|
76
|
+
invalidate: () => {
|
|
77
|
+
if (disposed) return;
|
|
78
|
+
error$.next(null);
|
|
79
|
+
client.browse.invalidateResourceDetail(resourceId);
|
|
80
|
+
attach();
|
|
81
|
+
},
|
|
82
|
+
dispose: () => {
|
|
83
|
+
if (disposed) return;
|
|
84
|
+
disposed = true;
|
|
85
|
+
subscription?.unsubscribe();
|
|
86
|
+
subscription = null;
|
|
87
|
+
resource$.complete();
|
|
88
|
+
error$.complete();
|
|
89
|
+
},
|
|
25
90
|
};
|
|
26
91
|
}
|
|
@@ -3,13 +3,14 @@ import type { ResourceId, components } from '@semiont/core';
|
|
|
3
3
|
import { createDisposer } from '@semiont/sdk';
|
|
4
4
|
import type { StateUnit } from '@semiont/core';
|
|
5
5
|
import type { ShellStateUnit } from '../../../state/shell-state-unit';
|
|
6
|
+
import { trackList, type ListState } from '../../../state/list-state';
|
|
6
7
|
import { createBeckonStateUnit, type BeckonStateUnit } from '@semiont/sdk';
|
|
7
8
|
import { createMarkStateUnit, type MarkStateUnit } from '@semiont/sdk';
|
|
8
9
|
import { createGatherStateUnit, type GatherStateUnit } from '@semiont/sdk';
|
|
9
10
|
import { createMatchStateUnit } from '@semiont/sdk';
|
|
10
11
|
import { createYieldStateUnit, type YieldStateUnit } from '@semiont/sdk';
|
|
11
|
-
import type {
|
|
12
|
-
import { decodeWithCharset, textExtractionOf } from '@semiont/core';
|
|
12
|
+
import type { SemiontSession } from '@semiont/sdk';
|
|
13
|
+
import { decodeWithCharset, textExtractionOf, uuidV4 } from '@semiont/core';
|
|
13
14
|
import { groupAnnotations } from '../../../lib/annotation-groups';
|
|
14
15
|
import type { ReferencedByEntry } from '@semiont/sdk';
|
|
15
16
|
|
|
@@ -43,11 +44,12 @@ export interface ResourceViewerPageStateUnit extends StateUnit {
|
|
|
43
44
|
gather: GatherStateUnit;
|
|
44
45
|
yield: YieldStateUnit;
|
|
45
46
|
|
|
46
|
-
annotations
|
|
47
|
+
annotations: ListState<Annotation[]>;
|
|
48
|
+
entityTypes: ListState<string[]>;
|
|
49
|
+
events: ListState<StoredEventResponse[]>;
|
|
50
|
+
referencedBy: ListState<ReferencedByEntry[]>;
|
|
51
|
+
/** Derived from `annotations.value$`; failure/loading live on `annotations`. */
|
|
47
52
|
annotationGroups$: Observable<AnnotationGroups>;
|
|
48
|
-
entityTypes$: Observable<string[]>;
|
|
49
|
-
events$: Observable<StoredEventResponse[]>;
|
|
50
|
-
referencedBy$: Observable<ReferencedByEntry[]>;
|
|
51
53
|
content$: Observable<string>;
|
|
52
54
|
contentLoading$: Observable<boolean>;
|
|
53
55
|
mediaToken$: Observable<string | null>;
|
|
@@ -56,13 +58,18 @@ export interface ResourceViewerPageStateUnit extends StateUnit {
|
|
|
56
58
|
closeWizard(): void;
|
|
57
59
|
}
|
|
58
60
|
|
|
61
|
+
// Session-typed (SESSION-TYPED-FACTORIES.md D1): the parameter is the
|
|
62
|
+
// lifetime this unit must not outlive. The internal flow units below keep
|
|
63
|
+
// the narrower client — their lifetime is THIS unit's disposer, which is now
|
|
64
|
+
// session-bound; that is layering, not a loophole.
|
|
59
65
|
export function createResourceViewerPageStateUnit(
|
|
60
|
-
|
|
66
|
+
session: SemiontSession,
|
|
61
67
|
resourceId: ResourceId,
|
|
62
68
|
locale: string,
|
|
63
69
|
browse: ShellStateUnit,
|
|
64
70
|
options?: { mediaType?: string },
|
|
65
71
|
): ResourceViewerPageStateUnit {
|
|
72
|
+
const { client } = session;
|
|
66
73
|
const disposer = createDisposer();
|
|
67
74
|
|
|
68
75
|
const beckon = createBeckonStateUnit(client);
|
|
@@ -81,23 +88,17 @@ export function createResourceViewerPageStateUnit(
|
|
|
81
88
|
disposer.add(matchStateUnit);
|
|
82
89
|
disposer.add(yieldStateUnit);
|
|
83
90
|
|
|
84
|
-
const annotations
|
|
85
|
-
|
|
86
|
-
);
|
|
91
|
+
const annotations = trackList<Annotation[]>(() => client.browse.annotations(resourceId), []);
|
|
92
|
+
const entityTypes = trackList<string[]>(() => client.browse.entityTypes(), []);
|
|
93
|
+
const events = trackList<StoredEventResponse[]>(() => client.browse.events(resourceId), []);
|
|
94
|
+
const referencedBy = trackList<ReferencedByEntry[]>(() => client.browse.referencedBy(resourceId), []);
|
|
95
|
+
disposer.add(annotations.dispose);
|
|
96
|
+
disposer.add(entityTypes.dispose);
|
|
97
|
+
disposer.add(events.dispose);
|
|
98
|
+
disposer.add(referencedBy.dispose);
|
|
87
99
|
|
|
88
|
-
const annotationGroups$: Observable<AnnotationGroups> =
|
|
89
|
-
|
|
90
|
-
const entityTypes$: Observable<string[]> = client.browse.entityTypes().pipe(
|
|
91
|
-
map((e) => e ?? []),
|
|
92
|
-
);
|
|
93
|
-
|
|
94
|
-
const events$: Observable<StoredEventResponse[]> = client.browse.events(resourceId).pipe(
|
|
95
|
-
map((e) => e ?? []),
|
|
96
|
-
);
|
|
97
|
-
|
|
98
|
-
const referencedBy$: Observable<ReferencedByEntry[]> = client.browse.referencedBy(resourceId).pipe(
|
|
99
|
-
map((r) => r ?? []),
|
|
100
|
-
);
|
|
100
|
+
const annotationGroups$: Observable<AnnotationGroups> =
|
|
101
|
+
annotations.state.value$.pipe(map(groupAnnotations));
|
|
101
102
|
|
|
102
103
|
const content$ = new BehaviorSubject<string>('');
|
|
103
104
|
const contentLoading$ = new BehaviorSubject<boolean>(false);
|
|
@@ -143,7 +144,7 @@ export function createResourceViewerPageStateUnit(
|
|
|
143
144
|
entityTypes: event.entityTypes,
|
|
144
145
|
});
|
|
145
146
|
client.bus.get('gather:requested').next({
|
|
146
|
-
correlationId:
|
|
147
|
+
correlationId: uuidV4(),
|
|
147
148
|
annotationId: event.annotationId,
|
|
148
149
|
resourceId: event.resourceId,
|
|
149
150
|
options: { contextWindow: 2000 },
|
|
@@ -157,11 +158,11 @@ export function createResourceViewerPageStateUnit(
|
|
|
157
158
|
mark,
|
|
158
159
|
gather,
|
|
159
160
|
yield: yieldStateUnit,
|
|
160
|
-
annotations
|
|
161
|
+
annotations: annotations.state,
|
|
162
|
+
entityTypes: entityTypes.state,
|
|
163
|
+
events: events.state,
|
|
164
|
+
referencedBy: referencedBy.state,
|
|
161
165
|
annotationGroups$,
|
|
162
|
-
entityTypes$,
|
|
163
|
-
events$,
|
|
164
|
-
referencedBy$,
|
|
165
166
|
content$: content$.asObservable(),
|
|
166
167
|
contentLoading$: contentLoading$.asObservable(),
|
|
167
168
|
mediaToken$: mediaToken$.asObservable(),
|
package/translations/ar.json
CHANGED
|
@@ -77,7 +77,9 @@
|
|
|
77
77
|
"justNow": "الآن",
|
|
78
78
|
"minutesAgo": "منذ {{count}}د",
|
|
79
79
|
"hoursAgo": "منذ {{count}}س",
|
|
80
|
-
"daysAgo": "منذ {{count}}ي"
|
|
80
|
+
"daysAgo": "منذ {{count}}ي",
|
|
81
|
+
"failed": "تعذّر تحميل السجل.",
|
|
82
|
+
"retry": "إعادة المحاولة"
|
|
81
83
|
},
|
|
82
84
|
"CommentsPanel": {
|
|
83
85
|
"title": "التعليقات",
|
|
@@ -171,7 +173,9 @@
|
|
|
171
173
|
"reference": "المراجع",
|
|
172
174
|
"assessment": "التقييمات",
|
|
173
175
|
"comment": "التعليقات",
|
|
174
|
-
"tag": "العلامات"
|
|
176
|
+
"tag": "العلامات",
|
|
177
|
+
"annotationsFailed": "تعذّر تحميل التعليقات التوضيحية.",
|
|
178
|
+
"retry": "إعادة المحاولة"
|
|
175
179
|
},
|
|
176
180
|
"StatisticsPanel": {
|
|
177
181
|
"title": "الإحصائيات",
|
|
@@ -220,7 +224,10 @@
|
|
|
220
224
|
"loading": "جارٍ التحميل...",
|
|
221
225
|
"loadingEllipsis": "جارٍ التحميل...",
|
|
222
226
|
"untitledResource": "مورد بدون عنوان",
|
|
223
|
-
"noText": "لا يوجد نص"
|
|
227
|
+
"noText": "لا يوجد نص",
|
|
228
|
+
"incomingReferencesFailed": "تعذّر تحميل المراجع الواردة.",
|
|
229
|
+
"retry": "إعادة المحاولة",
|
|
230
|
+
"entityTypesFailed": "تعذّر تحميل أنواع الكيانات."
|
|
224
231
|
},
|
|
225
232
|
"KeyboardShortcuts": {
|
|
226
233
|
"title": "اختصارات لوحة المفاتيح",
|
package/translations/bn.json
CHANGED
|
@@ -77,7 +77,9 @@
|
|
|
77
77
|
"justNow": "এইমাত্র",
|
|
78
78
|
"minutesAgo": "{{count}} মি. আগে",
|
|
79
79
|
"hoursAgo": "{{count}} ঘ. আগে",
|
|
80
|
-
"daysAgo": "{{count}} দি. আগে"
|
|
80
|
+
"daysAgo": "{{count}} দি. আগে",
|
|
81
|
+
"failed": "ইতিহাস লোড করা যায়নি।",
|
|
82
|
+
"retry": "আবার চেষ্টা করুন"
|
|
81
83
|
},
|
|
82
84
|
"CommentsPanel": {
|
|
83
85
|
"title": "মন্তব্যসমূহ",
|
|
@@ -171,7 +173,9 @@
|
|
|
171
173
|
"reference": "রেফারেন্সসমূহ",
|
|
172
174
|
"assessment": "মূল্যায়নসমূহ",
|
|
173
175
|
"comment": "মন্তব্যসমূহ",
|
|
174
|
-
"tag": "ট্যাগসমূহ"
|
|
176
|
+
"tag": "ট্যাগসমূহ",
|
|
177
|
+
"annotationsFailed": "টীকা লোড করা যায়নি।",
|
|
178
|
+
"retry": "আবার চেষ্টা করুন"
|
|
175
179
|
},
|
|
176
180
|
"StatisticsPanel": {
|
|
177
181
|
"title": "পরিসংখ্যান",
|
|
@@ -220,7 +224,10 @@
|
|
|
220
224
|
"loading": "লোড হচ্ছে...",
|
|
221
225
|
"loadingEllipsis": "লোড হচ্ছে...",
|
|
222
226
|
"untitledResource": "শিরোনামবিহীন সম্পদ",
|
|
223
|
-
"noText": "কোনো পাঠ্য নেই"
|
|
227
|
+
"noText": "কোনো পাঠ্য নেই",
|
|
228
|
+
"incomingReferencesFailed": "ইনকামিং রেফারেন্স লোড করা যায়নি।",
|
|
229
|
+
"retry": "আবার চেষ্টা করুন",
|
|
230
|
+
"entityTypesFailed": "সত্তার ধরন লোড করা যায়নি।"
|
|
224
231
|
},
|
|
225
232
|
"KeyboardShortcuts": {
|
|
226
233
|
"title": "কীবোর্ড শর্টকাট",
|
package/translations/cs.json
CHANGED
|
@@ -77,7 +77,9 @@
|
|
|
77
77
|
"justNow": "právě teď",
|
|
78
78
|
"minutesAgo": "před {{count}} min",
|
|
79
79
|
"hoursAgo": "před {{count}} hod",
|
|
80
|
-
"daysAgo": "před {{count}} dny"
|
|
80
|
+
"daysAgo": "před {{count}} dny",
|
|
81
|
+
"failed": "Historii se nepodařilo načíst.",
|
|
82
|
+
"retry": "Zkusit znovu"
|
|
81
83
|
},
|
|
82
84
|
"CommentsPanel": {
|
|
83
85
|
"title": "Komentáře",
|
|
@@ -171,7 +173,9 @@
|
|
|
171
173
|
"reference": "Reference",
|
|
172
174
|
"assessment": "Hodnocení",
|
|
173
175
|
"comment": "Komentáře",
|
|
174
|
-
"tag": "Štítky"
|
|
176
|
+
"tag": "Štítky",
|
|
177
|
+
"annotationsFailed": "Anotace se nepodařilo načíst.",
|
|
178
|
+
"retry": "Zkusit znovu"
|
|
175
179
|
},
|
|
176
180
|
"StatisticsPanel": {
|
|
177
181
|
"title": "Statistiky",
|
|
@@ -220,7 +224,10 @@
|
|
|
220
224
|
"loading": "načítání...",
|
|
221
225
|
"loadingEllipsis": "Načítání...",
|
|
222
226
|
"untitledResource": "Zdroj bez názvu",
|
|
223
|
-
"noText": "Žádný text"
|
|
227
|
+
"noText": "Žádný text",
|
|
228
|
+
"incomingReferencesFailed": "Příchozí reference se nepodařilo načíst.",
|
|
229
|
+
"retry": "Zkusit znovu",
|
|
230
|
+
"entityTypesFailed": "Typy entit se nepodařilo načíst."
|
|
224
231
|
},
|
|
225
232
|
"KeyboardShortcuts": {
|
|
226
233
|
"title": "Klávesové zkratky",
|
package/translations/da.json
CHANGED
|
@@ -77,7 +77,9 @@
|
|
|
77
77
|
"justNow": "lige nu",
|
|
78
78
|
"minutesAgo": "{{count}}m siden",
|
|
79
79
|
"hoursAgo": "{{count}}t siden",
|
|
80
|
-
"daysAgo": "{{count}}d siden"
|
|
80
|
+
"daysAgo": "{{count}}d siden",
|
|
81
|
+
"failed": "Historikken kunne ikke indlæses.",
|
|
82
|
+
"retry": "Prøv igen"
|
|
81
83
|
},
|
|
82
84
|
"CommentsPanel": {
|
|
83
85
|
"title": "Kommentarer",
|
|
@@ -171,7 +173,9 @@
|
|
|
171
173
|
"reference": "Referencer",
|
|
172
174
|
"assessment": "Vurderinger",
|
|
173
175
|
"comment": "Kommentarer",
|
|
174
|
-
"tag": "Tags"
|
|
176
|
+
"tag": "Tags",
|
|
177
|
+
"annotationsFailed": "Annoteringerne kunne ikke indlæses.",
|
|
178
|
+
"retry": "Prøv igen"
|
|
175
179
|
},
|
|
176
180
|
"StatisticsPanel": {
|
|
177
181
|
"title": "Statistik",
|
|
@@ -220,7 +224,10 @@
|
|
|
220
224
|
"loading": "indlæser...",
|
|
221
225
|
"loadingEllipsis": "Indlæser...",
|
|
222
226
|
"untitledResource": "Unavngivet ressource",
|
|
223
|
-
"noText": "Ingen tekst"
|
|
227
|
+
"noText": "Ingen tekst",
|
|
228
|
+
"incomingReferencesFailed": "Indgående referencer kunne ikke indlæses.",
|
|
229
|
+
"retry": "Prøv igen",
|
|
230
|
+
"entityTypesFailed": "Enhedstyper kunne ikke indlæses."
|
|
224
231
|
},
|
|
225
232
|
"KeyboardShortcuts": {
|
|
226
233
|
"title": "Tastaturgenveje",
|