@semiont/react-ui 0.4.14 → 0.4.15

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.
Files changed (49) hide show
  1. package/README.md +18 -12
  2. package/dist/KnowledgeBaseSessionContext-CpYaCbnC.d.mts +174 -0
  3. package/dist/{PdfAnnotationCanvas.client-CW6SKH2U.mjs → PdfAnnotationCanvas.client-CHDCGQBR.mjs} +3 -3
  4. package/dist/{chunk-HNZOXH4L.mjs → chunk-OZICDVH7.mjs} +5 -3
  5. package/dist/chunk-OZICDVH7.mjs.map +1 -0
  6. package/dist/chunk-R2U7P4TK.mjs +865 -0
  7. package/dist/chunk-R2U7P4TK.mjs.map +1 -0
  8. package/dist/{chunk-BQJWOK4C.mjs → chunk-VN5NY4SN.mjs} +9 -8
  9. package/dist/chunk-VN5NY4SN.mjs.map +1 -0
  10. package/dist/index.d.mts +139 -169
  11. package/dist/index.mjs +2197 -1947
  12. package/dist/index.mjs.map +1 -1
  13. package/dist/test-utils.d.mts +13 -62
  14. package/dist/test-utils.mjs +40 -21
  15. package/dist/test-utils.mjs.map +1 -1
  16. package/package.json +5 -3
  17. package/src/components/ProtectedErrorBoundary.tsx +95 -0
  18. package/src/components/__tests__/ProtectedErrorBoundary.test.tsx +197 -0
  19. package/src/components/modals/PermissionDeniedModal.tsx +140 -0
  20. package/src/components/modals/ReferenceWizardModal.tsx +3 -2
  21. package/src/components/modals/SessionExpiredModal.tsx +101 -0
  22. package/src/components/modals/__tests__/PermissionDeniedModal.test.tsx +150 -0
  23. package/src/components/modals/__tests__/SessionExpiredModal.test.tsx +115 -0
  24. package/src/components/resource/AnnotationHistory.tsx +5 -6
  25. package/src/components/resource/HistoryEvent.tsx +7 -7
  26. package/src/components/resource/__tests__/AnnotationHistory.test.tsx +33 -34
  27. package/src/components/resource/__tests__/HistoryEvent.test.tsx +17 -19
  28. package/src/components/resource/__tests__/event-formatting.test.ts +70 -94
  29. package/src/components/resource/event-formatting.ts +56 -56
  30. package/src/components/resource/panels/ReferenceEntry.tsx +7 -5
  31. package/src/components/resource/panels/ResourceInfoPanel.tsx +8 -6
  32. package/src/components/resource/panels/__tests__/ReferenceEntry.test.tsx +12 -12
  33. package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +1 -0
  34. package/src/features/resource-viewer/__tests__/AnnotationCreationPending.test.tsx +1 -1
  35. package/src/features/resource-viewer/__tests__/AnnotationDeletionIntegration.test.tsx +4 -4
  36. package/src/features/resource-viewer/__tests__/AnnotationProgressDismissal.test.tsx +5 -10
  37. package/src/features/resource-viewer/__tests__/BindFlowIntegration.test.tsx +23 -54
  38. package/src/features/resource-viewer/__tests__/DetectionFlowBug.test.tsx +6 -6
  39. package/src/features/resource-viewer/__tests__/DetectionFlowIntegration.test.tsx +7 -19
  40. package/src/features/resource-viewer/__tests__/ToastNotifications.test.tsx +1 -1
  41. package/src/features/resource-viewer/__tests__/YieldFlowIntegration.test.tsx +18 -44
  42. package/src/features/resource-viewer/__tests__/annotation-progress-flow.test.tsx +6 -6
  43. package/src/features/resource-viewer/components/ResourceViewerPage.tsx +24 -26
  44. package/dist/TranslationManager-CudgH3gw.d.mts +0 -107
  45. package/dist/chunk-BQJWOK4C.mjs.map +0 -1
  46. package/dist/chunk-HNZOXH4L.mjs.map +0 -1
  47. package/dist/chunk-OL5UST25.mjs +0 -413
  48. package/dist/chunk-OL5UST25.mjs.map +0 -1
  49. /package/dist/{PdfAnnotationCanvas.client-CW6SKH2U.mjs.map → PdfAnnotationCanvas.client-CHDCGQBR.mjs.map} +0 -0
