@semiont/react-ui 0.4.14 → 0.4.16

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 (169) hide show
  1. package/README.md +18 -12
  2. package/dist/KnowledgeBaseSessionContext-BNNunwzO.d.mts +175 -0
  3. package/dist/{PdfAnnotationCanvas.client-CW6SKH2U.mjs → PdfAnnotationCanvas.client-CHDCGQBR.mjs} +3 -3
  4. package/dist/{ar-R4CRNXEF.mjs → ar-3W37O3R3.mjs} +9 -3
  5. package/dist/ar-3W37O3R3.mjs.map +1 -0
  6. package/dist/{bn-CZKGRHTA.mjs → bn-JZTJLMVE.mjs} +9 -3
  7. package/dist/bn-JZTJLMVE.mjs.map +1 -0
  8. package/dist/chunk-FAI3S4BM.mjs +865 -0
  9. package/dist/chunk-FAI3S4BM.mjs.map +1 -0
  10. package/dist/{chunk-HVMAGUFA.mjs → chunk-NOD3NCXE.mjs} +3 -1
  11. package/dist/chunk-NOD3NCXE.mjs.map +1 -0
  12. package/dist/{chunk-HNZOXH4L.mjs → chunk-OZICDVH7.mjs} +5 -3
  13. package/dist/chunk-OZICDVH7.mjs.map +1 -0
  14. package/dist/{chunk-BQJWOK4C.mjs → chunk-VN5NY4SN.mjs} +9 -8
  15. package/dist/chunk-VN5NY4SN.mjs.map +1 -0
  16. package/dist/{cs-4WIB2IHH.mjs → cs-XYHH7HNE.mjs} +9 -3
  17. package/dist/cs-XYHH7HNE.mjs.map +1 -0
  18. package/dist/{da-JWYEUYPX.mjs → da-MZKIECVT.mjs} +9 -3
  19. package/dist/da-MZKIECVT.mjs.map +1 -0
  20. package/dist/{de-GWUQZGER.mjs → de-AYXTMRQW.mjs} +9 -3
  21. package/dist/de-AYXTMRQW.mjs.map +1 -0
  22. package/dist/{el-DM2GT7P5.mjs → el-A6CVQWAW.mjs} +9 -3
  23. package/dist/el-A6CVQWAW.mjs.map +1 -0
  24. package/dist/{en-IUV4ZXKH.mjs → en-YPQQBI4T.mjs} +2 -2
  25. package/dist/{es-6LVQIM3D.mjs → es-M2HXLJGT.mjs} +9 -3
  26. package/dist/es-M2HXLJGT.mjs.map +1 -0
  27. package/dist/{fa-IRUJY3QI.mjs → fa-V6JZJDYP.mjs} +9 -3
  28. package/dist/fa-V6JZJDYP.mjs.map +1 -0
  29. package/dist/{fi-53FBOEVT.mjs → fi-ONDTZ5H7.mjs} +9 -3
  30. package/dist/fi-ONDTZ5H7.mjs.map +1 -0
  31. package/dist/{fr-Q5KY7QL6.mjs → fr-PAPV4H4G.mjs} +9 -3
  32. package/dist/fr-PAPV4H4G.mjs.map +1 -0
  33. package/dist/{he-HJNKULBY.mjs → he-F6VTLJLW.mjs} +9 -3
  34. package/dist/he-F6VTLJLW.mjs.map +1 -0
  35. package/dist/{hi-UYZ4X6CR.mjs → hi-CFUAV4BF.mjs} +9 -3
  36. package/dist/hi-CFUAV4BF.mjs.map +1 -0
  37. package/dist/{id-UAQMH6U2.mjs → id-NBKLCCI7.mjs} +9 -3
  38. package/dist/id-NBKLCCI7.mjs.map +1 -0
  39. package/dist/index.d.mts +141 -169
  40. package/dist/index.mjs +2394 -2116
  41. package/dist/index.mjs.map +1 -1
  42. package/dist/{it-C7QEBNFA.mjs → it-SLSOWVVU.mjs} +9 -3
  43. package/dist/it-SLSOWVVU.mjs.map +1 -0
  44. package/dist/{ja-THS6AOSJ.mjs → ja-L5IG4ECE.mjs} +9 -3
  45. package/dist/ja-L5IG4ECE.mjs.map +1 -0
  46. package/dist/{ko-XKK3TWQG.mjs → ko-QYMTULKK.mjs} +9 -3
  47. package/dist/ko-QYMTULKK.mjs.map +1 -0
  48. package/dist/{ms-GSK7LIF7.mjs → ms-5DGSFKM2.mjs} +9 -3
  49. package/dist/ms-5DGSFKM2.mjs.map +1 -0
  50. package/dist/{nl-KUBWITGY.mjs → nl-VZPCGONO.mjs} +9 -3
  51. package/dist/nl-VZPCGONO.mjs.map +1 -0
  52. package/dist/{no-ECWZUHT6.mjs → no-MF6F352I.mjs} +9 -3
  53. package/dist/no-MF6F352I.mjs.map +1 -0
  54. package/dist/{pl-PLVWSZWS.mjs → pl-WIK72JUO.mjs} +9 -3
  55. package/dist/pl-WIK72JUO.mjs.map +1 -0
  56. package/dist/{pt-AL74ZTKB.mjs → pt-RRP5ZF6A.mjs} +9 -3
  57. package/dist/pt-RRP5ZF6A.mjs.map +1 -0
  58. package/dist/{ro-WTPHLHGS.mjs → ro-XHQLC3T7.mjs} +9 -3
  59. package/dist/ro-XHQLC3T7.mjs.map +1 -0
  60. package/dist/{sv-QCLI7SG4.mjs → sv-EWULDN6E.mjs} +9 -3
  61. package/dist/sv-EWULDN6E.mjs.map +1 -0
  62. package/dist/test-utils.d.mts +13 -62
  63. package/dist/test-utils.mjs +41 -22
  64. package/dist/test-utils.mjs.map +1 -1
  65. package/dist/{th-WCKVZU6U.mjs → th-TGOBHFG4.mjs} +9 -3
  66. package/dist/th-TGOBHFG4.mjs.map +1 -0
  67. package/dist/{tr-2CAFS2XS.mjs → tr-LMMPBMV7.mjs} +9 -3
  68. package/dist/tr-LMMPBMV7.mjs.map +1 -0
  69. package/dist/{uk-TDE4JLCY.mjs → uk-IPGRRJY6.mjs} +9 -3
  70. package/dist/uk-IPGRRJY6.mjs.map +1 -0
  71. package/dist/{vi-KKXZ4PCX.mjs → vi-Q676OJQS.mjs} +9 -3
  72. package/dist/vi-Q676OJQS.mjs.map +1 -0
  73. package/dist/{zh-VH4XN5PV.mjs → zh-F3MTWQDX.mjs} +9 -3
  74. package/dist/zh-F3MTWQDX.mjs.map +1 -0
  75. package/package.json +5 -3
  76. package/src/components/ProtectedErrorBoundary.tsx +95 -0
  77. package/src/components/__tests__/ProtectedErrorBoundary.test.tsx +197 -0
  78. package/src/components/modals/PermissionDeniedModal.tsx +140 -0
  79. package/src/components/modals/ReferenceWizardModal.tsx +3 -2
  80. package/src/components/modals/SessionExpiredModal.tsx +101 -0
  81. package/src/components/modals/__tests__/PermissionDeniedModal.test.tsx +150 -0
  82. package/src/components/modals/__tests__/SessionExpiredModal.test.tsx +115 -0
  83. package/src/components/resource/AnnotationHistory.tsx +5 -6
  84. package/src/components/resource/HistoryEvent.tsx +9 -8
  85. package/src/components/resource/__tests__/AnnotationHistory.test.tsx +33 -34
  86. package/src/components/resource/__tests__/HistoryEvent.test.tsx +18 -19
  87. package/src/components/resource/__tests__/event-formatting.test.ts +70 -94
  88. package/src/components/resource/event-formatting.ts +92 -56
  89. package/src/components/resource/panels/ReferenceEntry.tsx +7 -5
  90. package/src/components/resource/panels/ResourceInfoPanel.tsx +18 -6
  91. package/src/components/resource/panels/__tests__/ReferenceEntry.test.tsx +12 -12
  92. package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +24 -0
  93. package/src/features/resource-compose/components/ResourceComposePage.tsx +10 -1
  94. package/src/features/resource-viewer/__tests__/AnnotationCreationPending.test.tsx +1 -1
  95. package/src/features/resource-viewer/__tests__/AnnotationDeletionIntegration.test.tsx +4 -4
  96. package/src/features/resource-viewer/__tests__/AnnotationProgressDismissal.test.tsx +5 -10
  97. package/src/features/resource-viewer/__tests__/BindFlowIntegration.test.tsx +23 -54
  98. package/src/features/resource-viewer/__tests__/DetectionFlowBug.test.tsx +6 -6
  99. package/src/features/resource-viewer/__tests__/DetectionFlowIntegration.test.tsx +7 -19
  100. package/src/features/resource-viewer/__tests__/ToastNotifications.test.tsx +1 -1
  101. package/src/features/resource-viewer/__tests__/YieldFlowIntegration.test.tsx +18 -44
  102. package/src/features/resource-viewer/__tests__/annotation-progress-flow.test.tsx +6 -6
  103. package/src/features/resource-viewer/components/ResourceViewerPage.tsx +26 -26
  104. package/src/styles/features/compose.css +63 -0
  105. package/translations/ar.json +6 -2
  106. package/translations/bn.json +6 -2
  107. package/translations/cs.json +6 -2
  108. package/translations/da.json +6 -2
  109. package/translations/de.json +6 -2
  110. package/translations/el.json +6 -2
  111. package/translations/en.json +2 -0
  112. package/translations/es.json +6 -2
  113. package/translations/fa.json +6 -2
  114. package/translations/fi.json +6 -2
  115. package/translations/fr.json +6 -2
  116. package/translations/he.json +6 -2
  117. package/translations/hi.json +6 -2
  118. package/translations/id.json +6 -2
  119. package/translations/it.json +6 -2
  120. package/translations/ja.json +6 -2
  121. package/translations/ko.json +6 -2
  122. package/translations/ms.json +6 -2
  123. package/translations/nl.json +6 -2
  124. package/translations/no.json +6 -2
  125. package/translations/pl.json +6 -2
  126. package/translations/pt.json +6 -2
  127. package/translations/ro.json +6 -2
  128. package/translations/sv.json +6 -2
  129. package/translations/th.json +6 -2
  130. package/translations/tr.json +6 -2
  131. package/translations/uk.json +6 -2
  132. package/translations/vi.json +6 -2
  133. package/translations/zh.json +6 -2
  134. package/dist/TranslationManager-CudgH3gw.d.mts +0 -107
  135. package/dist/ar-R4CRNXEF.mjs.map +0 -1
  136. package/dist/bn-CZKGRHTA.mjs.map +0 -1
  137. package/dist/chunk-BQJWOK4C.mjs.map +0 -1
  138. package/dist/chunk-HNZOXH4L.mjs.map +0 -1
  139. package/dist/chunk-HVMAGUFA.mjs.map +0 -1
  140. package/dist/chunk-OL5UST25.mjs +0 -413
  141. package/dist/chunk-OL5UST25.mjs.map +0 -1
  142. package/dist/cs-4WIB2IHH.mjs.map +0 -1
  143. package/dist/da-JWYEUYPX.mjs.map +0 -1
  144. package/dist/de-GWUQZGER.mjs.map +0 -1
  145. package/dist/el-DM2GT7P5.mjs.map +0 -1
  146. package/dist/es-6LVQIM3D.mjs.map +0 -1
  147. package/dist/fa-IRUJY3QI.mjs.map +0 -1
  148. package/dist/fi-53FBOEVT.mjs.map +0 -1
  149. package/dist/fr-Q5KY7QL6.mjs.map +0 -1
  150. package/dist/he-HJNKULBY.mjs.map +0 -1
  151. package/dist/hi-UYZ4X6CR.mjs.map +0 -1
  152. package/dist/id-UAQMH6U2.mjs.map +0 -1
  153. package/dist/it-C7QEBNFA.mjs.map +0 -1
  154. package/dist/ja-THS6AOSJ.mjs.map +0 -1
  155. package/dist/ko-XKK3TWQG.mjs.map +0 -1
  156. package/dist/ms-GSK7LIF7.mjs.map +0 -1
  157. package/dist/nl-KUBWITGY.mjs.map +0 -1
  158. package/dist/no-ECWZUHT6.mjs.map +0 -1
  159. package/dist/pl-PLVWSZWS.mjs.map +0 -1
  160. package/dist/pt-AL74ZTKB.mjs.map +0 -1
  161. package/dist/ro-WTPHLHGS.mjs.map +0 -1
  162. package/dist/sv-QCLI7SG4.mjs.map +0 -1
  163. package/dist/th-WCKVZU6U.mjs.map +0 -1
  164. package/dist/tr-2CAFS2XS.mjs.map +0 -1
  165. package/dist/uk-TDE4JLCY.mjs.map +0 -1
  166. package/dist/vi-KKXZ4PCX.mjs.map +0 -1
  167. package/dist/zh-VH4XN5PV.mjs.map +0 -1
  168. /package/dist/{PdfAnnotationCanvas.client-CW6SKH2U.mjs.map → PdfAnnotationCanvas.client-CHDCGQBR.mjs.map} +0 -0
  169. /package/dist/{en-IUV4ZXKH.mjs.map → en-YPQQBI4T.mjs.map} +0 -0
