@semiont/react-ui 0.2.46 → 0.3.1
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-COQREPXU.mjs → PdfAnnotationCanvas.client-PVTVPDBQ.mjs} +3 -4
- package/dist/PdfAnnotationCanvas.client-PVTVPDBQ.mjs.map +1 -0
- package/dist/{ar-7SUXNE34.mjs → ar-5REA6P4J.mjs} +48 -6
- package/dist/ar-5REA6P4J.mjs.map +1 -0
- package/dist/{bn-XOET3DOI.mjs → bn-YHRYHHPD.mjs} +48 -6
- package/dist/bn-YHRYHHPD.mjs.map +1 -0
- package/dist/{chunk-3JTO27MH.mjs → chunk-D4GAAQMM.mjs} +2 -9
- package/dist/{chunk-Q2KV6Y2J.mjs → chunk-PFQYNPQJ.mjs} +32 -32
- package/dist/{chunk-JH7BXE2P.mjs → chunk-VVCCMJS7.mjs} +47 -5
- package/dist/chunk-VVCCMJS7.mjs.map +1 -0
- package/dist/{cs-X63DXX7L.mjs → cs-JTJXTX2T.mjs} +48 -6
- package/dist/cs-JTJXTX2T.mjs.map +1 -0
- package/dist/{da-OWTCV57A.mjs → da-MK37SJB6.mjs} +48 -6
- package/dist/da-MK37SJB6.mjs.map +1 -0
- package/dist/{de-77BMFDVF.mjs → de-LGBCWERA.mjs} +48 -6
- package/dist/de-LGBCWERA.mjs.map +1 -0
- package/dist/dist-YLEIY3JJ.mjs +547 -0
- package/dist/dist-YLEIY3JJ.mjs.map +1 -0
- package/dist/{el-FIBNLH2V.mjs → el-FKJMFCWY.mjs} +48 -6
- package/dist/el-FKJMFCWY.mjs.map +1 -0
- package/dist/{en-XWEPVTB4.mjs → en-AOSMPC2M.mjs} +5 -3
- package/dist/{es-726NTS53.mjs → es-LVDPIXWU.mjs} +48 -6
- package/dist/es-LVDPIXWU.mjs.map +1 -0
- package/dist/{fa-3N4CIWE6.mjs → fa-3VA2PIUD.mjs} +48 -6
- package/dist/fa-3VA2PIUD.mjs.map +1 -0
- package/dist/{fi-JOM3M7Z4.mjs → fi-3WM75ZLR.mjs} +48 -6
- package/dist/fi-3WM75ZLR.mjs.map +1 -0
- package/dist/{fr-56QSXS7E.mjs → fr-NK4A72WA.mjs} +48 -6
- package/dist/fr-NK4A72WA.mjs.map +1 -0
- package/dist/{he-SNAXPJEK.mjs → he-IACZDZMB.mjs} +48 -6
- package/dist/he-IACZDZMB.mjs.map +1 -0
- package/dist/{hi-CRBRD5TB.mjs → hi-JZ7MGMMS.mjs} +48 -6
- package/dist/hi-JZ7MGMMS.mjs.map +1 -0
- package/dist/{id-BRCVLICF.mjs → id-P3KDQGNK.mjs} +48 -6
- package/dist/id-P3KDQGNK.mjs.map +1 -0
- package/dist/index.css +123 -12
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +353 -107
- package/dist/index.mjs +3139 -1811
- package/dist/index.mjs.map +1 -1
- package/dist/{it-M2Z27BNB.mjs → it-LQS33SUY.mjs} +48 -6
- package/dist/it-LQS33SUY.mjs.map +1 -0
- package/dist/{ja-TZUKW7HD.mjs → ja-G4FKZPWD.mjs} +48 -6
- package/dist/ja-G4FKZPWD.mjs.map +1 -0
- package/dist/{ko-NKBGGOL6.mjs → ko-2XWKQ7BA.mjs} +48 -6
- package/dist/ko-2XWKQ7BA.mjs.map +1 -0
- package/dist/{magic-string.es-7FJ3LUGB.mjs → magic-string.es-K77I4ZQN.mjs} +2 -2
- package/dist/{ms-XFXPN6RX.mjs → ms-2SNONIUD.mjs} +48 -6
- package/dist/ms-2SNONIUD.mjs.map +1 -0
- package/dist/{nl-MVYXAS5C.mjs → nl-BMZUAJ7J.mjs} +48 -6
- package/dist/nl-BMZUAJ7J.mjs.map +1 -0
- package/dist/{no-XOLO4JPV.mjs → no-6J3WIZ6L.mjs} +48 -6
- package/dist/no-6J3WIZ6L.mjs.map +1 -0
- package/dist/{pl-TRWLMMC4.mjs → pl-QQ7DAUVK.mjs} +48 -6
- package/dist/pl-QQ7DAUVK.mjs.map +1 -0
- package/dist/{pt-M3TE24UI.mjs → pt-MU3GN7MW.mjs} +48 -6
- package/dist/pt-MU3GN7MW.mjs.map +1 -0
- package/dist/{ro-QBFG2T64.mjs → ro-6GBE72QK.mjs} +48 -6
- package/dist/ro-6GBE72QK.mjs.map +1 -0
- package/dist/{sv-IUECBXWX.mjs → sv-NQIL7PEM.mjs} +48 -6
- package/dist/sv-NQIL7PEM.mjs.map +1 -0
- package/dist/test-utils.mjs +16994 -22140
- package/dist/test-utils.mjs.map +1 -1
- package/dist/{th-US7KIN5Q.mjs → th-6OCNZQBE.mjs} +48 -6
- package/dist/th-6OCNZQBE.mjs.map +1 -0
- package/dist/{tr-DWJ2FFUK.mjs → tr-XWJ5P3SC.mjs} +48 -6
- package/dist/tr-XWJ5P3SC.mjs.map +1 -0
- package/dist/{uk-M4ZE4DPZ.mjs → uk-AKSN6DGW.mjs} +48 -6
- package/dist/uk-AKSN6DGW.mjs.map +1 -0
- package/dist/{vi-FERZNPSH.mjs → vi-23GHQ45M.mjs} +48 -6
- package/dist/vi-23GHQ45M.mjs.map +1 -0
- package/dist/{zh-3J2I3WYK.mjs → zh-ITT4QBSN.mjs} +48 -6
- package/dist/zh-ITT4QBSN.mjs.map +1 -0
- package/package.json +18 -14
- package/src/components/Button/Button.tsx +23 -25
- package/src/components/annotation/AnnotateToolbar.tsx +1 -1
- package/src/components/annotation-popups/SharedPopupElements.tsx +5 -7
- package/src/components/image-annotation/SvgDrawingCanvas.tsx +3 -4
- package/src/components/modals/ConfigureGenerationStep.tsx +190 -0
- package/src/components/modals/ConfigureSearchStep.tsx +105 -0
- package/src/components/modals/ContextSummary.tsx +202 -0
- package/src/components/modals/GatherContextStep.tsx +93 -0
- package/src/components/modals/KeyboardShortcutsHelpModal.tsx +4 -6
- package/src/components/modals/ProposeEntitiesModal.tsx +4 -6
- package/src/components/modals/ReferenceWizardModal.tsx +338 -0
- package/src/components/modals/ResourceSearchModal.tsx +4 -6
- package/src/components/modals/SearchModal.css +43 -0
- package/src/components/modals/SearchModal.tsx +4 -6
- package/src/components/modals/SearchResultsStep.tsx +126 -0
- package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +3 -4
- package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +36 -14
- package/src/components/resource/AnnotateView.tsx +4 -4
- package/src/components/resource/AnnotationHistory.tsx +2 -2
- package/src/components/resource/BrowseView.tsx +4 -4
- package/src/components/resource/ResourceViewer.tsx +4 -7
- package/src/components/resource/__tests__/AnnotationHistory.test.tsx +16 -16
- package/src/components/resource/__tests__/BrowseView.test.tsx +2 -2
- package/src/components/resource/__tests__/HistoryEvent.test.tsx +1 -1
- package/src/components/resource/__tests__/ResourceViewer.mode-switch.test.tsx +1 -1
- package/src/components/resource/panels/AssessmentEntry.tsx +9 -11
- package/src/components/resource/panels/CommentEntry.tsx +10 -12
- package/src/components/resource/panels/HighlightEntry.tsx +9 -11
- package/src/components/resource/panels/ReferenceEntry.tsx +57 -104
- package/src/components/resource/panels/ReferencesPanel.css +94 -13
- package/src/components/resource/panels/ReferencesPanel.tsx +1 -2
- package/src/components/resource/panels/TagEntry.tsx +9 -11
- package/src/components/resource/panels/__tests__/AssistSection.test.tsx +7 -7
- package/src/components/resource/panels/__tests__/HighlightPanel.annotationProgress.test.tsx +2 -2
- package/src/components/resource/panels/__tests__/ReferenceEntry.test.tsx +64 -101
- package/src/components/resource/panels/__tests__/StatisticsPanel.test.tsx +1 -1
- package/src/components/resource/panels/__tests__/TaggingPanel.test.tsx +3 -3
- package/src/components/viewers/ImageViewer.tsx +3 -6
- package/src/components/viewers/__tests__/ImageViewer.test.tsx +3 -3
- package/src/features/admin-devops/__tests__/AdminDevOpsPage.test.tsx +5 -5
- package/src/features/admin-exchange/__tests__/AdminExchangePage.test.tsx +141 -0
- package/src/features/admin-exchange/__tests__/ExportCard.test.tsx +41 -0
- package/src/features/admin-exchange/__tests__/ImportCard.test.tsx +148 -0
- package/src/features/admin-exchange/__tests__/ImportProgress.test.tsx +106 -0
- package/src/features/admin-exchange/components/AdminExchangePage.tsx +120 -0
- package/src/features/admin-exchange/components/ExportCard.tsx +35 -0
- package/src/features/admin-exchange/components/ImportCard.tsx +188 -0
- package/src/features/admin-exchange/components/ImportProgress.tsx +86 -0
- package/src/features/admin-security/__tests__/AdminSecurityPage.test.tsx +3 -3
- package/src/features/moderate-entity-tags/__tests__/EntityTagsPage.test.tsx +2 -2
- package/src/features/moderate-recent/__tests__/RecentDocumentsPage.test.tsx +4 -4
- package/src/features/moderate-tag-schemas/__tests__/TagSchemasPage.test.tsx +3 -3
- package/src/features/moderation-linked-data/__tests__/LinkedDataPage.test.tsx +117 -0
- package/src/features/moderation-linked-data/components/LinkedDataPage.tsx +121 -0
- package/src/features/resource-compose/__tests__/ResourceComposePage.test.tsx +5 -5
- package/src/features/resource-compose/components/ResourceComposePage.tsx +56 -1
- package/src/features/resource-discovery/__tests__/ResourceCard.test.tsx +1 -1
- package/src/features/resource-discovery/__tests__/ResourceDiscoveryPage.test.tsx +2 -2
- package/src/features/resource-viewer/__tests__/AnnotationCreationPending.test.tsx +3 -3
- package/src/features/resource-viewer/__tests__/AnnotationDeletionIntegration.test.tsx +11 -10
- package/src/features/resource-viewer/__tests__/AnnotationProgressDismissal.test.tsx +2 -2
- package/src/features/resource-viewer/__tests__/BindFlowIntegration.test.tsx +22 -115
- package/src/features/resource-viewer/__tests__/DetectionFlowBug.test.tsx +3 -3
- package/src/features/resource-viewer/__tests__/DetectionFlowIntegration.test.tsx +20 -20
- package/src/features/resource-viewer/__tests__/ResourceMutations.test.tsx +7 -7
- package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +5 -21
- package/src/features/resource-viewer/__tests__/ToastNotifications.test.tsx +2 -2
- package/src/features/resource-viewer/__tests__/YieldFlowIntegration.test.tsx +45 -82
- package/src/features/resource-viewer/__tests__/annotation-progress-flow.test.tsx +4 -4
- package/src/features/resource-viewer/components/ResourceViewerPage.tsx +146 -72
- package/src/integrations/tailwind-plugin.js +3 -3
- package/src/styles/core/buttons.css +31 -0
- package/src/styles/features/exchange.css +404 -0
- package/src/styles/index.css +1 -0
- package/translations/ar.json +44 -4
- package/translations/bn.json +44 -4
- package/translations/cs.json +44 -4
- package/translations/da.json +130 -90
- package/translations/de.json +124 -84
- package/translations/el.json +44 -4
- package/translations/en.json +44 -4
- package/translations/es.json +44 -4
- package/translations/fa.json +44 -4
- package/translations/fi.json +70 -30
- package/translations/fr.json +44 -4
- package/translations/he.json +44 -4
- package/translations/hi.json +44 -4
- package/translations/id.json +45 -5
- package/translations/it.json +64 -24
- package/translations/ja.json +45 -5
- package/translations/ko.json +44 -4
- package/translations/ms.json +45 -5
- package/translations/nl.json +43 -3
- package/translations/no.json +106 -66
- package/translations/pl.json +44 -4
- package/translations/pt.json +45 -5
- package/translations/ro.json +44 -4
- package/translations/sv.json +44 -4
- package/translations/th.json +44 -4
- package/translations/tr.json +44 -4
- package/translations/uk.json +44 -4
- package/translations/vi.json +44 -4
- package/translations/zh.json +44 -4
- package/dist/PdfAnnotationCanvas.client-COQREPXU.mjs.map +0 -1
- package/dist/ar-7SUXNE34.mjs.map +0 -1
- package/dist/bn-XOET3DOI.mjs.map +0 -1
- package/dist/chunk-JH7BXE2P.mjs.map +0 -1
- package/dist/cs-X63DXX7L.mjs.map +0 -1
- package/dist/da-OWTCV57A.mjs.map +0 -1
- package/dist/de-77BMFDVF.mjs.map +0 -1
- package/dist/el-FIBNLH2V.mjs.map +0 -1
- package/dist/es-726NTS53.mjs.map +0 -1
- package/dist/fa-3N4CIWE6.mjs.map +0 -1
- package/dist/fi-JOM3M7Z4.mjs.map +0 -1
- package/dist/fr-56QSXS7E.mjs.map +0 -1
- package/dist/he-SNAXPJEK.mjs.map +0 -1
- package/dist/hi-CRBRD5TB.mjs.map +0 -1
- package/dist/id-BRCVLICF.mjs.map +0 -1
- package/dist/it-M2Z27BNB.mjs.map +0 -1
- package/dist/ja-TZUKW7HD.mjs.map +0 -1
- package/dist/ko-NKBGGOL6.mjs.map +0 -1
- package/dist/ms-XFXPN6RX.mjs.map +0 -1
- package/dist/nl-MVYXAS5C.mjs.map +0 -1
- package/dist/no-XOLO4JPV.mjs.map +0 -1
- package/dist/pl-TRWLMMC4.mjs.map +0 -1
- package/dist/pt-M3TE24UI.mjs.map +0 -1
- package/dist/ro-QBFG2T64.mjs.map +0 -1
- package/dist/sv-IUECBXWX.mjs.map +0 -1
- package/dist/th-US7KIN5Q.mjs.map +0 -1
- package/dist/tr-DWJ2FFUK.mjs.map +0 -1
- package/dist/uk-M4ZE4DPZ.mjs.map +0 -1
- package/dist/vi-FERZNPSH.mjs.map +0 -1
- package/dist/zh-3J2I3WYK.mjs.map +0 -1
- package/src/examples/ButtonUsageExample.tsx +0 -242
- package/src/examples/button-css-modules.module.css +0 -164
- package/src/examples/button-styled-components.tsx +0 -215
- package/src/examples/button-tailwind.css +0 -51
- /package/dist/{chunk-3JTO27MH.mjs.map → chunk-D4GAAQMM.mjs.map} +0 -0
- /package/dist/{chunk-Q2KV6Y2J.mjs.map → chunk-PFQYNPQJ.mjs.map} +0 -0
- /package/dist/{en-XWEPVTB4.mjs.map → en-AOSMPC2M.mjs.map} +0 -0
- /package/dist/{magic-string.es-7FJ3LUGB.mjs.map → magic-string.es-K77I4ZQN.mjs.map} +0 -0
|
@@ -53,20 +53,21 @@ import { ReferenceEntry } from '../ReferenceEntry';
|
|
|
53
53
|
|
|
54
54
|
const createMockReference = (overrides?: Partial<Annotation>): Annotation => ({
|
|
55
55
|
'@context': 'http://www.w3.org/ns/anno.jsonld',
|
|
56
|
-
id: '
|
|
56
|
+
id: 'ref-1',
|
|
57
57
|
type: 'Annotation',
|
|
58
58
|
motivation: 'linking',
|
|
59
59
|
created: '2024-06-15T12:00:00Z',
|
|
60
60
|
modified: '2024-06-15T12:00:00Z',
|
|
61
61
|
target: {
|
|
62
|
-
source: '
|
|
62
|
+
source: 'resource-1',
|
|
63
63
|
selector: {
|
|
64
64
|
type: 'TextQuoteSelector',
|
|
65
65
|
exact: 'referenced text',
|
|
66
66
|
},
|
|
67
67
|
},
|
|
68
68
|
body: {
|
|
69
|
-
|
|
69
|
+
type: 'SpecificResource',
|
|
70
|
+
source: 'linked-doc',
|
|
70
71
|
},
|
|
71
72
|
...overrides,
|
|
72
73
|
});
|
|
@@ -124,7 +125,7 @@ describe('ReferenceEntry', () => {
|
|
|
124
125
|
|
|
125
126
|
it('should show link icon when reference is resolved', () => {
|
|
126
127
|
mockIsBodyResolved.mockReturnValue(true);
|
|
127
|
-
mockGetBodySource.mockReturnValue('
|
|
128
|
+
mockGetBodySource.mockReturnValue('linked-doc');
|
|
128
129
|
|
|
129
130
|
const { container } = renderWithProviders(<ReferenceEntry {...defaultProps} />);
|
|
130
131
|
|
|
@@ -161,7 +162,7 @@ describe('ReferenceEntry', () => {
|
|
|
161
162
|
|
|
162
163
|
it('should render resolved document name when enriched', () => {
|
|
163
164
|
mockIsBodyResolved.mockReturnValue(true);
|
|
164
|
-
mockGetBodySource.mockReturnValue('
|
|
165
|
+
mockGetBodySource.mockReturnValue('linked-doc');
|
|
165
166
|
|
|
166
167
|
const enrichedRef = {
|
|
167
168
|
...createMockReference(),
|
|
@@ -247,7 +248,7 @@ describe('ReferenceEntry', () => {
|
|
|
247
248
|
await userEvent.click(entry);
|
|
248
249
|
|
|
249
250
|
expect(clickHandler).toHaveBeenCalledWith({
|
|
250
|
-
annotationId: '
|
|
251
|
+
annotationId: 'ref-1',
|
|
251
252
|
motivation: 'linking',
|
|
252
253
|
});
|
|
253
254
|
|
|
@@ -255,57 +256,57 @@ describe('ReferenceEntry', () => {
|
|
|
255
256
|
});
|
|
256
257
|
});
|
|
257
258
|
|
|
258
|
-
describe('
|
|
259
|
-
it('should
|
|
259
|
+
describe('Status icon — resolved reference', () => {
|
|
260
|
+
it('should navigate on 🔗 icon click', async () => {
|
|
260
261
|
mockIsBodyResolved.mockReturnValue(true);
|
|
261
|
-
mockGetBodySource.mockReturnValue('
|
|
262
|
+
mockGetBodySource.mockReturnValue('linked-doc');
|
|
262
263
|
|
|
263
264
|
const { container } = renderWithProviders(<ReferenceEntry {...defaultProps} />);
|
|
264
265
|
|
|
265
|
-
const
|
|
266
|
-
|
|
266
|
+
const icon = container.querySelector('.semiont-reference-icon')!;
|
|
267
|
+
await userEvent.click(icon);
|
|
268
|
+
|
|
269
|
+
expect(mockRoutes.resourceDetail).toHaveBeenCalledWith('linked-doc');
|
|
270
|
+
expect(mockNavigate).toHaveBeenCalledWith('/resources/linked-doc', { resourceId: 'linked-doc' });
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('should have clickable class when resolved', () => {
|
|
274
|
+
mockIsBodyResolved.mockReturnValue(true);
|
|
275
|
+
mockGetBodySource.mockReturnValue('linked-doc');
|
|
276
|
+
|
|
277
|
+
const { container } = renderWithProviders(<ReferenceEntry {...defaultProps} />);
|
|
278
|
+
|
|
279
|
+
const icon = container.querySelector('.semiont-reference-icon');
|
|
280
|
+
expect(icon).toHaveClass('semiont-reference-icon--clickable');
|
|
267
281
|
});
|
|
268
282
|
|
|
269
|
-
it('should show unlink button
|
|
283
|
+
it('should show hover-reveal unlink button in annotate mode', () => {
|
|
270
284
|
mockIsBodyResolved.mockReturnValue(true);
|
|
271
|
-
mockGetBodySource.mockReturnValue('
|
|
285
|
+
mockGetBodySource.mockReturnValue('linked-doc');
|
|
272
286
|
|
|
273
287
|
const { container } = renderWithProviders(
|
|
274
288
|
<ReferenceEntry {...defaultProps} annotateMode={true} />
|
|
275
289
|
);
|
|
276
290
|
|
|
277
|
-
const unlinkButton = container.querySelector('
|
|
291
|
+
const unlinkButton = container.querySelector('.semiont-reference-unlink');
|
|
278
292
|
expect(unlinkButton).toBeInTheDocument();
|
|
279
293
|
});
|
|
280
294
|
|
|
281
295
|
it('should not show unlink button when not in annotate mode', () => {
|
|
282
296
|
mockIsBodyResolved.mockReturnValue(true);
|
|
283
|
-
mockGetBodySource.mockReturnValue('
|
|
297
|
+
mockGetBodySource.mockReturnValue('linked-doc');
|
|
284
298
|
|
|
285
299
|
const { container } = renderWithProviders(
|
|
286
300
|
<ReferenceEntry {...defaultProps} annotateMode={false} />
|
|
287
301
|
);
|
|
288
302
|
|
|
289
|
-
const unlinkButton = container.querySelector('
|
|
303
|
+
const unlinkButton = container.querySelector('.semiont-reference-unlink');
|
|
290
304
|
expect(unlinkButton).not.toBeInTheDocument();
|
|
291
305
|
});
|
|
292
306
|
|
|
293
|
-
it('should navigate on open click', async () => {
|
|
294
|
-
mockIsBodyResolved.mockReturnValue(true);
|
|
295
|
-
mockGetBodySource.mockReturnValue('http://example.com/resources/linked-doc');
|
|
296
|
-
|
|
297
|
-
const { container } = renderWithProviders(<ReferenceEntry {...defaultProps} />);
|
|
298
|
-
|
|
299
|
-
const openButton = container.querySelector('button[title="ReferencesPanel.open"]')!;
|
|
300
|
-
await userEvent.click(openButton);
|
|
301
|
-
|
|
302
|
-
expect(mockRoutes.resourceDetail).toHaveBeenCalledWith('linked-doc');
|
|
303
|
-
expect(mockNavigate).toHaveBeenCalledWith('/resources/linked-doc', { resourceId: 'linked-doc' });
|
|
304
|
-
});
|
|
305
|
-
|
|
306
307
|
it('should emit bind:update-body on unlink click', async () => {
|
|
307
308
|
mockIsBodyResolved.mockReturnValue(true);
|
|
308
|
-
mockGetBodySource.mockReturnValue('
|
|
309
|
+
mockGetBodySource.mockReturnValue('linked-doc');
|
|
309
310
|
const unlinkHandler = vi.fn();
|
|
310
311
|
|
|
311
312
|
const { container, eventBus } = renderWithProviders(
|
|
@@ -315,11 +316,11 @@ describe('ReferenceEntry', () => {
|
|
|
315
316
|
|
|
316
317
|
const subscription = eventBus!.get('bind:update-body').subscribe(unlinkHandler);
|
|
317
318
|
|
|
318
|
-
const unlinkButton = container.querySelector('
|
|
319
|
+
const unlinkButton = container.querySelector('.semiont-reference-unlink')!;
|
|
319
320
|
await userEvent.click(unlinkButton);
|
|
320
321
|
|
|
321
322
|
expect(unlinkHandler).toHaveBeenCalledWith({
|
|
322
|
-
|
|
323
|
+
annotationId: 'ref-1',
|
|
323
324
|
resourceId: 'resource-1',
|
|
324
325
|
operations: [{ op: 'remove' }],
|
|
325
326
|
});
|
|
@@ -328,110 +329,72 @@ describe('ReferenceEntry', () => {
|
|
|
328
329
|
});
|
|
329
330
|
});
|
|
330
331
|
|
|
331
|
-
describe('
|
|
332
|
-
it('should
|
|
333
|
-
mockIsBodyResolved.mockReturnValue(false);
|
|
334
|
-
|
|
335
|
-
const { container } = renderWithProviders(
|
|
336
|
-
<ReferenceEntry {...defaultProps} annotateMode={true} />
|
|
337
|
-
);
|
|
338
|
-
|
|
339
|
-
expect(container.querySelector('button[title="ReferencesPanel.generate"]')).toBeInTheDocument();
|
|
340
|
-
expect(container.querySelector('button[title="ReferencesPanel.find"]')).toBeInTheDocument();
|
|
341
|
-
expect(container.querySelector('button[title="ReferencesPanel.create"]')).toBeInTheDocument();
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
it('should not show stub actions when not in annotate mode', () => {
|
|
332
|
+
describe('Status icon — stub reference', () => {
|
|
333
|
+
it('should emit bind:initiate on ❓ icon click in annotate mode', async () => {
|
|
345
334
|
mockIsBodyResolved.mockReturnValue(false);
|
|
346
|
-
|
|
347
|
-
const
|
|
348
|
-
<ReferenceEntry {...defaultProps} annotateMode={false} />
|
|
349
|
-
);
|
|
350
|
-
|
|
351
|
-
expect(container.querySelector('button[title="ReferencesPanel.generate"]')).not.toBeInTheDocument();
|
|
352
|
-
expect(container.querySelector('button[title="ReferencesPanel.find"]')).not.toBeInTheDocument();
|
|
353
|
-
expect(container.querySelector('button[title="ReferencesPanel.create"]')).not.toBeInTheDocument();
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
it('should emit yield:modal-open on generate click', async () => {
|
|
357
|
-
mockIsBodyResolved.mockReturnValue(false);
|
|
358
|
-
const generateHandler = vi.fn();
|
|
335
|
+
mockGetEntityTypes.mockReturnValue(['Person']);
|
|
336
|
+
const initiateHandler = vi.fn();
|
|
359
337
|
|
|
360
338
|
const { container, eventBus } = renderWithProviders(
|
|
361
339
|
<ReferenceEntry {...defaultProps} annotateMode={true} />,
|
|
362
340
|
{ returnEventBus: true }
|
|
363
341
|
);
|
|
364
342
|
|
|
365
|
-
const subscription = eventBus!.get('
|
|
343
|
+
const subscription = eventBus!.get('bind:initiate').subscribe(initiateHandler);
|
|
366
344
|
|
|
367
|
-
const
|
|
368
|
-
await userEvent.click(
|
|
345
|
+
const icon = container.querySelector('.semiont-reference-icon')!;
|
|
346
|
+
await userEvent.click(icon);
|
|
369
347
|
|
|
370
|
-
expect(
|
|
371
|
-
|
|
372
|
-
|
|
348
|
+
expect(initiateHandler).toHaveBeenCalledWith({
|
|
349
|
+
annotationId: 'ref-1',
|
|
350
|
+
resourceId: 'resource-1',
|
|
373
351
|
defaultTitle: 'referenced text',
|
|
352
|
+
entityTypes: ['Person'],
|
|
374
353
|
});
|
|
375
354
|
|
|
376
355
|
subscription.unsubscribe();
|
|
377
356
|
});
|
|
378
357
|
|
|
379
|
-
it('should
|
|
358
|
+
it('should have clickable class in annotate mode', () => {
|
|
380
359
|
mockIsBodyResolved.mockReturnValue(false);
|
|
381
|
-
const searchHandler = vi.fn();
|
|
382
360
|
|
|
383
|
-
const { container
|
|
384
|
-
<ReferenceEntry {...defaultProps} annotateMode={true}
|
|
385
|
-
{ returnEventBus: true }
|
|
361
|
+
const { container } = renderWithProviders(
|
|
362
|
+
<ReferenceEntry {...defaultProps} annotateMode={true} />
|
|
386
363
|
);
|
|
387
364
|
|
|
388
|
-
const
|
|
365
|
+
const icon = container.querySelector('.semiont-reference-icon');
|
|
366
|
+
expect(icon).toHaveClass('semiont-reference-icon--clickable');
|
|
367
|
+
});
|
|
389
368
|
|
|
390
|
-
|
|
391
|
-
|
|
369
|
+
it('should not be clickable in browse mode', () => {
|
|
370
|
+
mockIsBodyResolved.mockReturnValue(false);
|
|
392
371
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
});
|
|
372
|
+
const { container } = renderWithProviders(
|
|
373
|
+
<ReferenceEntry {...defaultProps} annotateMode={false} />
|
|
374
|
+
);
|
|
397
375
|
|
|
398
|
-
|
|
376
|
+
const icon = container.querySelector('.semiont-reference-icon');
|
|
377
|
+
expect(icon).not.toHaveClass('semiont-reference-icon--clickable');
|
|
399
378
|
});
|
|
400
379
|
|
|
401
|
-
it('should emit bind:
|
|
380
|
+
it('should not emit bind:initiate on ❓ icon click in browse mode', async () => {
|
|
402
381
|
mockIsBodyResolved.mockReturnValue(false);
|
|
403
|
-
|
|
404
|
-
const createHandler = vi.fn();
|
|
382
|
+
const initiateHandler = vi.fn();
|
|
405
383
|
|
|
406
384
|
const { container, eventBus } = renderWithProviders(
|
|
407
|
-
<ReferenceEntry {...defaultProps} annotateMode={
|
|
385
|
+
<ReferenceEntry {...defaultProps} annotateMode={false} />,
|
|
408
386
|
{ returnEventBus: true }
|
|
409
387
|
);
|
|
410
388
|
|
|
411
|
-
const subscription = eventBus!.get('bind:
|
|
389
|
+
const subscription = eventBus!.get('bind:initiate').subscribe(initiateHandler);
|
|
412
390
|
|
|
413
|
-
const
|
|
414
|
-
await userEvent.click(
|
|
391
|
+
const icon = container.querySelector('.semiont-reference-icon')!;
|
|
392
|
+
await userEvent.click(icon);
|
|
415
393
|
|
|
416
|
-
expect(
|
|
417
|
-
annotationUri: 'http://example.com/annotations/ref-1',
|
|
418
|
-
title: 'referenced text',
|
|
419
|
-
entityTypes: ['Person'],
|
|
420
|
-
});
|
|
394
|
+
expect(initiateHandler).not.toHaveBeenCalled();
|
|
421
395
|
|
|
422
396
|
subscription.unsubscribe();
|
|
423
397
|
});
|
|
424
|
-
|
|
425
|
-
it('should set data-generating on generate button', () => {
|
|
426
|
-
mockIsBodyResolved.mockReturnValue(false);
|
|
427
|
-
|
|
428
|
-
const { container } = renderWithProviders(
|
|
429
|
-
<ReferenceEntry {...defaultProps} annotateMode={true} isGenerating={true} />
|
|
430
|
-
);
|
|
431
|
-
|
|
432
|
-
const generateButton = container.querySelector('button[title="ReferencesPanel.generate"]');
|
|
433
|
-
expect(generateButton).toHaveAttribute('data-generating', 'true');
|
|
434
|
-
});
|
|
435
398
|
});
|
|
436
399
|
|
|
437
400
|
describe('data-type attribute', () => {
|
|
@@ -33,7 +33,7 @@ const createMockAnnotation = (overrides?: Partial<Annotation>): Annotation => ({
|
|
|
33
33
|
created: '2024-06-15T12:00:00Z',
|
|
34
34
|
modified: '2024-06-15T12:00:00Z',
|
|
35
35
|
target: {
|
|
36
|
-
source: '
|
|
36
|
+
source: '1',
|
|
37
37
|
selector: {
|
|
38
38
|
type: 'TextQuoteSelector',
|
|
39
39
|
exact: 'some text',
|
|
@@ -542,7 +542,7 @@ describe('TaggingPanel Component', () => {
|
|
|
542
542
|
/>
|
|
543
543
|
);
|
|
544
544
|
|
|
545
|
-
const annotateButton = screen.getByRole('button', { name:
|
|
545
|
+
const annotateButton = screen.getByRole('button', { name: /✨\s*Annotate/i });
|
|
546
546
|
expect(annotateButton).toBeDisabled();
|
|
547
547
|
});
|
|
548
548
|
|
|
@@ -557,7 +557,7 @@ describe('TaggingPanel Component', () => {
|
|
|
557
557
|
const issueCheckbox = screen.getByLabelText(/Issue/);
|
|
558
558
|
await userEvent.click(issueCheckbox);
|
|
559
559
|
|
|
560
|
-
const annotateButton = screen.getByRole('button', { name:
|
|
560
|
+
const annotateButton = screen.getByRole('button', { name: /✨\s*Annotate/i });
|
|
561
561
|
expect(annotateButton).not.toBeDisabled();
|
|
562
562
|
});
|
|
563
563
|
|
|
@@ -577,7 +577,7 @@ describe('TaggingPanel Component', () => {
|
|
|
577
577
|
await userEvent.click(issueCheckbox);
|
|
578
578
|
await userEvent.click(ruleCheckbox);
|
|
579
579
|
|
|
580
|
-
const annotateButton = screen.getByRole('button', { name:
|
|
580
|
+
const annotateButton = screen.getByRole('button', { name: /✨\s*Annotate/i });
|
|
581
581
|
await userEvent.click(annotateButton);
|
|
582
582
|
|
|
583
583
|
await waitFor(() => {
|
|
@@ -1,18 +1,15 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ResourceId } from '@semiont/core';
|
|
2
2
|
|
|
3
3
|
interface ImageViewerProps {
|
|
4
|
-
resourceUri:
|
|
4
|
+
resourceUri: ResourceId;
|
|
5
5
|
mimeType: string;
|
|
6
6
|
alt?: string;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export function ImageViewer({ resourceUri, alt = 'Resource image' }: ImageViewerProps) {
|
|
10
|
-
// Extract resource ID from W3C canonical URI (last segment of path)
|
|
11
|
-
const resourceId = resourceUri.split('/').pop();
|
|
12
|
-
|
|
13
10
|
// Use Next.js API route proxy instead of direct backend call
|
|
14
11
|
// This allows us to add authentication headers which <img> tags can't send
|
|
15
|
-
const imageUrl = `/api/resources/${
|
|
12
|
+
const imageUrl = `/api/resources/${resourceUri}`;
|
|
16
13
|
|
|
17
14
|
return (
|
|
18
15
|
<div className="semiont-image-viewer">
|
|
@@ -4,11 +4,11 @@ import { screen } from '@testing-library/react';
|
|
|
4
4
|
import '@testing-library/jest-dom';
|
|
5
5
|
import { renderWithProviders } from '../../../test-utils';
|
|
6
6
|
import { ImageViewer } from '../ImageViewer';
|
|
7
|
-
import type {
|
|
7
|
+
import type { ResourceId } from '@semiont/core';
|
|
8
8
|
|
|
9
9
|
describe('ImageViewer', () => {
|
|
10
10
|
const defaultProps = {
|
|
11
|
-
resourceUri: '
|
|
11
|
+
resourceUri: 'abc-123' as ResourceId,
|
|
12
12
|
mimeType: 'image/png',
|
|
13
13
|
};
|
|
14
14
|
|
|
@@ -38,7 +38,7 @@ describe('ImageViewer', () => {
|
|
|
38
38
|
it('should extract the last segment of the URI as resource ID', () => {
|
|
39
39
|
renderWithProviders(
|
|
40
40
|
<ImageViewer
|
|
41
|
-
resourceUri={'
|
|
41
|
+
resourceUri={'resource-xyz' as ResourceId}
|
|
42
42
|
mimeType="image/jpeg"
|
|
43
43
|
/>
|
|
44
44
|
);
|
|
@@ -285,7 +285,7 @@ describe('AdminDevOpsPage', () => {
|
|
|
285
285
|
|
|
286
286
|
expect(ToolbarPanels).toHaveBeenCalledWith(
|
|
287
287
|
expect.objectContaining({ theme: 'dark' }),
|
|
288
|
-
|
|
288
|
+
undefined,
|
|
289
289
|
);
|
|
290
290
|
});
|
|
291
291
|
|
|
@@ -296,7 +296,7 @@ describe('AdminDevOpsPage', () => {
|
|
|
296
296
|
|
|
297
297
|
expect(ToolbarPanels).toHaveBeenCalledWith(
|
|
298
298
|
expect.objectContaining({ showLineNumbers: true }),
|
|
299
|
-
|
|
299
|
+
undefined,
|
|
300
300
|
);
|
|
301
301
|
});
|
|
302
302
|
|
|
@@ -307,7 +307,7 @@ describe('AdminDevOpsPage', () => {
|
|
|
307
307
|
|
|
308
308
|
expect(ToolbarPanels).toHaveBeenCalledWith(
|
|
309
309
|
expect.objectContaining({ activePanel: 'settings' }),
|
|
310
|
-
|
|
310
|
+
undefined,
|
|
311
311
|
);
|
|
312
312
|
});
|
|
313
313
|
|
|
@@ -318,7 +318,7 @@ describe('AdminDevOpsPage', () => {
|
|
|
318
318
|
|
|
319
319
|
expect(Toolbar).toHaveBeenCalledWith(
|
|
320
320
|
expect.objectContaining({ context: 'simple' }),
|
|
321
|
-
|
|
321
|
+
undefined,
|
|
322
322
|
);
|
|
323
323
|
});
|
|
324
324
|
|
|
@@ -329,7 +329,7 @@ describe('AdminDevOpsPage', () => {
|
|
|
329
329
|
|
|
330
330
|
expect(Toolbar).toHaveBeenCalledWith(
|
|
331
331
|
expect.objectContaining({ activePanel: 'help' }),
|
|
332
|
-
|
|
332
|
+
undefined,
|
|
333
333
|
);
|
|
334
334
|
});
|
|
335
335
|
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for AdminExchangePage component
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
6
|
+
import { render, screen } from '@testing-library/react';
|
|
7
|
+
import { AdminExchangePage } from '../components/AdminExchangePage';
|
|
8
|
+
import type { AdminExchangePageProps } from '../components/AdminExchangePage';
|
|
9
|
+
|
|
10
|
+
const createProps = (overrides?: Partial<AdminExchangePageProps>): AdminExchangePageProps => ({
|
|
11
|
+
onExport: vi.fn(),
|
|
12
|
+
isExporting: false,
|
|
13
|
+
onFileSelected: vi.fn(),
|
|
14
|
+
onImport: vi.fn(),
|
|
15
|
+
onCancelImport: vi.fn(),
|
|
16
|
+
selectedFile: null,
|
|
17
|
+
preview: null,
|
|
18
|
+
isImporting: false,
|
|
19
|
+
importPhase: null,
|
|
20
|
+
theme: 'light',
|
|
21
|
+
showLineNumbers: false,
|
|
22
|
+
activePanel: null,
|
|
23
|
+
translations: {
|
|
24
|
+
title: 'Backup & Restore',
|
|
25
|
+
subtitle: 'Back up and restore your knowledge base',
|
|
26
|
+
export: {
|
|
27
|
+
title: 'Backup',
|
|
28
|
+
description: 'Create a lossless backup',
|
|
29
|
+
exportButton: 'Create Backup',
|
|
30
|
+
exporting: 'Creating backup…',
|
|
31
|
+
},
|
|
32
|
+
import: {
|
|
33
|
+
title: 'Restore',
|
|
34
|
+
description: 'Restore from a backup',
|
|
35
|
+
dropzoneLabel: 'Drop a file here',
|
|
36
|
+
dropzoneActive: 'Drop to upload',
|
|
37
|
+
detectedFormat: 'Format',
|
|
38
|
+
statsPreview: 'Preview',
|
|
39
|
+
importButton: 'Restore',
|
|
40
|
+
importing: 'Restoring…',
|
|
41
|
+
importConfirmTitle: 'Confirm',
|
|
42
|
+
importConfirmMessage: 'Cannot undo.',
|
|
43
|
+
confirmImport: 'Proceed',
|
|
44
|
+
cancelImport: 'Cancel',
|
|
45
|
+
},
|
|
46
|
+
progress: {
|
|
47
|
+
phaseStarted: 'Starting…',
|
|
48
|
+
phaseEntityTypes: 'Entity types…',
|
|
49
|
+
phaseResources: 'Resources…',
|
|
50
|
+
phaseAnnotations: 'Annotations…',
|
|
51
|
+
phaseComplete: 'Complete',
|
|
52
|
+
phaseError: 'Failed',
|
|
53
|
+
hashChainValid: 'Hash valid',
|
|
54
|
+
hashChainInvalid: 'Hash invalid',
|
|
55
|
+
streams: 'Streams',
|
|
56
|
+
events: 'Events',
|
|
57
|
+
blobs: 'Blobs',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
ToolbarPanels: () => <div data-testid="toolbar-panels" />,
|
|
61
|
+
Toolbar: () => <div data-testid="toolbar" />,
|
|
62
|
+
...overrides,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe('AdminExchangePage', () => {
|
|
66
|
+
it('renders page title and subtitle', () => {
|
|
67
|
+
render(<AdminExchangePage {...createProps()} />);
|
|
68
|
+
expect(screen.getByText('Backup & Restore')).toBeInTheDocument();
|
|
69
|
+
expect(screen.getByText('Back up and restore your knowledge base')).toBeInTheDocument();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('renders ExportCard', () => {
|
|
73
|
+
render(<AdminExchangePage {...createProps()} />);
|
|
74
|
+
expect(screen.getByRole('heading', { name: 'Backup' })).toBeInTheDocument();
|
|
75
|
+
expect(screen.getByText('Create a lossless backup')).toBeInTheDocument();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('renders ImportCard', () => {
|
|
79
|
+
render(<AdminExchangePage {...createProps()} />);
|
|
80
|
+
expect(screen.getByRole('heading', { name: 'Restore' })).toBeInTheDocument();
|
|
81
|
+
expect(screen.getByText('Restore from a backup')).toBeInTheDocument();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('renders toolbar components', () => {
|
|
85
|
+
render(<AdminExchangePage {...createProps()} />);
|
|
86
|
+
expect(screen.getByTestId('toolbar-panels')).toBeInTheDocument();
|
|
87
|
+
expect(screen.getByTestId('toolbar')).toBeInTheDocument();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('does not render ImportProgress when importPhase is null', () => {
|
|
91
|
+
const { container } = render(<AdminExchangePage {...createProps()} />);
|
|
92
|
+
expect(container.querySelector('.semiont-exchange__progress')).not.toBeInTheDocument();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('renders ImportProgress when importPhase is set', () => {
|
|
96
|
+
render(<AdminExchangePage {...createProps({ importPhase: 'started' })} />);
|
|
97
|
+
expect(screen.getByText('Starting…')).toBeInTheDocument();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('renders ImportProgress with backup result on completion', () => {
|
|
101
|
+
render(<AdminExchangePage {...createProps({
|
|
102
|
+
importPhase: 'complete',
|
|
103
|
+
importResult: { stats: { streams: 5, events: 42, blobs: 3 }, hashChainValid: true },
|
|
104
|
+
})} />);
|
|
105
|
+
expect(screen.getByText('Complete')).toBeInTheDocument();
|
|
106
|
+
expect(screen.getByText('5')).toBeInTheDocument();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('applies panel-open class when common panel is active', () => {
|
|
110
|
+
const { container } = render(<AdminExchangePage {...createProps({ activePanel: 'user' })} />);
|
|
111
|
+
expect(container.querySelector('.semiont-page--panel-open')).toBeInTheDocument();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('does not apply panel-open class when no panel is active', () => {
|
|
115
|
+
const { container } = render(<AdminExchangePage {...createProps({ activePanel: null })} />);
|
|
116
|
+
expect(container.querySelector('.semiont-page--panel-open')).not.toBeInTheDocument();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('passes theme to ToolbarPanels', () => {
|
|
120
|
+
const ToolbarPanels = vi.fn(() => <div data-testid="toolbar-panels" />);
|
|
121
|
+
render(<AdminExchangePage {...createProps({ theme: 'dark', ToolbarPanels })} />);
|
|
122
|
+
expect(ToolbarPanels).toHaveBeenCalledWith(
|
|
123
|
+
expect.objectContaining({ theme: 'dark' }),
|
|
124
|
+
undefined,
|
|
125
|
+
);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('passes context to Toolbar', () => {
|
|
129
|
+
const Toolbar = vi.fn(() => <div data-testid="toolbar" />);
|
|
130
|
+
render(<AdminExchangePage {...createProps({ Toolbar })} />);
|
|
131
|
+
expect(Toolbar).toHaveBeenCalledWith(
|
|
132
|
+
expect.objectContaining({ context: 'simple' }),
|
|
133
|
+
undefined,
|
|
134
|
+
);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('renders cards in grid layout', () => {
|
|
138
|
+
const { container } = render(<AdminExchangePage {...createProps()} />);
|
|
139
|
+
expect(container.querySelector('.semiont-exchange__cards')).toBeInTheDocument();
|
|
140
|
+
});
|
|
141
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for ExportCard component
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
6
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
7
|
+
import { ExportCard } from '../components/ExportCard';
|
|
8
|
+
import type { ExportCardProps } from '../components/ExportCard';
|
|
9
|
+
|
|
10
|
+
const createProps = (overrides?: Partial<ExportCardProps>): ExportCardProps => ({
|
|
11
|
+
onExport: vi.fn(),
|
|
12
|
+
isExporting: false,
|
|
13
|
+
translations: {
|
|
14
|
+
title: 'Backup',
|
|
15
|
+
description: 'Create a lossless backup',
|
|
16
|
+
exportButton: 'Create Backup',
|
|
17
|
+
exporting: 'Creating backup…',
|
|
18
|
+
},
|
|
19
|
+
...overrides,
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('ExportCard', () => {
|
|
23
|
+
it('renders title and description', () => {
|
|
24
|
+
render(<ExportCard {...createProps()} />);
|
|
25
|
+
expect(screen.getByRole('heading', { name: 'Backup' })).toBeInTheDocument();
|
|
26
|
+
expect(screen.getByText('Create a lossless backup')).toBeInTheDocument();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('calls onExport when button is clicked', () => {
|
|
30
|
+
const onExport = vi.fn();
|
|
31
|
+
render(<ExportCard {...createProps({ onExport })} />);
|
|
32
|
+
fireEvent.click(screen.getByRole('button', { name: 'Create Backup' }));
|
|
33
|
+
expect(onExport).toHaveBeenCalled();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('disables button and shows exporting text when isExporting', () => {
|
|
37
|
+
render(<ExportCard {...createProps({ isExporting: true })} />);
|
|
38
|
+
const button = screen.getByRole('button', { name: 'Creating backup…' });
|
|
39
|
+
expect(button).toBeDisabled();
|
|
40
|
+
});
|
|
41
|
+
});
|