@@ -0,0 +1,150 @@
1
+ /**
2
+ * PermissionDeniedModal Tests
3
+ *
4
+ * The modal renders content when `permissionDeniedAt` is non-null on the
5
+ * KnowledgeBaseSession context, and is hidden otherwise. Button clicks call
6
+ * `acknowledgePermissionDenied()` and navigate the window or history.
7
+ */
8
+
9
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
10
+ import React from 'react';
11
+ import { screen, fireEvent } from '@testing-library/react';
12
+ import '@testing-library/jest-dom';
13
+ import {
14
+ renderWithProviders,
15
+ createMockKnowledgeBaseSession,
16
+ } from '../../../test-utils';
17
+ import { PermissionDeniedModal } from '../PermissionDeniedModal';
18
+
19
+ vi.mock('@headlessui/react', () => ({
20
+ Dialog: ({ children, ...props }: any) => <div role="dialog" {...props}>{typeof children === 'function' ? children({ open: true }) : children}</div>,
21
+ DialogPanel: ({ children, ...props }: any) => <div {...props}>{children}</div>,
22
+ DialogTitle: ({ children, ...props }: any) => <h2 {...props}>{children}</h2>,
23
+ Transition: ({ show, children }: any) => show ? <>{children}</> : null,
24
+ TransitionChild: ({ children }: any) => <>{children}</>,
25
+ }));
26
+
27
+ const originalLocation = window.location;
28
+ const originalHistoryBack = window.history.back;
29
+ let mockLocation: { href: string; pathname: string };
30
+ let mockHistoryBack: ReturnType<typeof vi.fn>;
31
+
32
+ beforeEach(() => {
33
+ mockLocation = { href: '', pathname: '/admin/users' };
34
+ Object.defineProperty(window, 'location', {
35
+ value: mockLocation,
36
+ writable: true,
37
+ configurable: true,
38
+ });
39
+ mockHistoryBack = vi.fn();
40
+ window.history.back = mockHistoryBack;
41
+ });
42
+
43
+ afterEach(() => {
44
+ Object.defineProperty(window, 'location', {
45
+ value: originalLocation,
46
+ writable: true,
47
+ configurable: true,
48
+ });
49
+ window.history.back = originalHistoryBack;
50
+ });
51
+
52
+ describe('PermissionDeniedModal', () => {
53
+ describe('initial render', () => {
54
+ it('does not render modal content when permissionDeniedAt is null', () => {
55
+ renderWithProviders(<PermissionDeniedModal />, {
56
+ knowledgeBaseSession: createMockKnowledgeBaseSession({
57
+ permissionDeniedAt: null,
58
+ }),
59
+ });
60
+ expect(screen.queryByText('Access Denied')).not.toBeInTheDocument();
61
+ });
62
+ });
63
+
64
+ describe('when permissionDeniedAt is set', () => {
65
+ it('shows modal with default message when no message provided', () => {
66
+ renderWithProviders(<PermissionDeniedModal />, {
67
+ knowledgeBaseSession: createMockKnowledgeBaseSession({
68
+ permissionDeniedAt: Date.now(),
69
+ }),
70
+ });
71
+
72
+ expect(screen.getByText('Access Denied')).toBeInTheDocument();
73
+ expect(screen.getByText('You do not have permission to perform this action.')).toBeInTheDocument();
74
+ });
75
+
76
+ it('shows custom message from permissionDeniedMessage', () => {
77
+ renderWithProviders(<PermissionDeniedModal />, {
78
+ knowledgeBaseSession: createMockKnowledgeBaseSession({
79
+ permissionDeniedAt: Date.now(),
80
+ permissionDeniedMessage: 'Admin access required for this resource',
81
+ }),
82
+ });
83
+
84
+ expect(screen.getByText('Admin access required for this resource')).toBeInTheDocument();
85
+ });
86
+
87
+ it('renders all three action buttons', () => {
88
+ renderWithProviders(<PermissionDeniedModal />, {
89
+ knowledgeBaseSession: createMockKnowledgeBaseSession({
90
+ permissionDeniedAt: Date.now(),
91
+ }),
92
+ });
93
+
94
+ expect(screen.getByRole('button', { name: /go back/i })).toBeInTheDocument();
95
+ expect(screen.getByRole('button', { name: /go to home/i })).toBeInTheDocument();
96
+ expect(screen.getByRole('button', { name: /switch account/i })).toBeInTheDocument();
97
+ });
98
+ });
99
+
100
+ describe('button actions', () => {
101
+ it('acknowledges and calls window.history.back on Go Back', () => {
102
+ const ack = vi.fn();
103
+ renderWithProviders(<PermissionDeniedModal />, {
104
+ knowledgeBaseSession: createMockKnowledgeBaseSession({
105
+ permissionDeniedAt: Date.now(),
106
+ permissionDeniedMessage: 'denied',
107
+ acknowledgePermissionDenied: ack,
108
+ }),
109
+ });
110
+
111
+ fireEvent.click(screen.getByRole('button', { name: /go back/i }));
112
+
113
+ expect(ack).toHaveBeenCalled();
114
+ expect(mockHistoryBack).toHaveBeenCalled();
115
+ });
116
+
117
+ it('acknowledges and navigates to / on Go to Home', () => {
118
+ const ack = vi.fn();
119
+ renderWithProviders(<PermissionDeniedModal />, {
120
+ knowledgeBaseSession: createMockKnowledgeBaseSession({
121
+ permissionDeniedAt: Date.now(),
122
+ permissionDeniedMessage: 'denied',
123
+ acknowledgePermissionDenied: ack,
124
+ }),
125
+ });
126
+
127
+ fireEvent.click(screen.getByRole('button', { name: /go to home/i }));
128
+
129
+ expect(ack).toHaveBeenCalled();
130
+ expect(mockLocation.href).toBe('/');
131
+ });
132
+
133
+ it('acknowledges and navigates to /auth/connect with current path on Switch Account', () => {
134
+ const ack = vi.fn();
135
+ mockLocation.pathname = '/admin/users';
136
+ renderWithProviders(<PermissionDeniedModal />, {
137
+ knowledgeBaseSession: createMockKnowledgeBaseSession({
138
+ permissionDeniedAt: Date.now(),
139
+ permissionDeniedMessage: 'denied',
140
+ acknowledgePermissionDenied: ack,
141
+ }),
142
+ });
143
+
144
+ fireEvent.click(screen.getByRole('button', { name: /switch account/i }));
145
+
146
+ expect(ack).toHaveBeenCalled();
147
+ expect(mockLocation.href).toBe('/auth/connect?callbackUrl=%2Fadmin%2Fusers');
148
+ });
149
+ });
150
+ });
@@ -0,0 +1,115 @@
1
+ /**
2
+ * SessionExpiredModal Tests
3
+ *
4
+ * The modal renders content when `sessionExpiredAt` is non-null on the
5
+ * KnowledgeBaseSession context, and is hidden otherwise. Button clicks
6
+ * call `acknowledgeSessionExpired()` and navigate the window.
7
+ */
8
+
9
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
10
+ import React from 'react';
11
+ import { screen, fireEvent } from '@testing-library/react';
12
+ import '@testing-library/jest-dom';
13
+ import {
14
+ renderWithProviders,
15
+ createMockKnowledgeBaseSession,
16
+ } from '../../../test-utils';
17
+ import { SessionExpiredModal } from '../SessionExpiredModal';
18
+
19
+ vi.mock('@headlessui/react', () => ({
20
+ Dialog: ({ children, ...props }: any) => <div role="dialog" {...props}>{typeof children === 'function' ? children({ open: true }) : children}</div>,
21
+ DialogPanel: ({ children, ...props }: any) => <div {...props}>{children}</div>,
22
+ DialogTitle: ({ children, ...props }: any) => <h2 {...props}>{children}</h2>,
23
+ Transition: ({ show, children }: any) => show ? <>{children}</> : null,
24
+ TransitionChild: ({ children }: any) => <>{children}</>,
25
+ }));
26
+
27
+ const originalLocation = window.location;
28
+ let mockLocation: { href: string; pathname: string };
29
+
30
+ beforeEach(() => {
31
+ mockLocation = { href: '', pathname: '/know/discover' };
32
+ Object.defineProperty(window, 'location', {
33
+ value: mockLocation,
34
+ writable: true,
35
+ configurable: true,
36
+ });
37
+ });
38
+
39
+ afterEach(() => {
40
+ Object.defineProperty(window, 'location', {
41
+ value: originalLocation,
42
+ writable: true,
43
+ configurable: true,
44
+ });
45
+ });
46
+
47
+ describe('SessionExpiredModal', () => {
48
+ describe('initial render', () => {
49
+ it('does not render modal content when sessionExpiredAt is null', () => {
50
+ renderWithProviders(<SessionExpiredModal />, {
51
+ knowledgeBaseSession: createMockKnowledgeBaseSession({
52
+ sessionExpiredAt: null,
53
+ }),
54
+ });
55
+ expect(screen.queryByText('Session Expired')).not.toBeInTheDocument();
56
+ });
57
+ });
58
+
59
+ describe('when sessionExpiredAt is set', () => {
60
+ it('renders the modal with default message', () => {
61
+ renderWithProviders(<SessionExpiredModal />, {
62
+ knowledgeBaseSession: createMockKnowledgeBaseSession({
63
+ sessionExpiredAt: Date.now(),
64
+ }),
65
+ });
66
+
67
+ expect(screen.getByText('Session Expired')).toBeInTheDocument();
68
+ expect(screen.getByRole('button', { name: /sign in again/i })).toBeInTheDocument();
69
+ expect(screen.getByRole('button', { name: /go to home/i })).toBeInTheDocument();
70
+ });
71
+
72
+ it('renders the custom message from sessionExpiredMessage', () => {
73
+ renderWithProviders(<SessionExpiredModal />, {
74
+ knowledgeBaseSession: createMockKnowledgeBaseSession({
75
+ sessionExpiredAt: Date.now(),
76
+ sessionExpiredMessage: 'Your token expired at 5pm',
77
+ }),
78
+ });
79
+ expect(screen.getByText(/your token expired at 5pm/i)).toBeInTheDocument();
80
+ });
81
+ });
82
+
83
+ describe('button actions', () => {
84
+ it('calls acknowledgeSessionExpired and navigates to /auth/connect on Sign In Again', () => {
85
+ const ack = vi.fn();
86
+ mockLocation.pathname = '/know/discover';
87
+ renderWithProviders(<SessionExpiredModal />, {
88
+ knowledgeBaseSession: createMockKnowledgeBaseSession({
89
+ sessionExpiredAt: Date.now(),
90
+ acknowledgeSessionExpired: ack,
91
+ }),
92
+ });
93
+
94
+ fireEvent.click(screen.getByRole('button', { name: /sign in again/i }));
95
+
96
+ expect(ack).toHaveBeenCalled();
97
+ expect(mockLocation.href).toBe('/auth/connect?callbackUrl=%2Fknow%2Fdiscover');
98
+ });
99
+
100
+ it('calls acknowledgeSessionExpired and navigates to / on Go to Home', () => {
101
+ const ack = vi.fn();
102
+ renderWithProviders(<SessionExpiredModal />, {
103
+ knowledgeBaseSession: createMockKnowledgeBaseSession({
104
+ sessionExpiredAt: Date.now(),
105
+ acknowledgeSessionExpired: ack,
106
+ }),
107
+ });
108
+
109
+ fireEvent.click(screen.getByRole('button', { name: /go to home/i }));
110
+
111
+ expect(ack).toHaveBeenCalled();
112
+ expect(mockLocation.href).toBe('/');
113
+ });
114
+ });
115
+ });
@@ -5,7 +5,7 @@ import { useTranslations } from '../../contexts/TranslationContext';
5
5
  import type { RouteBuilder, LinkComponentProps } from '../../contexts/RoutingContext';