@@ -26,41 +26,41 @@ describe('event-formatting', () => {
26
26
 
27
27
  describe('formatEventType', () => {
28
28
  it('returns translation key for resource events', () => {
29
- expect(formatEventType('resource.created', t)).toBe('resourceCreated');
30
- expect(formatEventType('resource.cloned', t)).toBe('resourceCloned');
31
- expect(formatEventType('resource.archived', t)).toBe('resourceArchived');
32
- expect(formatEventType('resource.unarchived', t)).toBe('resourceUnarchived');
29
+ expect(formatEventType('yield:created', t)).toBe('resourceCreated');
30
+ expect(formatEventType('yield:cloned', t)).toBe('resourceCloned');
31
+ expect(formatEventType('mark:archived', t)).toBe('resourceArchived');
32
+ expect(formatEventType('mark:unarchived', t)).toBe('resourceUnarchived');
33
33
  });
34
34
 
35
- it('returns motivation-specific key for annotation.added', () => {
36
- expect(formatEventType('annotation.added', t, { annotation: { motivation: 'highlighting' } })).toBe('highlightAdded');
37
- expect(formatEventType('annotation.added', t, { annotation: { motivation: 'linking' } })).toBe('referenceCreated');
38
- expect(formatEventType('annotation.added', t, { annotation: { motivation: 'assessing' } })).toBe('assessmentAdded');
39
- expect(formatEventType('annotation.added', t, { annotation: { motivation: 'commenting' } })).toBe('annotationAdded');
35
+ it('returns motivation-specific key for mark:added', () => {
36
+ expect(formatEventType('mark:added', t, { annotation: { motivation: 'highlighting' } })).toBe('highlightAdded');
37
+ expect(formatEventType('mark:added', t, { annotation: { motivation: 'linking' } })).toBe('referenceCreated');
38
+ expect(formatEventType('mark:added', t, { annotation: { motivation: 'assessing' } })).toBe('assessmentAdded');
39
+ expect(formatEventType('mark:added', t, { annotation: { motivation: 'commenting' } })).toBe('annotationAdded');
40
40
  });
41
41
 
42
- it('returns annotationRemoved for annotation.removed', () => {
43
- expect(formatEventType('annotation.removed', t)).toBe('annotationRemoved');
42
+ it('returns annotationRemoved for mark:removed', () => {
43
+ expect(formatEventType('mark:removed', t)).toBe('annotationRemoved');
44
44
  });
45
45
 
46
- it('returns annotationBodyUpdated for annotation.body.updated', () => {
47
- expect(formatEventType('annotation.body.updated', t)).toBe('annotationBodyUpdated');
46
+ it('returns annotationBodyUpdated for mark:body-updated', () => {
47
+ expect(formatEventType('mark:body-updated', t)).toBe('annotationBodyUpdated');
48
48
  });
49
49
 
50
50
  it('returns entitytag keys', () => {
51
- expect(formatEventType('entitytag.added', t)).toBe('entitytagAdded');
52
- expect(formatEventType('entitytag.removed', t)).toBe('entitytagRemoved');
51
+ expect(formatEventType('mark:entity-tag-added', t)).toBe('entitytagAdded');
52
+ expect(formatEventType('mark:entity-tag-removed', t)).toBe('entitytagRemoved');
53
53
  });
54
54
 
55
55
  it('returns jobEvent for job types', () => {
56
- expect(formatEventType('job.completed', t)).toBe('jobEvent');
57
- expect(formatEventType('job.started', t)).toBe('jobEvent');
58
- expect(formatEventType('job.failed', t)).toBe('jobEvent');
56
+ expect(formatEventType('job:completed', t)).toBe('jobEvent');
57
+ expect(formatEventType('job:started', t)).toBe('jobEvent');
58
+ expect(formatEventType('job:failed', t)).toBe('jobEvent');
59
59
  });
60
60
 
61
- it('returns representationEvent for representation types', () => {
62
- expect(formatEventType('representation.added', t)).toBe('representationEvent');
63
- expect(formatEventType('representation.removed', t)).toBe('representationEvent');
61
+ it('returns representationEvent for yield:representation types', () => {
62
+ expect(formatEventType('yield:representation-added', t)).toBe('representationEvent');
63
+ expect(formatEventType('yield:representation-removed', t)).toBe('representationEvent');
64
64
  });
65
65
 
66
66
  it('returns raw type for unknown event types', () => {
@@ -70,33 +70,33 @@ describe('event-formatting', () => {
70
70
 
71
71
  describe('getEventEmoji', () => {
72
72
  it('returns document emoji for resource events', () => {
73
- expect(getEventEmoji('resource.created')).toBe('📄');
74
- expect(getEventEmoji('resource.cloned')).toBe('📄');
73
+ expect(getEventEmoji('yield:created')).toBe('📄');
74
+ expect(getEventEmoji('yield:cloned')).toBe('📄');
75
75
  });
76
76
 
77
- it('returns motivation-specific emoji for annotation.added', () => {
78
- expect(getEventEmoji('annotation.added', { annotation: { motivation: 'highlighting' } })).toBe('🟡');
79
- expect(getEventEmoji('annotation.added', { annotation: { motivation: 'linking' } })).toBeTruthy();
80
- expect(getEventEmoji('annotation.added', { annotation: { motivation: 'assessing' } })).toBe('🔴');
77
+ it('returns motivation-specific emoji for mark:added', () => {
78
+ expect(getEventEmoji('mark:added', { annotation: { motivation: 'highlighting' } })).toBe('🟡');
79
+ expect(getEventEmoji('mark:added', { annotation: { motivation: 'linking' } })).toBeTruthy();
80
+ expect(getEventEmoji('mark:added', { annotation: { motivation: 'assessing' } })).toBe('🔴');
81
81
  });
82
82
 
83
- it('returns trash emoji for annotation.removed', () => {
84
- expect(getEventEmoji('annotation.removed')).toBe('🗑️');
83
+ it('returns trash emoji for mark:removed', () => {
84
+ expect(getEventEmoji('mark:removed')).toBe('🗑️');
85
85
  });
86
86
 
87
- it('returns pencil emoji for annotation.body.updated', () => {
88
- expect(getEventEmoji('annotation.body.updated')).toBe('✏️');
87
+ it('returns pencil emoji for mark:body-updated', () => {
88
+ expect(getEventEmoji('mark:body-updated')).toBe('✏️');
89
89
  });
90
90
 
91
91
  it('returns tag emoji for entitytag events', () => {
92
- expect(getEventEmoji('entitytag.added')).toBe('🏷️');
93
- expect(getEventEmoji('entitytag.removed')).toBe('🏷️');
92
+ expect(getEventEmoji('mark:entity-tag-added')).toBe('🏷️');
93
+ expect(getEventEmoji('mark:entity-tag-removed')).toBe('🏷️');
94
94
  });
95
95
 
96
96
  it('returns appropriate emoji for job events', () => {
97
- expect(getEventEmoji('job.completed')).toBe('🔗');
98
- expect(getEventEmoji('job.started')).toBe('⚙️');
99
- expect(getEventEmoji('job.failed')).toBe('❌');
97
+ expect(getEventEmoji('job:completed')).toBe('🔗');
98
+ expect(getEventEmoji('job:started')).toBe('⚙️');
99
+ expect(getEventEmoji('job:failed')).toBe('❌');
100
100
  });
101
101
 
102
102
  it('returns default emoji for unknown', () => {
@@ -137,55 +137,43 @@ describe('event-formatting', () => {
137
137
  });
138
138
 
139
139
  describe('getEventDisplayContent', () => {
140
- it('returns resource name for resource.created', () => {
141
- const event = {
142
- event: { type: 'resource.created' as const, payload: { name: 'My Document' }, userId: 'u1', timestamp: '' },
143
- } as any;
140
+ it('returns resource name for yield:created', () => {
141
+ const event = { type: 'yield:created' as const, payload: { name: 'My Document' }, userId: 'u1', timestamp: '' } as any;
144
142
  const result = getEventDisplayContent(event, [], []);
145
143
  expect(result).toEqual({ exact: 'My Document', isQuoted: false, isTag: false });
146
144
  });
147
145
 
148
- it('returns resource name for resource.cloned', () => {
149
- const event = {
150
- event: { type: 'resource.cloned' as const, payload: { name: 'Cloned Doc' }, userId: 'u1', timestamp: '' },
151
- } as any;
146
+ it('returns resource name for yield:cloned', () => {
147
+ const event = { type: 'yield:cloned' as const, payload: { name: 'Cloned Doc' }, userId: 'u1', timestamp: '' } as any;
152
148
  const result = getEventDisplayContent(event, [], []);
153
149
  expect(result).toEqual({ exact: 'Cloned Doc', isQuoted: false, isTag: false });
154
150
  });
155
151
 
156
152
  it('returns entity type for entitytag events', () => {
157
- const event = {
158
- event: { type: 'entitytag.added' as const, payload: { entityType: 'Person' }, userId: 'u1', timestamp: '' },
159
- } as any;
153
+ const event = { type: 'mark:entity-tag-added' as const, payload: { entityType: 'Person' }, userId: 'u1', timestamp: '' } as any;
160
154
  const result = getEventDisplayContent(event, [], []);
161
155
  expect(result).toEqual({ exact: 'Person', isQuoted: false, isTag: true });
162
156
  });
163
157
 
164
- it('returns null for job.started', () => {
165
- const event = {
166
- event: { type: 'job.started' as const, payload: {}, userId: 'u1', timestamp: '' },
167
- } as any;
158
+ it('returns null for job:started', () => {
159
+ const event = { type: 'job:started' as const, payload: {}, userId: 'u1', timestamp: '' } as any;
168
160
  expect(getEventDisplayContent(event, [], [])).toBeNull();
169
161
  });
170
162
 
171
- it('returns null for representation events', () => {
172
- const event = {
173
- event: { type: 'representation.added' as const, payload: {}, userId: 'u1', timestamp: '' },
174
- } as any;
163
+ it('returns null for yield:representation events', () => {
164
+ const event = { type: 'yield:representation-added' as const, payload: {}, userId: 'u1', timestamp: '' } as any;
175
165
  expect(getEventDisplayContent(event, [], [])).toBeNull();
176
166
  });
177
167
  });
178
168
 
179
169
  describe('getEventEntityTypes', () => {
180
- it('returns entity types from annotation.added with linking motivation', () => {
170
+ it('returns entity types from mark:added with linking motivation', () => {
181
171
  const event = {
182
- event: {
183
- type: 'annotation.added' as const,
184
- payload: {
185
- annotation: {
186
- motivation: 'linking',
187
- body: { entityTypes: ['Person', 'Place'] },
188
- },
172
+ type: 'mark:added' as const,
173
+ payload: {
174
+ annotation: {
175
+ motivation: 'linking',
176
+ body: { entityTypes: ['Person', 'Place'] },
189
177
  },
190
178
  },
191
179
  } as any;
@@ -194,33 +182,27 @@ describe('event-formatting', () => {
194
182
 
195
183
  it('returns empty array for non-linking annotations', () => {
196
184
  const event = {
197
- event: {
198
- type: 'annotation.added' as const,
199
- payload: {
200
- annotation: { motivation: 'highlighting', body: null },
201
- },
185
+ type: 'mark:added' as const,
186
+ payload: {
187
+ annotation: { motivation: 'highlighting', body: null },
202
188
  },
203
189
  } as any;
204
190
  expect(getEventEntityTypes(event)).toEqual([]);
205
191
  });
206
192
 
207
193
  it('returns empty array for non-annotation events', () => {
208
- const event = {
209
- event: { type: 'resource.created' as const, payload: { name: 'test' } },
210
- } as any;
194
+ const event = { type: 'yield:created' as const, payload: { name: 'test' } } as any;
211
195
  expect(getEventEntityTypes(event)).toEqual([]);
212
196
  });
213
197
  });
214
198
 
215
199
  describe('getResourceCreationDetails', () => {
216
- it('returns created details for resource.created', () => {
200
+ it('returns created details for yield:created', () => {
217
201
  const event = {
218
- event: {
219
- type: 'resource.created' as const,
220
- payload: { name: 'Doc', creationMethod: 'upload' },
221
- userId: 'user-1',
222
- timestamp: '',
223
- },
202
+ type: 'yield:created' as const,
203
+ payload: { name: 'Doc', creationMethod: 'upload' },
204
+ userId: 'user-1',
205
+ timestamp: '',
224
206
  } as any;
225
207
  const result = getResourceCreationDetails(event);
226
208
  expect(result).toEqual({
@@ -231,14 +213,12 @@ describe('event-formatting', () => {
231
213
  });
232
214
  });
233
215
 
234
- it('returns cloned details for resource.cloned', () => {
216
+ it('returns cloned details for yield:cloned', () => {
235
217
  const event = {
236
- event: {
237
- type: 'resource.cloned' as const,
238
- payload: { name: 'Clone', creationMethod: 'clone', parentResourceId: 'parent-1' },
239
- userId: 'user-2',
240
- timestamp: '',
241
- },
218
+ type: 'yield:cloned' as const,
219
+ payload: { name: 'Clone', creationMethod: 'clone', parentResourceId: 'parent-1' },
220
+ userId: 'user-2',
221
+ timestamp: '',
242
222
  } as any;
243
223
  const result = getResourceCreationDetails(event);
244
224
  expect(result).toEqual({
@@ -253,20 +233,16 @@ describe('event-formatting', () => {
253
233
 
254
234
  it('uses fallback method when creationMethod missing', () => {
255
235
  const event = {
256
- event: {
257
- type: 'resource.created' as const,
258
- payload: { name: 'Doc' },
259
- userId: 'u1',
260
- timestamp: '',
261
- },
236
+ type: 'yield:created' as const,
237
+ payload: { name: 'Doc' },
238
+ userId: 'u1',
239
+ timestamp: '',
262
240
  } as any;
263
241
  expect(getResourceCreationDetails(event)?.method).toBe('unknown');
264
242
  });
265
243
 
266
244
  it('returns null for non-creation events', () => {
267
- const event = {
268
- event: { type: 'annotation.added' as const, payload: {} },
269
- } as any;
245
+ const event = { type: 'mark:added' as const, payload: {} } as any;
270
246
  expect(getResourceCreationDetails(event)).toBeNull();
271
247
  });
272
248
  });
@@ -5,7 +5,7 @@
5
5
  * No React dependencies - safe to use in any JavaScript environment.
6
6
  */
7
7
 
8
- import type { StoredEventLike, ResourceEventType } from '@semiont/core';
8
+ import type { StoredEventLike, PersistedEventType } from '@semiont/core';
9
9
  import type { components } from '@semiont/core';
10
10
  import { getExactText, getTargetSelector } from '@semiont/api-client';
11
11
  import { ANNOTATORS } from '../../lib/annotation-registry';
@@ -13,6 +13,36 @@ import { ANNOTATORS } from '../../lib/annotation-registry';
13
13
  type Annotation = components['schemas']['Annotation'];
14
14
  type TranslateFn = (key: string, params?: Record<string, string | number>) => string;
15
15
 
16
+ // =============================================================================
17
+ // USER ID DISPLAY
18
+ // =============================================================================
19
+
20
+ /**
21
+ * Format a DID or user ID for display.
22
+ *
23
+ * did:web:example.com:users:admin%40example.com → admin@example.com
24
+ * did:web:system:smelter → Smelter
25
+ * plain-string → plain-string
26
+ */
27
+ export function formatUserId(userId: string): string {
28
+ if (!userId.startsWith('did:')) return userId;
29
+
30
+ // System actors: did:web:system:smelter → Smelter
31
+ const systemMatch = userId.match(/^did:web:system:(.+)$/);
32
+ if (systemMatch) {
33
+ const name = systemMatch[1];
34
+ return name.charAt(0).toUpperCase() + name.slice(1);
35
+ }
36
+
37
+ // User DIDs: did:web:example.com:users:admin%40example.com → admin@example.com
38
+ const userMatch = userId.match(/^did:web:[^:]+:users:(.+)$/);
39
+ if (userMatch) {
40
+ return decodeURIComponent(userMatch[1]);
41
+ }
42
+
43
+ return userId;
44
+ }
45
+
16
46
  // =============================================================================
17
47
  // EVENT FORMATTING AND DISPLAY
18
48
  // =============================================================================
@@ -20,46 +50,49 @@ type TranslateFn = (key: string, params?: Record<string, string | number>) => st
20
50
  /**
21
51
  * Format event type for display with i18n support
22
52
  */
23
- export function formatEventType(type: ResourceEventType, t: TranslateFn, payload?: any): string {
53
+ export function formatEventType(type: PersistedEventType, t: TranslateFn, payload?: any): string {
24
54
  switch (type) {
25
- case 'resource.created':
55
+ case 'yield:created':
26
56
  return t('resourceCreated');
27
- case 'resource.cloned':
57
+ case 'yield:cloned':
28
58
  return t('resourceCloned');
29
- case 'resource.archived':
59
+ case 'mark:archived':
30
60
  return t('resourceArchived');
31
- case 'resource.unarchived':
61
+ case 'mark:unarchived':
32
62
  return t('resourceUnarchived');
33
63
 
34
- case 'annotation.added': {
64
+ case 'mark:added': {
35
65
  const motivation = payload?.annotation?.motivation;
36
66
  if (motivation === 'highlighting') return t('highlightAdded');
37
67
  if (motivation === 'linking') return t('referenceCreated');
38
68
  if (motivation === 'assessing') return t('assessmentAdded');
39
69
  return t('annotationAdded');
40
70
  }
41
- case 'annotation.removed': {
71
+ case 'mark:removed': {
42
72
  return t('annotationRemoved');
43
73
  }
44
- case 'annotation.body.updated': {
74
+ case 'mark:body-updated': {
45
75
  return t('annotationBodyUpdated');
46
76
  }
47
77
 
48
- case 'entitytag.added':
78
+ case 'mark:entity-tag-added':
49
79
  return t('entitytagAdded');
50
- case 'entitytag.removed':
80
+ case 'mark:entity-tag-removed':
51
81
  return t('entitytagRemoved');
52
82
 
53
- case 'job.completed':
54
- case 'job.started':
55
- case 'job.progress':
56
- case 'job.failed':
83
+ case 'job:completed':
84
+ case 'job:started':
85
+ case 'job:progress':
86
+ case 'job:failed':
57
87
  return t('jobEvent');
58
88
 
59
- case 'representation.added':
60
- case 'representation.removed':
89
+ case 'yield:representation-added':
90
+ case 'yield:representation-removed':
61
91
  return t('representationEvent');
62
92
 
93
+ case 'embedding:computed':
94
+ return t('embeddingComputed');
95
+
63
96
  default:
64
97
  return type;
65
98
  }
@@ -69,15 +102,15 @@ export function formatEventType(type: ResourceEventType, t: TranslateFn, payload
69
102
  * Get emoji for event type
70
103
  * For unified annotation events, pass the payload to determine motivation
71
104
  */
72
- export function getEventEmoji(type: ResourceEventType, payload?: any): string {
105
+ export function getEventEmoji(type: PersistedEventType, payload?: any): string {
73
106
  switch (type) {
74
- case 'resource.created':
75
- case 'resource.cloned':
76
- case 'resource.archived':
77
- case 'resource.unarchived':
107
+ case 'yield:created':
108
+ case 'yield:cloned':
109
+ case 'mark:archived':
110
+ case 'mark:unarchived':
78
111
  return '📄';
79
112
 
80
- case 'annotation.added': {
113
+ case 'mark:added': {
81
114
  const motivation = payload?.annotation?.motivation;
82
115
  // Use annotation registry as single source of truth for emojis
83
116
  if (motivation === 'highlighting') return ANNOTATORS.highlight.iconEmoji || '📝';
@@ -85,29 +118,32 @@ export function getEventEmoji(type: ResourceEventType, payload?: any): string {
85
118
  if (motivation === 'assessing') return ANNOTATORS.assessment.iconEmoji || '📝';
86
119
  return '📝';
87
120
  }
88
- case 'annotation.removed': {
121
+ case 'mark:removed': {
89
122
  return '🗑️';
90
123
  }
91
- case 'annotation.body.updated': {
124
+ case 'mark:body-updated': {
92
125
  return '✏️';
93
126
  }
94
127
 
95
- case 'entitytag.added':
96
- case 'entitytag.removed':
128
+ case 'mark:entity-tag-added':
129
+ case 'mark:entity-tag-removed':
97
130
  return '🏷️';
98
131
 
99
- case 'job.completed':
132
+ case 'job:completed':
100
133
  return '🔗'; // Link emoji for linked document creation
101
- case 'job.started':
102
- case 'job.progress':
134
+ case 'job:started':
135
+ case 'job:progress':
103
136
  return '⚙️'; // Gear for job processing
104
- case 'job.failed':
137
+ case 'job:failed':
105
138
  return '❌'; // X mark for failed jobs
106
139
 
107
- case 'representation.added':
108
- case 'representation.removed':
140
+ case 'yield:representation-added':
141
+ case 'yield:representation-removed':
109
142
  return '📄';
110
143
 
144
+ case 'embedding:computed':
145
+ return '🧮';
146
+
111
147
  default:
112
148
  return '📝';
113
149
  }
@@ -148,18 +184,18 @@ export function getEventDisplayContent(
148
184
  annotations: Annotation[], // Unified annotations array (all types)
149
185
  allEvents: StoredEventLike[]
150
186
  ): { exact: string; isQuoted: boolean; isTag: boolean } | null {
151
- const eventData = event.event;
187
+ const eventData = event;
152
188
  const payload = eventData.payload as any;
153
189
 
154
190
  // Use type discriminators for proper narrowing
155
191
  switch (eventData.type) {
156
- case 'resource.created':
157
- case 'resource.cloned': {
192
+ case 'yield:created':
193
+ case 'yield:cloned': {
158
194
  return { exact: payload.name, isQuoted: false, isTag: false };
159
195
  }
160
196
 
161
197
  // Unified annotation events
162
- case 'annotation.body.updated': {
198
+ case 'mark:body-updated': {
163
199
  // Find current annotation to get its text
164
200
  // payload.annotationId is just the UUID, but annotation.id is the full URI
165
201
  const annotation = annotations.find(a =>
@@ -180,16 +216,16 @@ export function getEventDisplayContent(
180
216
  return null;
181
217
  }
182
218
 
183
- case 'annotation.removed': {
219
+ case 'mark:removed': {
184
220
  // Find the original annotation.added event to get the text
185
221
  // payload.annotationId is just the UUID, but annotation.id in the added event is the full URI
186
222
  const addedEvent = allEvents.find(e =>
187
- e.event.type === 'annotation.added' &&
188
- (e.event.payload as any).annotation.id.endsWith(`/annotations/${payload.annotationId}`)
223
+ e.type === 'mark:added' &&
224
+ (e.payload as any).annotation.id.endsWith(`/annotations/${payload.annotationId}`)
189
225
  );
190
- if (addedEvent && addedEvent.event.type === 'annotation.added') {
226
+ if (addedEvent && addedEvent.type === 'mark:added') {
191
227
  try {
192
- const target = (addedEvent.event.payload as any).annotation.target;
228
+ const target = (addedEvent.payload as any).annotation.target;
193
229
  if (typeof target !== 'string' && target.selector) {
194
230
  const exact = getExactText(target.selector);
195
231
  if (exact) {
@@ -203,7 +239,7 @@ export function getEventDisplayContent(
203
239
  return null;
204
240
  }
205
241
 
206
- case 'annotation.added': {
242
+ case 'mark:added': {
207
243
  // New unified event structure - annotation is in payload
208
244
  try {
209
245
  const target = payload.annotation.target;
@@ -219,12 +255,12 @@ export function getEventDisplayContent(
219
255
  return null;
220
256
  }
221
257
 
222
- case 'entitytag.added':
223
- case 'entitytag.removed': {
258
+ case 'mark:entity-tag-added':
259
+ case 'mark:entity-tag-removed': {
224
260
  return { exact: payload.entityType, isQuoted: false, isTag: true };
225
261
  }
226
262
 
227
- case 'job.completed': {
263
+ case 'job:completed': {
228
264
  // Find the annotation that was used to generate the resource
229
265
  if (payload.annotationUri) {
230
266
  const annotation = annotations.find(a =>
@@ -246,11 +282,11 @@ export function getEventDisplayContent(
246
282
  return null;
247
283
  }
248
284
 
249
- case 'job.started':
250
- case 'job.progress':
251
- case 'job.failed':
252
- case 'representation.added':
253
- case 'representation.removed':
285
+ case 'job:started':
286
+ case 'job:progress':
287
+ case 'job:failed':
288
+ case 'yield:representation-added':
289
+ case 'yield:representation-removed':
254
290
  return null;
255
291
 
256
292
  default:
@@ -262,10 +298,10 @@ export function getEventDisplayContent(
262
298
  * Get entity types from event payload
263
299
  */
264
300
  export function getEventEntityTypes(event: StoredEventLike): string[] {
265
- const eventData = event.event;
301
+ const eventData = event;
266
302
  const payload = eventData.payload as any;
267
303
 
268
- if (eventData.type === 'annotation.added') {
304
+ if (eventData.type === 'mark:added') {
269
305
  const motivation = payload.annotation.motivation;
270
306
  const body = payload.annotation.body;
271
307
  if (motivation === 'linking' && body && 'entityTypes' in body) {
@@ -292,10 +328,10 @@ export interface ResourceCreationDetails {
292
328
  * Get resource creation details from event
293
329
  */
294
330
  export function getResourceCreationDetails(event: StoredEventLike): ResourceCreationDetails | null {
295
- const eventData = event.event;
331
+ const eventData = event;
296
332
  const payload = eventData.payload as any;
297
333
 
298
- if (eventData.type === 'resource.created') {
334
+ if (eventData.type === 'yield:created') {
299
335
  return {
300
336
  type: 'created',
301
337
  method: payload.creationMethod || 'unknown',
@@ -304,7 +340,7 @@ export function getResourceCreationDetails(event: StoredEventLike): ResourceCrea
304
340
  };
305
341
  }
306
342
 
307
- if (eventData.type === 'resource.cloned') {
343
+ if (eventData.type === 'yield:cloned') {
308
344
  return {
309
345
  type: 'cloned',
310
346
  method: payload.creationMethod || 'clone',
@@ -9,6 +9,7 @@ import { getAnnotationExactText, isBodyResolved, getBodySource, getFragmentSelec
9
9
  import { getEntityTypes } from '@semiont/ontology';
10
10
  import { getResourceIcon } from '../../../lib/resource-utils';
11
11
  import { useEventBus } from '../../../contexts/EventBusContext';
12
+ import { useApiClient } from '../../../contexts/ApiClientContext';
12
13
  import { useObservableExternalNavigation } from '../../../hooks/useObservableBrowse';
13
14
  import { useHoverEmitter } from '../../../hooks/useBeckonFlow';
14
15
 
@@ -41,6 +42,7 @@ export function ReferenceEntry({
41
42
  }: ReferenceEntryProps) {
42
43
  const t = useTranslations('ReferencesPanel');
43
44
  const eventBus = useEventBus();
45
+ const semiont = useApiClient();
44
46
  const navigate = useObservableExternalNavigation();
45
47
  const hoverProps = useHoverEmitter(reference.id);
46
48
 
@@ -74,11 +76,11 @@ export function ReferenceEntry({
74
76
 
75
77
  const handleUnlink = () => {
76
78
  if (source && resolvedResourceUri) {
77
- eventBus.get('bind:update-body').next({
78
- annotationId: annotationId(reference.id),
79
- resourceId: resourceId(source),
80
- operations: [{ op: 'remove', item: { type: 'SpecificResource', source: resolvedResourceUri } }],
81
- });
79
+ semiont.bind.body(
80
+ resourceId(source),
81
+ annotationId(reference.id),
82
+ [{ op: 'remove', item: { type: 'SpecificResource', source: resolvedResourceUri } }],
83
+ ).catch(() => { /* error handled by events-stream */ });
82
84
  }
83
85
  };
84
86