@semiont/react-ui 0.2.35-build.100 → 0.2.35-build.102
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/{EventBusContext-DMI4uwYk.d.mts → EventBusContext-BsIUjdWP.d.mts} +4 -4
- package/dist/{PdfAnnotationCanvas.client-HNYRKFDS.mjs → PdfAnnotationCanvas.client-COQREPXU.mjs} +7 -7
- package/dist/PdfAnnotationCanvas.client-COQREPXU.mjs.map +1 -0
- package/dist/{chunk-YI5IX5ZA.mjs → chunk-2HGWOLVN.mjs} +1 -1
- package/dist/{chunk-YI5IX5ZA.mjs.map → chunk-2HGWOLVN.mjs.map} +1 -1
- package/dist/{chunk-MWQ5CNKW.mjs → chunk-ZPV43WN2.mjs} +11 -11
- package/dist/chunk-ZPV43WN2.mjs.map +1 -0
- package/dist/index.d.mts +169 -165
- package/dist/index.mjs +316 -312
- package/dist/index.mjs.map +1 -1
- package/dist/test-utils.d.mts +2 -2
- package/dist/test-utils.mjs +1 -1
- package/package.json +1 -1
- package/src/components/AnnotateReferencesProgressWidget.tsx +5 -5
- package/src/components/CodeMirrorRenderer.tsx +5 -5
- package/src/components/Toolbar.tsx +2 -2
- package/src/components/annotation/AnnotateToolbar.tsx +9 -9
- package/src/components/annotation/__tests__/AnnotateToolbar.test.tsx +17 -17
- package/src/components/image-annotation/AnnotationOverlay.tsx +10 -10
- package/src/components/image-annotation/SvgDrawingCanvas.tsx +4 -4
- package/src/components/navigation/CollapsibleResourceNavigation.tsx +7 -7
- package/src/components/navigation/ObservableLink.tsx +3 -3
- package/src/components/navigation/SimpleNavigation.tsx +2 -2
- package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +8 -8
- package/src/components/resource/AnnotateView.tsx +12 -12
- package/src/components/resource/BrowseView.tsx +9 -9
- package/src/components/resource/ResourceViewer.tsx +23 -23
- package/src/components/resource/__tests__/BrowseView.test.tsx +27 -27
- package/src/components/resource/__tests__/ResourceViewer.mode-switch.test.tsx +1 -1
- package/src/components/resource/panels/AssessmentEntry.tsx +2 -2
- package/src/components/resource/panels/AssessmentPanel.tsx +7 -7
- package/src/components/resource/panels/AssistSection.tsx +5 -5
- package/src/components/resource/panels/CommentEntry.tsx +2 -2
- package/src/components/resource/panels/CommentsPanel.tsx +7 -7
- package/src/components/resource/panels/HighlightEntry.tsx +2 -2
- package/src/components/resource/panels/HighlightPanel.tsx +5 -5
- package/src/components/resource/panels/ReferenceEntry.tsx +8 -8
- package/src/components/resource/panels/ReferencesPanel.tsx +10 -10
- package/src/components/resource/panels/ResourceInfoPanel.tsx +6 -6
- package/src/components/resource/panels/TagEntry.tsx +2 -2
- package/src/components/resource/panels/TaggingPanel.tsx +8 -8
- package/src/components/resource/panels/UnifiedAnnotationsPanel.tsx +2 -2
- package/src/components/resource/panels/__tests__/AssessmentPanel.test.tsx +4 -4
- package/src/components/resource/panels/__tests__/AssistSection.test.tsx +4 -4
- package/src/components/resource/panels/__tests__/CommentEntry.test.tsx +8 -8
- package/src/components/resource/panels/__tests__/CommentsPanel.test.tsx +3 -3
- package/src/components/resource/panels/__tests__/HighlightPanel.annotationProgress.test.tsx +1 -1
- package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +3 -3
- package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +9 -9
- package/src/components/resource/panels/__tests__/TaggingPanel.test.tsx +5 -5
- package/src/features/admin-devops/components/AdminDevOpsPage.tsx +2 -1
- package/src/features/admin-security/components/AdminSecurityPage.tsx +2 -1
- package/src/features/admin-users/components/AdminUsersPage.tsx +2 -1
- package/src/features/moderate-entity-tags/components/EntityTagsPage.tsx +2 -1
- package/src/features/moderate-recent/components/RecentDocumentsPage.tsx +2 -1
- package/src/features/moderate-tag-schemas/components/TagSchemasPage.tsx +2 -1
- package/src/features/resource-compose/components/ResourceComposePage.tsx +2 -1
- package/src/features/resource-discovery/components/ResourceDiscoveryPage.tsx +2 -1
- package/src/features/resource-viewer/__tests__/AnnotationCreationPending.test.tsx +26 -26
- package/src/features/resource-viewer/__tests__/AnnotationDeletionIntegration.test.tsx +21 -21
- package/src/features/resource-viewer/__tests__/AnnotationProgressDismissal.test.tsx +23 -23
- package/src/features/resource-viewer/__tests__/{ResolutionFlowIntegration.test.tsx → BindFlowIntegration.test.tsx} +49 -49
- package/src/features/resource-viewer/__tests__/DetectionFlowBug.test.tsx +18 -18
- package/src/features/resource-viewer/__tests__/DetectionFlowIntegration.test.tsx +19 -19
- package/src/features/resource-viewer/__tests__/ResourceMutations.test.tsx +19 -19
- package/src/features/resource-viewer/__tests__/ToastNotifications.test.tsx +13 -13
- package/src/features/resource-viewer/__tests__/{GenerationFlowIntegration.test.tsx → YieldFlowIntegration.test.tsx} +34 -34
- package/src/features/resource-viewer/__tests__/annotation-progress-flow.test.tsx +11 -11
- package/src/features/resource-viewer/components/ResourceViewerPage.tsx +55 -55
- package/dist/PdfAnnotationCanvas.client-HNYRKFDS.mjs.map +0 -1
- package/dist/chunk-MWQ5CNKW.mjs.map +0 -1
|
@@ -11,7 +11,7 @@ import type { components, paths, Selector } from '@semiont/core';
|
|
|
11
11
|
import { getTextPositionSelector, getTargetSelector } from '@semiont/api-client';
|
|
12
12
|
import { PanelHeader } from './PanelHeader';
|
|
13
13
|
import './ReferencesPanel.css';
|
|
14
|
-
import type {
|
|
14
|
+
import type { MarkProgress } from '@semiont/core';
|
|
15
15
|
|
|
16
16
|
type Annotation = components['schemas']['Annotation'];
|
|
17
17
|
type Motivation = components['schemas']['Motivation'];
|
|
@@ -45,7 +45,7 @@ interface Props {
|
|
|
45
45
|
// Generic panel props
|
|
46
46
|
annotations?: Annotation[];
|
|
47
47
|
isAssisting: boolean;
|
|
48
|
-
progress:
|
|
48
|
+
progress: MarkProgress | null;
|
|
49
49
|
annotateMode?: boolean;
|
|
50
50
|
Link: React.ComponentType<LinkComponentProps>;
|
|
51
51
|
routes: RouteBuilder;
|
|
@@ -65,9 +65,9 @@ interface Props {
|
|
|
65
65
|
* Panel for managing reference annotations with entity type annotation
|
|
66
66
|
*
|
|
67
67
|
* @emits annotate:detect-request - Start reference annotation. Payload: { motivation: 'linking', options: { entityTypes: string[], includeDescriptiveReferences: boolean } }
|
|
68
|
-
* @emits
|
|
69
|
-
* @emits
|
|
70
|
-
* @subscribes
|
|
68
|
+
* @emits mark:create - Create new reference annotation. Payload: { motivation: 'linking', selector: Selector | Selector[], body: Body[] }
|
|
69
|
+
* @emits mark:cancel-pending - Cancel pending reference annotation. Payload: undefined
|
|
70
|
+
* @subscribes browse:click - Annotation clicked. Payload: { annotationId: string }
|
|
71
71
|
*/
|
|
72
72
|
export function ReferencesPanel({
|
|
73
73
|
annotations = [],
|
|
@@ -196,13 +196,13 @@ export function ReferencesPanel({
|
|
|
196
196
|
}, []);
|
|
197
197
|
|
|
198
198
|
useEventSubscriptions({
|
|
199
|
-
'
|
|
199
|
+
'browse:click': handleAnnotationClick,
|
|
200
200
|
});
|
|
201
201
|
|
|
202
202
|
// Clear log when starting new annotation
|
|
203
203
|
const handleAssist = () => {
|
|
204
204
|
setLastDetectionLog(null);
|
|
205
|
-
eventBus.get('
|
|
205
|
+
eventBus.get('mark:assist-request').next({
|
|
206
206
|
motivation: 'linking',
|
|
207
207
|
options: {
|
|
208
208
|
entityTypes: selectedEntityTypes,
|
|
@@ -245,7 +245,7 @@ export function ReferencesPanel({
|
|
|
245
245
|
const handleCreateReference = () => {
|
|
246
246
|
if (pendingAnnotation) {
|
|
247
247
|
const entityType = pendingEntityTypes.join(',') || undefined;
|
|
248
|
-
eventBus.get('
|
|
248
|
+
eventBus.get('mark:create').next({
|
|
249
249
|
motivation: 'linking',
|
|
250
250
|
selector: pendingAnnotation.selector,
|
|
251
251
|
body: entityType ? [{ type: 'TextualBody', value: entityType, purpose: 'tagging' }] : [],
|
|
@@ -260,7 +260,7 @@ export function ReferencesPanel({
|
|
|
260
260
|
|
|
261
261
|
const handleEscape = (e: KeyboardEvent) => {
|
|
262
262
|
if (e.key === 'Escape') {
|
|
263
|
-
eventBus.get('
|
|
263
|
+
eventBus.get('mark:cancel-pending').next(undefined);
|
|
264
264
|
setPendingEntityTypes([]);
|
|
265
265
|
}
|
|
266
266
|
};
|
|
@@ -312,7 +312,7 @@ export function ReferencesPanel({
|
|
|
312
312
|
<div className="semiont-annotation-prompt__actions">
|
|
313
313
|
<button
|
|
314
314
|
onClick={() => {
|
|
315
|
-
eventBus.get('
|
|
315
|
+
eventBus.get('mark:cancel-pending').next(undefined);
|
|
316
316
|
setPendingEntityTypes([]);
|
|
317
317
|
}}
|
|
318
318
|
className="semiont-button semiont-button--secondary"
|
|
@@ -16,9 +16,9 @@ interface Props {
|
|
|
16
16
|
/**
|
|
17
17
|
* Panel for displaying resource metadata and management actions
|
|
18
18
|
*
|
|
19
|
-
* @emits
|
|
20
|
-
* @emits
|
|
21
|
-
* @emits
|
|
19
|
+
* @emits yield:clone - Clone this resource. Payload: undefined
|
|
20
|
+
* @emits mark:unarchive - Unarchive this resource. Payload: undefined
|
|
21
|
+
* @emits mark:archive - Archive this resource. Payload: undefined
|
|
22
22
|
*/
|
|
23
23
|
export function ResourceInfoPanel({
|
|
24
24
|
documentEntityTypes,
|
|
@@ -97,7 +97,7 @@ export function ResourceInfoPanel({
|
|
|
97
97
|
{/* Clone Action */}
|
|
98
98
|
<div className="semiont-resource-info-panel__action-section">
|
|
99
99
|
<button
|
|
100
|
-
onClick={() => eventBus.get('
|
|
100
|
+
onClick={() => eventBus.get('yield:clone').next(undefined)}
|
|
101
101
|
className="semiont-resource-button semiont-resource-button--secondary"
|
|
102
102
|
>
|
|
103
103
|
🔗 {t('clone')}
|
|
@@ -112,7 +112,7 @@ export function ResourceInfoPanel({
|
|
|
112
112
|
{isArchived ? (
|
|
113
113
|
<>
|
|
114
114
|
<button
|
|
115
|
-
onClick={() => eventBus.get('
|
|
115
|
+
onClick={() => eventBus.get('mark:unarchive').next(undefined)}
|
|
116
116
|
className="semiont-resource-button semiont-resource-button--secondary"
|
|
117
117
|
>
|
|
118
118
|
📤 {t('unarchive')}
|
|
@@ -124,7 +124,7 @@ export function ResourceInfoPanel({
|
|
|
124
124
|
) : (
|
|
125
125
|
<>
|
|
126
126
|
<button
|
|
127
|
-
onClick={() => eventBus.get('
|
|
127
|
+
onClick={() => eventBus.get('mark:archive').next(undefined)}
|
|
128
128
|
className="semiont-resource-button semiont-resource-button--archive"
|
|
129
129
|
>
|
|
130
130
|
📦 {t('archive')}
|
|
@@ -6,7 +6,7 @@ import { getAnnotationExactText } from '@semiont/api-client';
|
|
|
6
6
|
import { getTagCategory, getTagSchemaId } from '@semiont/ontology';
|
|
7
7
|
import { getTagSchema } from '../../../lib/tag-schemas';
|
|
8
8
|
import { useEventBus } from '../../../contexts/EventBusContext';
|
|
9
|
-
import { useHoverEmitter } from '../../../hooks/
|
|
9
|
+
import { useHoverEmitter } from '../../../hooks/useBeckonFlow';
|
|
10
10
|
|
|
11
11
|
type Annotation = components['schemas']['Annotation'];
|
|
12
12
|
|
|
@@ -37,7 +37,7 @@ export const TagEntry = forwardRef<HTMLDivElement, TagEntryProps>(
|
|
|
37
37
|
<div
|
|
38
38
|
ref={ref}
|
|
39
39
|
onClick={() => {
|
|
40
|
-
eventBus.get('
|
|
40
|
+
eventBus.get('browse:click').next({ annotationId: tag.id, motivation: tag.motivation });
|
|
41
41
|
}}
|
|
42
42
|
{...hoverProps}
|
|
43
43
|
className={`semiont-annotation-entry${isHovered ? ' semiont-annotation-pulse' : ''}`}
|
|
@@ -60,9 +60,9 @@ interface TaggingPanelProps {
|
|
|
60
60
|
* Panel for managing tag annotations with schema-based annotation
|
|
61
61
|
*
|
|
62
62
|
* @emits annotate:detect-request - Start tag annotation. Payload: { motivation: 'tagging', options: { schemaId: string, categories: string[] } }
|
|
63
|
-
* @emits
|
|
64
|
-
* @emits
|
|
65
|
-
* @subscribes
|
|
63
|
+
* @emits mark:cancel-pending - Cancel pending tag annotation. Payload: undefined
|
|
64
|
+
* @emits mark:create - Create new tag annotation. Payload: { motivation: 'tagging', selector: Selector | Selector[], body: Body[] }
|
|
65
|
+
* @subscribes browse:click - Annotation clicked. Payload: { annotationId: string }
|
|
66
66
|
*/
|
|
67
67
|
export function TaggingPanel({
|
|
68
68
|
annotations,
|
|
@@ -102,7 +102,7 @@ export function TaggingPanel({
|
|
|
102
102
|
}, []);
|
|
103
103
|
|
|
104
104
|
useEventSubscriptions({
|
|
105
|
-
'
|
|
105
|
+
'browse:click': handleAnnotationClick,
|
|
106
106
|
});
|
|
107
107
|
|
|
108
108
|
// Direct ref management
|
|
@@ -195,7 +195,7 @@ export function TaggingPanel({
|
|
|
195
195
|
|
|
196
196
|
const handleAssist = () => {
|
|
197
197
|
if (selectedCategories.size > 0) {
|
|
198
|
-
eventBus.get('
|
|
198
|
+
eventBus.get('mark:assist-request').next({
|
|
199
199
|
motivation: 'tagging',
|
|
200
200
|
options: {
|
|
201
201
|
schemaId: selectedSchemaId,
|
|
@@ -212,7 +212,7 @@ export function TaggingPanel({
|
|
|
212
212
|
|
|
213
213
|
const handleEscape = (e: KeyboardEvent) => {
|
|
214
214
|
if (e.key === 'Escape') {
|
|
215
|
-
eventBus.get('
|
|
215
|
+
eventBus.get('mark:cancel-pending').next(undefined);
|
|
216
216
|
}
|
|
217
217
|
};
|
|
218
218
|
|
|
@@ -274,7 +274,7 @@ export function TaggingPanel({
|
|
|
274
274
|
className="semiont-select"
|
|
275
275
|
onChange={(e) => {
|
|
276
276
|
if (e.target.value && pendingAnnotation) {
|
|
277
|
-
eventBus.get('
|
|
277
|
+
eventBus.get('mark:create').next({
|
|
278
278
|
motivation: 'tagging',
|
|
279
279
|
selector: pendingAnnotation.selector,
|
|
280
280
|
body: [
|
|
@@ -305,7 +305,7 @@ export function TaggingPanel({
|
|
|
305
305
|
{/* Cancel button */}
|
|
306
306
|
<div className="semiont-annotation-prompt__footer">
|
|
307
307
|
<button
|
|
308
|
-
onClick={() => eventBus.get('
|
|
308
|
+
onClick={() => eventBus.get('mark:cancel-pending').next(undefined)}
|
|
309
309
|
className="semiont-button semiont-button--secondary"
|
|
310
310
|
data-type="tag"
|
|
311
311
|
>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import React, { useState, useEffect } from 'react';
|
|
4
4
|
import { useTranslations } from '../../../contexts/TranslationContext';
|
|
5
|
-
import type { components, Selector,
|
|
5
|
+
import type { components, Selector, MarkProgress } from '@semiont/core';
|
|
6
6
|
import type { RouteBuilder, LinkComponentProps } from '../../../contexts/RoutingContext';
|
|
7
7
|
import type { Annotator } from '../../../lib/annotation-registry';
|
|
8
8
|
import { StatisticsPanel } from './StatisticsPanel';
|
|
@@ -47,7 +47,7 @@ interface UnifiedAnnotationsPanelProps {
|
|
|
47
47
|
|
|
48
48
|
// Annotation assistance state (per motivation)
|
|
49
49
|
assistingMotivation?: Motivation | null;
|
|
50
|
-
progress?:
|
|
50
|
+
progress?: MarkProgress | null;
|
|
51
51
|
|
|
52
52
|
// Unified pending annotation (for creating new annotations)
|
|
53
53
|
pendingAnnotation: PendingAnnotation | null;
|
|
@@ -29,7 +29,7 @@ function createEventTracker() {
|
|
|
29
29
|
events.push({ event: eventName, payload });
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
const panelEvents = ['
|
|
32
|
+
const panelEvents = ['mark:create'] as const;
|
|
33
33
|
|
|
34
34
|
panelEvents.forEach(eventName => {
|
|
35
35
|
const handler = trackEvent(eventName);
|
|
@@ -359,7 +359,7 @@ describe('AssessmentPanel Component', () => {
|
|
|
359
359
|
expect(textarea).toHaveFocus();
|
|
360
360
|
});
|
|
361
361
|
|
|
362
|
-
it('should emit
|
|
362
|
+
it('should emit mark:createevent when save is clicked', async () => {
|
|
363
363
|
const tracker = createEventTracker();
|
|
364
364
|
const pendingAnnotation = createPendingAnnotation('Selected text');
|
|
365
365
|
|
|
@@ -379,7 +379,7 @@ describe('AssessmentPanel Component', () => {
|
|
|
379
379
|
|
|
380
380
|
await waitFor(() => {
|
|
381
381
|
expect(tracker.events.some(e =>
|
|
382
|
-
e.event === '
|
|
382
|
+
e.event === 'mark:create' &&
|
|
383
383
|
e.payload?.motivation === 'assessing' &&
|
|
384
384
|
e.payload?.body?.[0]?.value === 'My assessment'
|
|
385
385
|
)).toBe(true);
|
|
@@ -420,7 +420,7 @@ describe('AssessmentPanel Component', () => {
|
|
|
420
420
|
|
|
421
421
|
await waitFor(() => {
|
|
422
422
|
expect(tracker.events.some(e =>
|
|
423
|
-
e.event === '
|
|
423
|
+
e.event === 'mark:create' &&
|
|
424
424
|
e.payload?.motivation === 'assessing' &&
|
|
425
425
|
Array.isArray(e.payload?.body) &&
|
|
426
426
|
e.payload.body.length === 0
|
|
@@ -277,7 +277,7 @@ describe('AssistSection', () => {
|
|
|
277
277
|
{ returnEventBus: true }
|
|
278
278
|
);
|
|
279
279
|
|
|
280
|
-
const subscription = eventBus!.get('
|
|
280
|
+
const subscription = eventBus!.get('mark:assist-request').subscribe(detectionHandler);
|
|
281
281
|
|
|
282
282
|
const annotateButton = screen.getByRole('button', { name: /✨ Annotate/ });
|
|
283
283
|
await user.click(annotateButton);
|
|
@@ -303,7 +303,7 @@ describe('AssistSection', () => {
|
|
|
303
303
|
{ returnEventBus: true }
|
|
304
304
|
);
|
|
305
305
|
|
|
306
|
-
const subscription = eventBus!.get('
|
|
306
|
+
const subscription = eventBus!.get('mark:assist-request').subscribe(detectionHandler);
|
|
307
307
|
|
|
308
308
|
const annotateButton = screen.getByRole('button', { name: /✨ Annotate/ });
|
|
309
309
|
await user.click(annotateButton);
|
|
@@ -329,7 +329,7 @@ describe('AssistSection', () => {
|
|
|
329
329
|
{ returnEventBus: true }
|
|
330
330
|
);
|
|
331
331
|
|
|
332
|
-
const subscription = eventBus!.get('
|
|
332
|
+
const subscription = eventBus!.get('mark:assist-request').subscribe(detectionHandler);
|
|
333
333
|
|
|
334
334
|
const annotateButton = screen.getByRole('button', { name: /✨ Annotate/ });
|
|
335
335
|
await user.click(annotateButton);
|
|
@@ -355,7 +355,7 @@ describe('AssistSection', () => {
|
|
|
355
355
|
{ returnEventBus: true }
|
|
356
356
|
);
|
|
357
357
|
|
|
358
|
-
const subscription = eventBus!.get('
|
|
358
|
+
const subscription = eventBus!.get('mark:assist-request').subscribe(detectionHandler);
|
|
359
359
|
|
|
360
360
|
const textarea = screen.getByPlaceholderText('Enter custom instructions...');
|
|
361
361
|
await user.type(textarea, 'Find key concepts');
|
|
@@ -241,7 +241,7 @@ describe('CommentEntry Component', () => {
|
|
|
241
241
|
});
|
|
242
242
|
|
|
243
243
|
describe('Click Interactions', () => {
|
|
244
|
-
it('should emit
|
|
244
|
+
it('should emit browse:click event when comment is clicked', async () => {
|
|
245
245
|
const clickHandler = vi.fn();
|
|
246
246
|
|
|
247
247
|
const { container, eventBus } = renderWithProviders(
|
|
@@ -250,7 +250,7 @@ describe('CommentEntry Component', () => {
|
|
|
250
250
|
);
|
|
251
251
|
|
|
252
252
|
// Subscribe to actual event on real event bus
|
|
253
|
-
const subscription = eventBus!.get('
|
|
253
|
+
const subscription = eventBus!.get('browse:click').subscribe(clickHandler);
|
|
254
254
|
|
|
255
255
|
const commentDiv = container.firstChild as HTMLElement;
|
|
256
256
|
await userEvent.click(commentDiv);
|
|
@@ -273,7 +273,7 @@ describe('CommentEntry Component', () => {
|
|
|
273
273
|
});
|
|
274
274
|
|
|
275
275
|
describe('Hover Interactions', () => {
|
|
276
|
-
it('should emit
|
|
276
|
+
it('should emit beckon:hover event with annotation id after dwell delay', () => {
|
|
277
277
|
vi.useFakeTimers();
|
|
278
278
|
const hoverHandler = vi.fn();
|
|
279
279
|
|
|
@@ -283,7 +283,7 @@ describe('CommentEntry Component', () => {
|
|
|
283
283
|
);
|
|
284
284
|
|
|
285
285
|
// Subscribe to actual event
|
|
286
|
-
const subscription = eventBus!.get('
|
|
286
|
+
const subscription = eventBus!.get('beckon:hover').subscribe(hoverHandler);
|
|
287
287
|
|
|
288
288
|
const commentDiv = container.firstChild as HTMLElement;
|
|
289
289
|
fireEvent.mouseEnter(commentDiv);
|
|
@@ -301,7 +301,7 @@ describe('CommentEntry Component', () => {
|
|
|
301
301
|
vi.useRealTimers();
|
|
302
302
|
});
|
|
303
303
|
|
|
304
|
-
it('should NOT emit
|
|
304
|
+
it('should NOT emit beckon:hover when mouse leaves before dwell delay', () => {
|
|
305
305
|
vi.useFakeTimers();
|
|
306
306
|
const hoverHandler = vi.fn();
|
|
307
307
|
|
|
@@ -311,7 +311,7 @@ describe('CommentEntry Component', () => {
|
|
|
311
311
|
);
|
|
312
312
|
|
|
313
313
|
// Subscribe to actual event
|
|
314
|
-
const subscription = eventBus!.get('
|
|
314
|
+
const subscription = eventBus!.get('beckon:hover').subscribe(hoverHandler);
|
|
315
315
|
|
|
316
316
|
const commentDiv = container.firstChild as HTMLElement;
|
|
317
317
|
fireEvent.mouseEnter(commentDiv);
|
|
@@ -327,7 +327,7 @@ describe('CommentEntry Component', () => {
|
|
|
327
327
|
vi.useRealTimers();
|
|
328
328
|
});
|
|
329
329
|
|
|
330
|
-
it('should emit
|
|
330
|
+
it('should emit beckon:hover null after dwell then leave', () => {
|
|
331
331
|
vi.useFakeTimers();
|
|
332
332
|
const hoverHandler = vi.fn();
|
|
333
333
|
|
|
@@ -336,7 +336,7 @@ describe('CommentEntry Component', () => {
|
|
|
336
336
|
{ returnEventBus: true }
|
|
337
337
|
);
|
|
338
338
|
|
|
339
|
-
const subscription = eventBus!.get('
|
|
339
|
+
const subscription = eventBus!.get('beckon:hover').subscribe(hoverHandler);
|
|
340
340
|
|
|
341
341
|
const commentDiv = container.firstChild as HTMLElement;
|
|
342
342
|
fireEvent.mouseEnter(commentDiv);
|
|
@@ -29,7 +29,7 @@ function createEventTracker() {
|
|
|
29
29
|
events.push({ event: eventName, payload });
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
const panelEvents = ['
|
|
32
|
+
const panelEvents = ['mark:create'] as const;
|
|
33
33
|
|
|
34
34
|
panelEvents.forEach(eventName => {
|
|
35
35
|
const handler = trackEvent(eventName);
|
|
@@ -396,7 +396,7 @@ describe('CommentsPanel Component', () => {
|
|
|
396
396
|
expect(textarea).toHaveFocus();
|
|
397
397
|
});
|
|
398
398
|
|
|
399
|
-
it('should emit
|
|
399
|
+
it('should emit mark:createevent when save is clicked', async () => {
|
|
400
400
|
const tracker = createEventTracker();
|
|
401
401
|
const pendingAnnotation = createPendingAnnotation('Selected text');
|
|
402
402
|
|
|
@@ -416,7 +416,7 @@ describe('CommentsPanel Component', () => {
|
|
|
416
416
|
|
|
417
417
|
await waitFor(() => {
|
|
418
418
|
expect(tracker.events.some(e =>
|
|
419
|
-
e.event === '
|
|
419
|
+
e.event === 'mark:create' &&
|
|
420
420
|
e.payload?.motivation === 'commenting' &&
|
|
421
421
|
e.payload?.body?.[0]?.value === 'My new comment'
|
|
422
422
|
)).toBe(true);
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* This is a Layer 2 test because it:
|
|
8
8
|
* - Tests multiple real React components together (HighlightPanel + AssistSection)
|
|
9
|
-
* - Uses real EventBus for
|
|
9
|
+
* - Uses real EventBus for browse:click events
|
|
10
10
|
* - Mocks API and external dependencies
|
|
11
11
|
* - Tests the data flow between parent and child components
|
|
12
12
|
*/
|
|
@@ -25,7 +25,7 @@ function createEventTracker() {
|
|
|
25
25
|
events.push({ event: eventName, payload });
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
const panelEvents = ['
|
|
28
|
+
const panelEvents = ['mark:assist-request'] as const;
|
|
29
29
|
|
|
30
30
|
panelEvents.forEach(eventName => {
|
|
31
31
|
const handler = trackEvent(eventName);
|
|
@@ -302,7 +302,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
302
302
|
|
|
303
303
|
await waitFor(() => {
|
|
304
304
|
expect(tracker.events.some(e =>
|
|
305
|
-
e.event === '
|
|
305
|
+
e.event === 'mark:assist-request' &&
|
|
306
306
|
e.payload?.motivation === 'linking' &&
|
|
307
307
|
e.payload?.options?.entityTypes?.includes('Person') &&
|
|
308
308
|
e.payload?.options?.entityTypes?.includes('Organization') &&
|
|
@@ -327,7 +327,7 @@ describe('ReferencesPanel Component', () => {
|
|
|
327
327
|
|
|
328
328
|
await waitFor(() => {
|
|
329
329
|
expect(tracker.events.some(e =>
|
|
330
|
-
e.event === '
|
|
330
|
+
e.event === 'mark:assist-request' &&
|
|
331
331
|
e.payload?.motivation === 'linking' &&
|
|
332
332
|
e.payload?.options?.entityTypes?.includes('Person') &&
|
|
333
333
|
e.payload?.options?.includeDescriptiveReferences === true
|
|
@@ -66,9 +66,9 @@ function createEventTracker() {
|
|
|
66
66
|
};
|
|
67
67
|
|
|
68
68
|
const resourceEvents = [
|
|
69
|
-
'
|
|
70
|
-
'
|
|
71
|
-
'
|
|
69
|
+
'yield:clone',
|
|
70
|
+
'mark:archive',
|
|
71
|
+
'mark:unarchive',
|
|
72
72
|
] as const;
|
|
73
73
|
|
|
74
74
|
resourceEvents.forEach(eventName => {
|
|
@@ -248,7 +248,7 @@ describe('ResourceInfoPanel Component', () => {
|
|
|
248
248
|
expect(screen.getByText('Generate a shareable clone link for this resource')).toBeInTheDocument();
|
|
249
249
|
});
|
|
250
250
|
|
|
251
|
-
it('should emit
|
|
251
|
+
it('should emit yield:clone event when clone button clicked', async () => {
|
|
252
252
|
const tracker = createEventTracker();
|
|
253
253
|
renderWithEventBus(
|
|
254
254
|
<ResourceInfoPanel
|
|
@@ -261,7 +261,7 @@ describe('ResourceInfoPanel Component', () => {
|
|
|
261
261
|
fireEvent.click(button);
|
|
262
262
|
|
|
263
263
|
await waitFor(() => {
|
|
264
|
-
expect(tracker.events.some(e => e.event === '
|
|
264
|
+
expect(tracker.events.some(e => e.event === 'yield:clone')).toBe(true);
|
|
265
265
|
});
|
|
266
266
|
});
|
|
267
267
|
});
|
|
@@ -291,7 +291,7 @@ describe('ResourceInfoPanel Component', () => {
|
|
|
291
291
|
expect(screen.getByText('Restore this resource to active status')).toBeInTheDocument();
|
|
292
292
|
});
|
|
293
293
|
|
|
294
|
-
it('should emit
|
|
294
|
+
it('should emit mark:archive event when archive button clicked', async () => {
|
|
295
295
|
const tracker = createEventTracker();
|
|
296
296
|
renderWithEventBus(
|
|
297
297
|
<ResourceInfoPanel
|
|
@@ -305,11 +305,11 @@ describe('ResourceInfoPanel Component', () => {
|
|
|
305
305
|
fireEvent.click(button);
|
|
306
306
|
|
|
307
307
|
await waitFor(() => {
|
|
308
|
-
expect(tracker.events.some(e => e.event === '
|
|
308
|
+
expect(tracker.events.some(e => e.event === 'mark:archive')).toBe(true);
|
|
309
309
|
});
|
|
310
310
|
});
|
|
311
311
|
|
|
312
|
-
it('should emit
|
|
312
|
+
it('should emit mark:unarchive event when unarchive button clicked', async () => {
|
|
313
313
|
const tracker = createEventTracker();
|
|
314
314
|
renderWithEventBus(
|
|
315
315
|
<ResourceInfoPanel
|
|
@@ -323,7 +323,7 @@ describe('ResourceInfoPanel Component', () => {
|
|
|
323
323
|
fireEvent.click(button);
|
|
324
324
|
|
|
325
325
|
await waitFor(() => {
|
|
326
|
-
expect(tracker.events.some(e => e.event === '
|
|
326
|
+
expect(tracker.events.some(e => e.event === 'mark:unarchive')).toBe(true);
|
|
327
327
|
});
|
|
328
328
|
});
|
|
329
329
|
});
|
|
@@ -29,7 +29,7 @@ function createEventTracker() {
|
|
|
29
29
|
events.push({ event: eventName, payload });
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
const panelEvents = ['
|
|
32
|
+
const panelEvents = ['mark:create', 'mark:assist-request'] as const;
|
|
33
33
|
|
|
34
34
|
panelEvents.forEach(eventName => {
|
|
35
35
|
const handler = trackEvent(eventName);
|
|
@@ -354,7 +354,7 @@ describe('TaggingPanel Component', () => {
|
|
|
354
354
|
expect(screen.getByText(/Select category/)).toBeInTheDocument();
|
|
355
355
|
});
|
|
356
356
|
|
|
357
|
-
it('should emit
|
|
357
|
+
it('should emit mark:createevent when category is selected', async () => {
|
|
358
358
|
const tracker = createEventTracker();
|
|
359
359
|
const pendingAnnotation = createPendingAnnotation('Selected text');
|
|
360
360
|
|
|
@@ -378,7 +378,7 @@ describe('TaggingPanel Component', () => {
|
|
|
378
378
|
|
|
379
379
|
await waitFor(() => {
|
|
380
380
|
expect(tracker.events.some(e =>
|
|
381
|
-
e.event === '
|
|
381
|
+
e.event === 'mark:create' &&
|
|
382
382
|
e.payload?.motivation === 'tagging' &&
|
|
383
383
|
e.payload?.body?.[0]?.value === 'Issue' &&
|
|
384
384
|
e.payload?.body?.[0]?.type === 'TextualBody'
|
|
@@ -407,7 +407,7 @@ describe('TaggingPanel Component', () => {
|
|
|
407
407
|
await userEvent.selectOptions(categorySelect!, 'Rule');
|
|
408
408
|
|
|
409
409
|
await waitFor(() => {
|
|
410
|
-
const createEvent = tracker.events.find(e => e.event === '
|
|
410
|
+
const createEvent = tracker.events.find(e => e.event === 'mark:create');
|
|
411
411
|
expect(createEvent).toBeDefined();
|
|
412
412
|
const body: any[] = createEvent!.payload.body;
|
|
413
413
|
|
|
@@ -582,7 +582,7 @@ describe('TaggingPanel Component', () => {
|
|
|
582
582
|
|
|
583
583
|
await waitFor(() => {
|
|
584
584
|
expect(tracker.events.some(e =>
|
|
585
|
-
e.event === '
|
|
585
|
+
e.event === 'mark:assist-request' &&
|
|
586
586
|
e.payload?.motivation === 'tagging' &&
|
|
587
587
|
e.payload?.options?.schemaId === 'legal-irac' &&
|
|
588
588
|
e.payload?.options?.categories?.includes('Issue') &&
|
|
@@ -9,6 +9,7 @@ import React from 'react';
|
|
|
9
9
|
import {
|
|
10
10
|
CommandLineIcon
|
|
11
11
|
} from '@heroicons/react/24/outline';
|
|
12
|
+
import { COMMON_PANELS, type ToolbarPanelType } from '../../../hooks/usePanelBrowse';
|
|
12
13
|
|
|
13
14
|
export interface DevOpsFeature {
|
|
14
15
|
title: string;
|
|
@@ -54,7 +55,7 @@ export function AdminDevOpsPage({
|
|
|
54
55
|
Toolbar,
|
|
55
56
|
}: AdminDevOpsPageProps) {
|
|
56
57
|
return (
|
|
57
|
-
<div className={`semiont-page${activePanel ? ' semiont-page--panel-open' : ''}`}>
|
|
58
|
+
<div className={`semiont-page${activePanel && COMMON_PANELS.includes(activePanel as ToolbarPanelType) ? ' semiont-page--panel-open' : ''}`}>
|
|
58
59
|
{/* Main Content Area */}
|
|
59
60
|
<div className="semiont-page__content">
|
|
60
61
|
{/* Page Title */}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
CheckCircleIcon,
|
|
13
13
|
InformationCircleIcon
|
|
14
14
|
} from '@heroicons/react/24/outline';
|
|
15
|
+
import { COMMON_PANELS, type ToolbarPanelType } from '../../../hooks/usePanelBrowse';
|
|
15
16
|
|
|
16
17
|
export interface OAuthProvider {
|
|
17
18
|
name: string;
|
|
@@ -67,7 +68,7 @@ export function AdminSecurityPage({
|
|
|
67
68
|
Toolbar,
|
|
68
69
|
}: AdminSecurityPageProps) {
|
|
69
70
|
return (
|
|
70
|
-
<div className={`semiont-page${activePanel ? ' semiont-page--panel-open' : ''}`}>
|
|
71
|
+
<div className={`semiont-page${activePanel && COMMON_PANELS.includes(activePanel as ToolbarPanelType) ? ' semiont-page--panel-open' : ''}`}>
|
|
71
72
|
{/* Main Content Area */}
|
|
72
73
|
<div className="semiont-page__content">
|
|
73
74
|
<div className="semiont-page__sections">
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import React, { useState } from 'react';
|
|
9
|
+
import { COMMON_PANELS, type ToolbarPanelType } from '../../../hooks/usePanelBrowse';
|
|
9
10
|
import {
|
|
10
11
|
PlusIcon,
|
|
11
12
|
MagnifyingGlassIcon,
|
|
@@ -235,7 +236,7 @@ export function AdminUsersPage({
|
|
|
235
236
|
});
|
|
236
237
|
|
|
237
238
|
return (
|
|
238
|
-
<div className={`semiont-page${activePanel ? ' semiont-page--panel-open' : ''}`}>
|
|
239
|
+
<div className={`semiont-page${activePanel && COMMON_PANELS.includes(activePanel as ToolbarPanelType) ? ' semiont-page--panel-open' : ''}`}>
|
|
239
240
|
{/* Main Content Area */}
|
|
240
241
|
<div className="semiont-page__content">
|
|
241
242
|
<div className="semiont-page__sections">
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
PlusIcon,
|
|
12
12
|
ExclamationCircleIcon
|
|
13
13
|
} from '@heroicons/react/24/outline';
|
|
14
|
+
import { COMMON_PANELS, type ToolbarPanelType } from '../../../hooks/usePanelBrowse';
|
|
14
15
|
|
|
15
16
|
export interface EntityTagsPageProps {
|
|
16
17
|
// Data props
|
|
@@ -69,7 +70,7 @@ export function EntityTagsPage({
|
|
|
69
70
|
};
|
|
70
71
|
|
|
71
72
|
return (
|
|
72
|
-
<div className={`semiont-page${activePanel ? ' semiont-page--panel-open' : ''}`}>
|
|
73
|
+
<div className={`semiont-page${activePanel && COMMON_PANELS.includes(activePanel as ToolbarPanelType) ? ' semiont-page--panel-open' : ''}`}>
|
|
73
74
|
{/* Main Content Area */}
|
|
74
75
|
<div className="semiont-page__content">
|
|
75
76
|
{/* Page Title */}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import React from 'react';
|
|
9
9
|
import { ClockIcon } from '@heroicons/react/24/outline';
|
|
10
|
+
import { COMMON_PANELS, type ToolbarPanelType } from '../../../hooks/usePanelBrowse';
|
|
10
11
|
|
|
11
12
|
export interface RecentDocumentsPageProps {
|
|
12
13
|
// Data props
|
|
@@ -53,7 +54,7 @@ export function RecentDocumentsPage({
|
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
return (
|
|
56
|
-
<div className={`semiont-page${activePanel ? ' semiont-page--panel-open' : ''}`}>
|
|
57
|
+
<div className={`semiont-page${activePanel && COMMON_PANELS.includes(activePanel as ToolbarPanelType) ? ' semiont-page--panel-open' : ''}`}>
|
|
57
58
|
{/* Main Content Area */}
|
|
58
59
|
<div className="semiont-page__content">
|
|
59
60
|
{/* Page Title */}
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
ScaleIcon,
|
|
12
12
|
LightBulbIcon
|
|
13
13
|
} from '@heroicons/react/24/outline';
|
|
14
|
+
import { COMMON_PANELS, type ToolbarPanelType } from '../../../hooks/usePanelBrowse';
|
|
14
15
|
import type { TagSchema } from '@semiont/react-ui';
|
|
15
16
|
|
|
16
17
|
export interface TagSchemasPageProps {
|
|
@@ -68,7 +69,7 @@ export function TagSchemasPage({
|
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
return (
|
|
71
|
-
<div className={`semiont-page${activePanel ? ' semiont-page--panel-open' : ''}`}>
|
|
72
|
+
<div className={`semiont-page${activePanel && COMMON_PANELS.includes(activePanel as ToolbarPanelType) ? ' semiont-page--panel-open' : ''}`}>
|
|
72
73
|
{/* Main Content Area */}
|
|
73
74
|
<div className="semiont-page__content">
|
|
74
75
|
{/* Page Title */}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import React, { useState, useEffect } from 'react';
|
|
10
10
|
import type { components } from '@semiont/core';
|
|
11
11
|
import { isImageMimeType, isPdfMimeType, LOCALES } from '@semiont/api-client';
|
|
12
|
+
import { COMMON_PANELS, type ToolbarPanelType } from '../../../hooks/usePanelBrowse';
|
|
12
13
|
import { buttonStyles } from '../../../lib/button-styles';
|
|
13
14
|
import { CodeMirrorRenderer } from '../../../components/CodeMirrorRenderer';
|
|
14
15
|
import { useFormAnnouncements } from '../../../components/LiveRegion';
|
|
@@ -254,7 +255,7 @@ export function ResourceComposePage({
|
|
|
254
255
|
const isReferenceCompletion = mode === 'reference';
|
|
255
256
|
|
|
256
257
|
return (
|
|
257
|
-
<div className={`semiont-page${activePanel ? ' semiont-page--panel-open' : ''}`}>
|
|
258
|
+
<div className={`semiont-page${activePanel && COMMON_PANELS.includes(activePanel as ToolbarPanelType) ? ' semiont-page--panel-open' : ''}`}>
|
|
258
259
|
{/* Main Content Area */}
|
|
259
260
|
<div className="semiont-page__content semiont-page__compose">
|
|
260
261
|
{/* Page Title */}
|