6
6
  import { useResources } from '../../lib/api-hooks';
7
7
  import type { ResourceId } from '@semiont/core';
8
- import { getAnnotationUriFromEvent } from '@semiont/core';
8
+ import { getAnnotationUriFromEvent, type StoredEventLike } from '@semiont/core';
9
9
  import { HistoryEvent } from './HistoryEvent';
10
10
 
11
11
  interface Props {
@@ -36,11 +36,10 @@ export function AnnotationHistory({ rUri, hoveredAnnotationId, onEventHover, onE
36
36
  const containerRef = useRef<HTMLDivElement>(null);
37
37
 
38
38
  // Sort events by oldest first (most recent at bottom)
39
- // Filter out all job events - they're represented by annotation.body.updated events instead
40
- const events = !eventsData?.events ? [] : [...eventsData.events]
39
+ // Filter out job events - they're represented by mark:body-updated events instead
40
+ const events: StoredEventLike[] = !eventsData?.events ? [] : (eventsData.events as StoredEventLike[])
41
41
  .filter((e) => {
42
- const eventType = e.event.type;
43
- return eventType !== 'job.started' && eventType !== 'job.progress' && eventType !== 'job.completed';
42
+ return e.type !== 'job:started' && e.type !== 'job:progress' && e.type !== 'job:completed';
44
43
  })
45
44
  .sort((a, b) => a.metadata.sequenceNumber - b.metadata.sequenceNumber);
46
45
 
@@ -110,7 +109,7 @@ export function AnnotationHistory({ rUri, hoveredAnnotationId, onEventHover, onE
110
109
 
111
110
  return (
112
111
  <HistoryEvent
113
- key={stored.event.id}
112
+ key={stored.id}
114
113
  event={stored}
115
114
  annotations={annotations}
116
115
  allEvents={events}
@@ -2,7 +2,7 @@
2
2
 
3
3
  import React, { useRef, useCallback, useEffect } from 'react';
4
4
  import type { RouteBuilder, LinkComponentProps } from '../../contexts/RoutingContext';
5
- import type { StoredEventLike, ResourceEventType } from '@semiont/core';
5
+ import type { StoredEventLike, PersistedEventType } from '@semiont/core';
6
6
  import { getAnnotationUriFromEvent } from '@semiont/core';
7
7
  import {
8
8
  formatEventType,
@@ -85,7 +85,7 @@ export function HistoryEvent({
85
85
  const eventWrapperProps = annotationUri ? {
86
86
  type: 'button' as const,
87
87
  onClick: () => onEventClick?.(annotationUri),
88
- 'aria-label': t('viewAnnotation', { content: displayContent?.exact || formatEventType(event.event.type as ResourceEventType, t) }),
88
+ 'aria-label': t('viewAnnotation', { content: displayContent?.exact || formatEventType(event.type as PersistedEventType, t) }),
89
89
  className: 'semiont-history-event',
90
90
  'data-related': isRelated ? 'true' : 'false',
91
91
  'data-interactive': 'true'
@@ -109,7 +109,7 @@ export function HistoryEvent({
109
109
  onMouseEnter={handleEmojiMouseEnter}
110
110
  onMouseLeave={handleEmojiMouseLeave}
111
111
  >
112
- {getEventEmoji(event.event.type as ResourceEventType, event.event.payload)}
112
+ {getEventEmoji(event.type as PersistedEventType, event.payload)}
113
113
  </span>
114
114
  {displayContent ? (
115
115
  displayContent.isTag ? (
@@ -127,16 +127,16 @@ export function HistoryEvent({
127
127
  )
128
128
  ) : (
129
129
  <span className="semiont-history-event__text">
130
- {formatEventType(event.event.type as ResourceEventType, t, event.event.payload)}
130
+ {formatEventType(event.type as PersistedEventType, t, event.payload)}
131
131
  </span>
132
132
  )}
133
- {event.event.userId && (
133
+ {event.userId && (
134
134
  <span className="semiont-history-event__user">
135
- {event.event.userId}
135
+ {event.userId}
136
136
  </span>
137
137
  )}
138
138
  <span className="semiont-history-event__timestamp">
139
- {formatRelativeTime(event.event.timestamp, t)}
139
+ {formatRelativeTime(event.timestamp, t)}
140
140
  </span>
141
141
  </div>
142
142
  {entityTypes.length > 0 && (
@@ -40,8 +40,8 @@ vi.mock('../../../lib/api-hooks', () => ({
40
40
 
41
41
  // Mock HistoryEvent to avoid deep rendering and mocking all its dependencies
42
42
  const MockHistoryEvent = vi.fn(({ event }: any) => (
43
- <div data-testid={`history-event-${event.event.id}`}>
44
- {event.event.type}
43
+ <div data-testid={`history-event-${event.id}`}>
44
+ {event.type}
45
45
  </div>
46
46
  ));
47
47
 
@@ -54,23 +54,22 @@ const mockGetAnnotationUri = getAnnotationUriFromEvent as ReturnType<typeof vi.f
54
54
 
55
55
  const testRId = 'res-1' as ResourceId;
56
56
 
57
- function makeStoredEvent(id: string, type: string, seq: number, overrides: Record<string, any> = {}): StoredEvent {
57
+ /** Returns flat StoredEventResponse shape (matches API response) */
58
+ function makeStoredEvent(id: string, type: string, seq: number, overrides: Record<string, any> = {}): any {
58
59
  return {
59
- event: {
60
- id,
61
- type,
62
- timestamp: '2026-03-06T12:00:00Z',
63
- resourceId: 'res-1',
64
- userId: 'user-1',
65
- version: 1,
66
- payload: {},
67
- ...overrides,
68
- },
60
+ id,
61
+ type,
62
+ timestamp: '2026-03-06T12:00:00Z',
63
+ resourceId: 'res-1',
64
+ userId: 'user-1',
65
+ version: 1,
66
+ payload: {},
67
+ ...overrides,
69
68
  metadata: {
70
69
  sequenceNumber: seq,
71
- storedAt: '2026-03-06T12:00:00Z',
70
+ streamPosition: 0,
72
71
  },
73
- } as StoredEvent;
72
+ };
74
73
  }
75
74
 
76
75
  const MockLink = ({ href, children, ...props }: any) => <a href={href} {...props}>{children}</a>;
@@ -130,9 +129,9 @@ describe('AnnotationHistory', () => {
130
129
 
131
130
  it('renders events sorted by sequence number', () => {
132
131
  const events = [
133
- makeStoredEvent('evt-3', 'annotation.added', 3),
134
- makeStoredEvent('evt-1', 'resource.created', 1),
135
- makeStoredEvent('evt-2', 'annotation.added', 2),
132
+ makeStoredEvent('evt-3', 'mark:added', 3),
133
+ makeStoredEvent('evt-1', 'yield:created', 1),
134
+ makeStoredEvent('evt-2', 'mark:added', 2),
136
135
  ];
137
136
  mockEventsUseQuery.mockReturnValue({ data: { events }, isLoading: false, isError: false });
138
137
 
@@ -152,18 +151,18 @@ describe('AnnotationHistory', () => {
152
151
 
153
152
  // Verify HistoryEvent was called with events in sequence order
154
153
  const calls = MockHistoryEvent.mock.calls;
155
- expect(calls[0][0].event.event.id).toBe('evt-1');
156
- expect(calls[1][0].event.event.id).toBe('evt-2');
157
- expect(calls[2][0].event.event.id).toBe('evt-3');
154
+ expect(calls[0][0].event.id).toBe('evt-1'); // .event is the React prop name
155
+ expect(calls[1][0].event.id).toBe('evt-2');
156
+ expect(calls[2][0].event.id).toBe('evt-3');
158
157
  });
159
158
 
160
159
  it('filters out job events', () => {
161
160
  const events = [
162
- makeStoredEvent('evt-1', 'resource.created', 1),
163
- makeStoredEvent('evt-2', 'job.started', 2),
164
- makeStoredEvent('evt-3', 'job.progress', 3),
165
- makeStoredEvent('evt-4', 'job.completed', 4),
166
- makeStoredEvent('evt-5', 'annotation.added', 5),
161
+ makeStoredEvent('evt-1', 'yield:created', 1),
162
+ makeStoredEvent('evt-2', 'job:started', 2),
163
+ makeStoredEvent('evt-3', 'job:progress', 3),
164
+ makeStoredEvent('evt-4', 'job:completed', 4),
165
+ makeStoredEvent('evt-5', 'mark:added', 5),
167
166
  ];
168
167
  mockEventsUseQuery.mockReturnValue({ data: { events }, isLoading: false, isError: false });
169
168
 
@@ -188,7 +187,7 @@ describe('AnnotationHistory', () => {
188
187
  mockGetAnnotationUri.mockReturnValue(annotationUri);
189
188
 
190
189
  const events = [
191
- makeStoredEvent('evt-1', 'annotation.added', 1),
190
+ makeStoredEvent('evt-1', 'mark:added', 1),
192
191
  ];
193
192
  mockEventsUseQuery.mockReturnValue({ data: { events }, isLoading: false, isError: false });
194
193
 
@@ -209,7 +208,7 @@ describe('AnnotationHistory', () => {
209
208
  mockGetAnnotationUri.mockReturnValue('http://localhost/annotations/ann-other');
210
209
 
211
210
  const events = [
212
- makeStoredEvent('evt-1', 'annotation.added', 1),
211
+ makeStoredEvent('evt-1', 'mark:added', 1),
213
212
  ];
214
213
  mockEventsUseQuery.mockReturnValue({ data: { events }, isLoading: false, isError: false });
215
214
 
@@ -228,7 +227,7 @@ describe('AnnotationHistory', () => {
228
227
 
229
228
  it('passes isRelated=false when no hoveredAnnotationId', () => {
230
229
  const events = [
231
- makeStoredEvent('evt-1', 'annotation.added', 1),
230
+ makeStoredEvent('evt-1', 'mark:added', 1),
232
231
  ];
233
232
  mockEventsUseQuery.mockReturnValue({ data: { events }, isLoading: false, isError: false });
234
233
 
@@ -249,7 +248,7 @@ describe('AnnotationHistory', () => {
249
248
  const onEventHover = vi.fn();
250
249
 
251
250
  const events = [
252
- makeStoredEvent('evt-1', 'resource.created', 1),
251
+ makeStoredEvent('evt-1', 'yield:created', 1),
253
252
  ];
254
253
  mockEventsUseQuery.mockReturnValue({ data: { events }, isLoading: false, isError: false });
255
254
 
@@ -270,7 +269,7 @@ describe('AnnotationHistory', () => {
270
269
 
271
270
  it('does not pass onEventClick/onEventHover when not provided', () => {
272
271
  const events = [
273
- makeStoredEvent('evt-1', 'resource.created', 1),
272
+ makeStoredEvent('evt-1', 'yield:created', 1),
274
273
  ];
275
274
  mockEventsUseQuery.mockReturnValue({ data: { events }, isLoading: false, isError: false });
276
275
 
@@ -292,7 +291,7 @@ describe('AnnotationHistory', () => {
292
291
  mockAnnotationsUseQuery.mockReturnValue({ data: { annotations: mockAnnotations } });
293
292
 
294
293
  const events = [
295
- makeStoredEvent('evt-1', 'resource.created', 1),
294
+ makeStoredEvent('evt-1', 'yield:created', 1),
296
295
  ];
297
296
  mockEventsUseQuery.mockReturnValue({ data: { events }, isLoading: false, isError: false });
298
297
 
@@ -312,7 +311,7 @@ describe('AnnotationHistory', () => {
312
311
  mockAnnotationsUseQuery.mockReturnValue({ data: undefined });
313
312
 
314
313
  const events = [
315
- makeStoredEvent('evt-1', 'resource.created', 1),
314
+ makeStoredEvent('evt-1', 'yield:created', 1),
316
315
  ];
317
316
  mockEventsUseQuery.mockReturnValue({ data: { events }, isLoading: false, isError: false });
318
317
 
@@ -330,7 +329,7 @@ describe('AnnotationHistory', () => {
330
329
 
331
330
  it('renders history panel structure with title and list', () => {
332
331
  const events = [
333
- makeStoredEvent('evt-1', 'resource.created', 1),
332
+ makeStoredEvent('evt-1', 'yield:created', 1),
334
333
  ];
335
334
  mockEventsUseQuery.mockReturnValue({ data: { events }, isLoading: false, isError: false });
336
335
 
@@ -49,23 +49,21 @@ const mockGetEventEntityTypes = getEventEntityTypes as ReturnType<typeof vi.fn>;
49
49
  const mockGetResourceCreationDetails = getResourceCreationDetails as ReturnType<typeof vi.fn>;
50
50
  const mockFormatEventType = formatEventType as ReturnType<typeof vi.fn>;
51
51
 
52
- function makeStoredEvent(overrides: Partial<StoredEvent['event']> = {}): StoredEvent {
52
+ function makeStoredEvent(overrides: Record<string, any> = {}): any {
53
53
  return {
54
- event: {
55
- id: 'evt-1',
56
- type: 'resource.created',
57
- timestamp: '2026-03-06T12:00:00Z',
58
- resourceId: 'res-1',
59
- userId: 'user-1',
60
- version: 1,
61
- payload: { name: 'Test', format: 'text/plain', contentChecksum: 'abc', creationMethod: 'upload' },
62
- ...overrides,
63
- },
54
+ id: 'evt-1',
55
+ type: 'yield:created',
56
+ timestamp: '2026-03-06T12:00:00Z',
57
+ resourceId: 'res-1',
58
+ userId: 'user-1',
59
+ version: 1,
60
+ payload: { name: 'Test', format: 'text/plain', contentChecksum: 'abc', creationMethod: 'upload' },
61
+ ...overrides,
64
62
  metadata: {
65
63
  sequenceNumber: 1,
66
- storedAt: '2026-03-06T12:00:00Z',
64
+ streamPosition: 0,
67
65
  },
68
- } as StoredEvent;
66
+ };
69
67
  }
70
68
 
71
69
  const mockT = (key: string) => key;
@@ -139,7 +137,7 @@ describe('HistoryEvent', () => {
139
137
 
140
138
  it('renders as button when annotationUri exists', () => {
141
139
  mockGetAnnotationUri.mockReturnValue('http://localhost/annotations/ann-1');
142
- const event = makeStoredEvent({ type: 'annotation.added' } as any);
140
+ const event = makeStoredEvent({ type: 'mark:added' } as any);
143
141
  const { container } = renderWithProviders(
144
142
  <HistoryEvent
145
143
  event={event}
@@ -160,7 +158,7 @@ describe('HistoryEvent', () => {
160
158
  const annotationUri = 'http://localhost/annotations/ann-1';
161
159
  mockGetAnnotationUri.mockReturnValue(annotationUri);
162
160
  const onEventClick = vi.fn();
163
- const event = makeStoredEvent({ type: 'annotation.added' } as any);
161
+ const event = makeStoredEvent({ type: 'mark:added' } as any);
164
162
 
165
163
  renderWithProviders(
166
164
  <HistoryEvent
@@ -364,7 +362,7 @@ describe('HistoryEvent', () => {
364
362
  const annotationUri = 'http://localhost/annotations/ann-1';
365
363
  mockGetAnnotationUri.mockReturnValue(annotationUri);
366
364
  const onEventRef = vi.fn();
367
- const event = makeStoredEvent({ type: 'annotation.added' } as any);
365
+ const event = makeStoredEvent({ type: 'mark:added' } as any);
368
366
 
369
367
  renderWithProviders(
370
368
  <HistoryEvent
@@ -387,7 +385,7 @@ describe('HistoryEvent', () => {
387
385
  const annotationUri = 'http://localhost/annotations/ann-1';
388
386
  mockGetAnnotationUri.mockReturnValue(annotationUri);
389
387
  const onEventHover = vi.fn();
390
- const event = makeStoredEvent({ type: 'annotation.added' } as any);
388
+ const event = makeStoredEvent({ type: 'mark:added' } as any);
391
389
 
392
390
  const { container } = renderWithProviders(
393
391
  <HistoryEvent
@@ -420,7 +418,7 @@ describe('HistoryEvent', () => {
420
418
  const annotationUri = 'http://localhost/annotations/ann-1';
421
419
  mockGetAnnotationUri.mockReturnValue(annotationUri);
422
420
  const onEventHover = vi.fn();
423
- const event = makeStoredEvent({ type: 'annotation.added' } as any);
421
+ const event = makeStoredEvent({ type: 'mark:added' } as any);
424
422
 
425
423
  const { container } = renderWithProviders(
426
424
  <HistoryEvent
@@ -454,7 +452,7 @@ describe('HistoryEvent', () => {
454
452
 
455
453
  it('sets data-interactive on button wrapper', () => {
456
454
  mockGetAnnotationUri.mockReturnValue('http://localhost/annotations/ann-1');
457
- const event = makeStoredEvent({ type: 'annotation.added' } as any);
455
+ const event = makeStoredEvent({ type: 'mark:added' } as any);
458
456
  const { container } = renderWithProviders(
459
457
  <HistoryEvent
460
458
  event={event}