@semiont/react-ui 0.2.33-build.79 → 0.2.33-build.80

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 (213) hide show
  1. package/dist/EventBusContext-7GvDyO0d.d.mts +414 -0
  2. package/dist/{PdfAnnotationCanvas.client-ADC4FFSE.mjs → PdfAnnotationCanvas.client-RAJRPQLU.mjs} +42 -27
  3. package/dist/PdfAnnotationCanvas.client-RAJRPQLU.mjs.map +1 -0
  4. package/dist/{ar-EMHEHPCJ.mjs → ar-4ZEORRW2.mjs} +7 -4
  5. package/dist/ar-4ZEORRW2.mjs.map +1 -0
  6. package/dist/{bn-OVCI4F6X.mjs → bn-SEDE5BQJ.mjs} +7 -4
  7. package/dist/bn-SEDE5BQJ.mjs.map +1 -0
  8. package/dist/{chunk-LIHZTECW.mjs → chunk-D7NBW4RV.mjs} +7 -4
  9. package/dist/chunk-D7NBW4RV.mjs.map +1 -0
  10. package/dist/{chunk-JZIO2A3B.mjs → chunk-ZR4ZV2LY.mjs} +206 -146
  11. package/dist/chunk-ZR4ZV2LY.mjs.map +1 -0
  12. package/dist/{cs-FAN66Q2F.mjs → cs-7W4WF5WD.mjs} +7 -4
  13. package/dist/cs-7W4WF5WD.mjs.map +1 -0
  14. package/dist/{da-YBBIHI2O.mjs → da-75XGBCBK.mjs} +7 -4
  15. package/dist/da-75XGBCBK.mjs.map +1 -0
  16. package/dist/{de-MAYU33LB.mjs → de-ODJVFLHM.mjs} +7 -4
  17. package/dist/de-ODJVFLHM.mjs.map +1 -0
  18. package/dist/{el-MKGSWN4O.mjs → el-C4PM4WB3.mjs} +7 -4
  19. package/dist/el-C4PM4WB3.mjs.map +1 -0
  20. package/dist/{en-DDLIXJCU.mjs → en-KJCJQ4OO.mjs} +2 -2
  21. package/dist/{es-52LHUWJD.mjs → es-WD33R7QL.mjs} +7 -4
  22. package/dist/es-WD33R7QL.mjs.map +1 -0
  23. package/dist/{fa-FJICRANB.mjs → fa-2BP6V56P.mjs} +7 -4
  24. package/dist/fa-2BP6V56P.mjs.map +1 -0
  25. package/dist/{fi-O455XFCR.mjs → fi-USRRW24J.mjs} +7 -4
  26. package/dist/fi-USRRW24J.mjs.map +1 -0
  27. package/dist/{fr-TXIXHOOE.mjs → fr-EC5S6WVF.mjs} +7 -4
  28. package/dist/fr-EC5S6WVF.mjs.map +1 -0
  29. package/dist/{he-JBSOX5IN.mjs → he-7TBVIKAA.mjs} +7 -4
  30. package/dist/he-7TBVIKAA.mjs.map +1 -0
  31. package/dist/{hi-KGHI3XVT.mjs → hi-FO4VIZLA.mjs} +7 -4
  32. package/dist/hi-FO4VIZLA.mjs.map +1 -0
  33. package/dist/{id-5OCPPZLO.mjs → id-7U7GGVWY.mjs} +7 -4
  34. package/dist/id-7U7GGVWY.mjs.map +1 -0
  35. package/dist/index.css +123 -85
  36. package/dist/index.css.map +1 -1
  37. package/dist/index.d.mts +645 -471
  38. package/dist/index.mjs +3461 -3025
  39. package/dist/index.mjs.map +1 -1
  40. package/dist/{it-PNBBZSM2.mjs → it-Y4OPL6I2.mjs} +7 -4
  41. package/dist/it-Y4OPL6I2.mjs.map +1 -0
  42. package/dist/{ja-LDD7R3TJ.mjs → ja-PK7SQL55.mjs} +7 -4
  43. package/dist/ja-PK7SQL55.mjs.map +1 -0
  44. package/dist/{ko-F47ZDEY3.mjs → ko-L25PXMYD.mjs} +7 -4
  45. package/dist/ko-L25PXMYD.mjs.map +1 -0
  46. package/dist/{ms-Z7LMXJWL.mjs → ms-STH777QM.mjs} +7 -4
  47. package/dist/ms-STH777QM.mjs.map +1 -0
  48. package/dist/{nl-6SJFBPJ3.mjs → nl-Y7LECDDR.mjs} +7 -4
  49. package/dist/nl-Y7LECDDR.mjs.map +1 -0
  50. package/dist/{no-YXPBPSGF.mjs → no-KEKCEWU6.mjs} +7 -4
  51. package/dist/no-KEKCEWU6.mjs.map +1 -0
  52. package/dist/{pl-P4AZ2QME.mjs → pl-7A7OC75O.mjs} +7 -4
  53. package/dist/pl-7A7OC75O.mjs.map +1 -0
  54. package/dist/{pt-LHWUS6U6.mjs → pt-35HTM7RA.mjs} +7 -4
  55. package/dist/pt-35HTM7RA.mjs.map +1 -0
  56. package/dist/{ro-EA5J2ZON.mjs → ro-VAWL5KQA.mjs} +7 -4
  57. package/dist/ro-VAWL5KQA.mjs.map +1 -0
  58. package/dist/{sv-DATBS3UQ.mjs → sv-7ZK5EQEB.mjs} +7 -4
  59. package/dist/sv-7ZK5EQEB.mjs.map +1 -0
  60. package/dist/test-utils.d.mts +18 -8
  61. package/dist/test-utils.mjs +36 -14
  62. package/dist/test-utils.mjs.map +1 -1
  63. package/dist/{th-WTFJRWPT.mjs → th-UDWZ4X34.mjs} +7 -4
  64. package/dist/th-UDWZ4X34.mjs.map +1 -0
  65. package/dist/{tr-IKO3RXOX.mjs → tr-4WMPK3UX.mjs} +7 -4
  66. package/dist/tr-4WMPK3UX.mjs.map +1 -0
  67. package/dist/{uk-CF6CTTRK.mjs → uk-SSLASQYJ.mjs} +7 -4
  68. package/dist/uk-SSLASQYJ.mjs.map +1 -0
  69. package/dist/{vi-AJLTXPZQ.mjs → vi-IF42Z5PU.mjs} +7 -4
  70. package/dist/vi-IF42Z5PU.mjs.map +1 -0
  71. package/dist/{zh-U3ORHHYH.mjs → zh-HRQTNTAI.mjs} +7 -4
  72. package/dist/zh-HRQTNTAI.mjs.map +1 -0
  73. package/package.json +3 -1
  74. package/src/components/CodeMirrorRenderer.tsx +66 -93
  75. package/src/components/DetectionProgressWidget.tsx +16 -5
  76. package/src/components/LiveRegion.tsx +18 -18
  77. package/src/components/ResizeHandle.tsx +10 -4
  78. package/src/components/SessionTimer.tsx +2 -2
  79. package/src/components/Toolbar.tsx +18 -9
  80. package/src/components/__tests__/SessionTimer.test.tsx +9 -9
  81. package/src/components/annotation/AnnotateToolbar.tsx +17 -15
  82. package/src/components/annotation/__tests__/AnnotateToolbar.test.tsx +165 -63
  83. package/src/components/annotation/annotation-entries.css +10 -0
  84. package/src/components/annotation-popups/JsonLdView.tsx +8 -2
  85. package/src/components/image-annotation/AnnotationOverlay.tsx +42 -22
  86. package/src/components/image-annotation/SvgDrawingCanvas.tsx +27 -30
  87. package/src/components/layout/__tests__/LeftSidebar.test.tsx +12 -33
  88. package/src/components/layout/__tests__/PageLayout.test.tsx +37 -32
  89. package/src/components/layout/__tests__/UnifiedHeader.test.tsx +21 -40
  90. package/src/components/modals/ResourceSearchModal.tsx +2 -2
  91. package/src/components/modals/SearchModal.tsx +1 -1
  92. package/src/components/navigation/CollapsibleResourceNavigation.tsx +14 -9
  93. package/src/components/navigation/NavigationTabs.css +36 -24
  94. package/src/components/navigation/ObservableLink.tsx +91 -0
  95. package/src/components/navigation/SimpleNavigation.tsx +20 -16
  96. package/src/components/navigation/SortableResourceTab.tsx +11 -5
  97. package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +51 -26
  98. package/src/components/pdf-annotation/__tests__/PdfAnnotationCanvas.test.tsx +28 -22
  99. package/src/components/resource/AnnotateView.tsx +64 -134
  100. package/src/components/resource/BrowseView.tsx +86 -166
  101. package/src/components/resource/HistoryEvent.tsx +13 -7
  102. package/src/components/resource/ResourceViewer.tsx +122 -264
  103. package/src/components/resource/__tests__/BrowseView.test.tsx +631 -0
  104. package/src/components/resource/__tests__/ResourceViewer.mode-switch.test.tsx +231 -0
  105. package/src/components/resource/panels/AssessmentEntry.tsx +25 -33
  106. package/src/components/resource/panels/AssessmentPanel.tsx +106 -28
  107. package/src/components/resource/panels/CommentEntry.tsx +38 -32
  108. package/src/components/resource/panels/CommentsPanel.tsx +121 -28
  109. package/src/components/resource/panels/DetectSection.css +36 -1
  110. package/src/components/resource/panels/DetectSection.tsx +38 -10
  111. package/src/components/resource/panels/HighlightEntry.tsx +25 -33
  112. package/src/components/resource/panels/HighlightPanel.tsx +100 -25
  113. package/src/components/resource/panels/ReferenceEntry.tsx +61 -75
  114. package/src/components/resource/panels/ReferencesPanel.tsx +134 -42
  115. package/src/components/resource/panels/ResourceInfoPanel.tsx +47 -48
  116. package/src/components/resource/panels/TagEntry.tsx +25 -33
  117. package/src/components/resource/panels/TaggingPanel.tsx +119 -30
  118. package/src/components/resource/panels/UnifiedAnnotationsPanel.tsx +30 -92
  119. package/src/components/resource/panels/__tests__/AssessmentPanel.test.tsx +129 -110
  120. package/src/components/resource/panels/__tests__/CommentEntry.test.tsx +86 -78
  121. package/src/components/resource/panels/__tests__/CommentsPanel.test.tsx +144 -149
  122. package/src/components/resource/panels/__tests__/DetectSection.test.tsx +480 -0
  123. package/src/components/resource/panels/__tests__/HighlightPanel.detectionProgress.test.tsx +362 -0
  124. package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +226 -111
  125. package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +117 -61
  126. package/src/components/resource/panels/__tests__/TaggingPanel.test.tsx +128 -106
  127. package/src/components/settings/SettingsPanel.tsx +15 -12
  128. package/src/features/admin-devops/__tests__/AdminDevOpsPage.test.tsx +1 -46
  129. package/src/features/admin-devops/components/AdminDevOpsPage.tsx +0 -9
  130. package/src/features/admin-security/__tests__/AdminSecurityPage.test.tsx +0 -3
  131. package/src/features/admin-security/components/AdminSecurityPage.tsx +0 -9
  132. package/src/features/admin-users/__tests__/AdminUsersPage.test.tsx +0 -3
  133. package/src/features/admin-users/components/AdminUsersPage.tsx +0 -9
  134. package/src/features/moderate-entity-tags/__tests__/EntityTagsPage.test.tsx +0 -3
  135. package/src/features/moderate-entity-tags/components/EntityTagsPage.tsx +1 -9
  136. package/src/features/moderate-recent/__tests__/RecentDocumentsPage.test.tsx +0 -32
  137. package/src/features/moderate-recent/components/RecentDocumentsPage.tsx +1 -9
  138. package/src/features/moderate-tag-schemas/__tests__/TagSchemasPage.test.tsx +0 -32
  139. package/src/features/moderate-tag-schemas/components/TagSchemasPage.tsx +1 -9
  140. package/src/features/resource-compose/__tests__/ResourceComposePage.test.tsx +51 -54
  141. package/src/features/resource-compose/components/ResourceComposePage.tsx +3 -13
  142. package/src/features/resource-discovery/__tests__/ResourceDiscoveryPage.test.tsx +39 -45
  143. package/src/features/resource-discovery/components/ResourceDiscoveryPage.tsx +9 -13
  144. package/src/features/resource-viewer/__tests__/AnnotationDeletionIntegration.test.tsx +231 -0
  145. package/src/features/resource-viewer/__tests__/DetectionFlowBug.test.tsx +234 -0
  146. package/src/features/resource-viewer/__tests__/DetectionFlowIntegration.test.tsx +388 -0
  147. package/src/features/resource-viewer/__tests__/DetectionProgressDismissal.test.tsx +318 -0
  148. package/src/features/resource-viewer/__tests__/GenerationFlowIntegration.test.tsx +504 -0
  149. package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +135 -88
  150. package/src/features/resource-viewer/__tests__/detection-progress-flow.test.tsx +322 -0
  151. package/src/features/resource-viewer/components/ResourceViewerPage.tsx +308 -528
  152. package/translations/ar.json +6 -3
  153. package/translations/bn.json +6 -3
  154. package/translations/cs.json +6 -3
  155. package/translations/da.json +6 -3
  156. package/translations/de.json +6 -3
  157. package/translations/el.json +6 -3
  158. package/translations/en.json +6 -3
  159. package/translations/es.json +6 -3
  160. package/translations/fa.json +6 -3
  161. package/translations/fi.json +6 -3
  162. package/translations/fr.json +6 -3
  163. package/translations/he.json +6 -3
  164. package/translations/hi.json +6 -3
  165. package/translations/id.json +6 -3
  166. package/translations/it.json +6 -3
  167. package/translations/ja.json +6 -3
  168. package/translations/ko.json +6 -3
  169. package/translations/ms.json +6 -3
  170. package/translations/nl.json +6 -3
  171. package/translations/no.json +6 -3
  172. package/translations/pl.json +6 -3
  173. package/translations/pt.json +6 -3
  174. package/translations/ro.json +6 -3
  175. package/translations/sv.json +6 -3
  176. package/translations/th.json +6 -3
  177. package/translations/tr.json +6 -3
  178. package/translations/uk.json +6 -3
  179. package/translations/vi.json +6 -3
  180. package/translations/zh.json +6 -3
  181. package/dist/PdfAnnotationCanvas.client-ADC4FFSE.mjs.map +0 -1
  182. package/dist/TranslationManager-Co_5fSxl.d.mts +0 -118
  183. package/dist/ar-EMHEHPCJ.mjs.map +0 -1
  184. package/dist/bn-OVCI4F6X.mjs.map +0 -1
  185. package/dist/chunk-JZIO2A3B.mjs.map +0 -1
  186. package/dist/chunk-LIHZTECW.mjs.map +0 -1
  187. package/dist/cs-FAN66Q2F.mjs.map +0 -1
  188. package/dist/da-YBBIHI2O.mjs.map +0 -1
  189. package/dist/de-MAYU33LB.mjs.map +0 -1
  190. package/dist/el-MKGSWN4O.mjs.map +0 -1
  191. package/dist/es-52LHUWJD.mjs.map +0 -1
  192. package/dist/fa-FJICRANB.mjs.map +0 -1
  193. package/dist/fi-O455XFCR.mjs.map +0 -1
  194. package/dist/fr-TXIXHOOE.mjs.map +0 -1
  195. package/dist/he-JBSOX5IN.mjs.map +0 -1
  196. package/dist/hi-KGHI3XVT.mjs.map +0 -1
  197. package/dist/id-5OCPPZLO.mjs.map +0 -1
  198. package/dist/it-PNBBZSM2.mjs.map +0 -1
  199. package/dist/ja-LDD7R3TJ.mjs.map +0 -1
  200. package/dist/ko-F47ZDEY3.mjs.map +0 -1
  201. package/dist/ms-Z7LMXJWL.mjs.map +0 -1
  202. package/dist/nl-6SJFBPJ3.mjs.map +0 -1
  203. package/dist/no-YXPBPSGF.mjs.map +0 -1
  204. package/dist/pl-P4AZ2QME.mjs.map +0 -1
  205. package/dist/pt-LHWUS6U6.mjs.map +0 -1
  206. package/dist/ro-EA5J2ZON.mjs.map +0 -1
  207. package/dist/sv-DATBS3UQ.mjs.map +0 -1
  208. package/dist/th-WTFJRWPT.mjs.map +0 -1
  209. package/dist/tr-IKO3RXOX.mjs.map +0 -1
  210. package/dist/uk-CF6CTTRK.mjs.map +0 -1
  211. package/dist/vi-AJLTXPZQ.mjs.map +0 -1
  212. package/dist/zh-U3ORHHYH.mjs.map +0 -1
  213. /package/dist/{en-DDLIXJCU.mjs.map → en-KJCJQ4OO.mjs.map} +0 -0
@@ -1,8 +1,9 @@
1
- import { describe, it, expect, vi } from 'vitest';
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
2
  import React from 'react';
3
- import { render, screen, fireEvent } from '@testing-library/react';
3
+ import { render, screen, fireEvent, waitFor } from '@testing-library/react';
4
4
  import '@testing-library/jest-dom';
5
5
  import { ResourceInfoPanel } from '../ResourceInfoPanel';
6
+ import { EventBusProvider, resetEventBusForTesting, useEventBus } from '../../../../contexts/EventBusContext';
6
7
 
7
8
  // Mock TranslationContext
8
9
  vi.mock('../../../../contexts/TranslationContext', () => ({
@@ -23,6 +24,7 @@ vi.mock('../../../../contexts/TranslationContext', () => ({
23
24
  };
24
25
  return translations[key] || key;
25
26
  }),
27
+ TranslationProvider: ({ children }: { children: React.ReactNode }) => children,
26
28
  }));
27
29
 
28
30
  // Mock @semiont/api-client utilities
@@ -43,6 +45,74 @@ vi.mock('@/lib/button-styles', () => ({
43
45
  },
44
46
  }));
45
47
 
48
+ // Composition-based event tracker
49
+ interface TrackedEvent {
50
+ event: string;
51
+ payload: any;
52
+ }
53
+
54
+ function createEventTracker() {
55
+ const events: TrackedEvent[] = [];
56
+
57
+ function EventTrackingWrapper({ children }: { children: React.ReactNode }) {
58
+ const eventBus = useEventBus();
59
+
60
+ React.useEffect(() => {
61
+ const handlers: Array<() => void> = [];
62
+
63
+ // Track resource-related events
64
+ const trackEvent = (eventName: string) => (payload: any) => {
65
+ events.push({ event: eventName, payload });
66
+ };
67
+
68
+ const resourceEvents = [
69
+ 'resource:clone',
70
+ 'resource:archive',
71
+ 'resource:unarchive',
72
+ ];
73
+
74
+ resourceEvents.forEach(eventName => {
75
+ const handler = trackEvent(eventName);
76
+ eventBus.on(eventName, handler);
77
+ handlers.push(() => eventBus.off(eventName, handler));
78
+ });
79
+
80
+ return () => {
81
+ handlers.forEach(cleanup => cleanup());
82
+ };
83
+ }, [eventBus]);
84
+
85
+ return <>{children}</>;
86
+ }
87
+
88
+ return {
89
+ EventTrackingWrapper,
90
+ events,
91
+ clear: () => {
92
+ events.length = 0;
93
+ },
94
+ };
95
+ }
96
+
97
+ // Helper to render with EventBusProvider
98
+ const renderWithEventBus = (component: React.ReactElement, tracker?: ReturnType<typeof createEventTracker>) => {
99
+ if (tracker) {
100
+ return render(
101
+ <EventBusProvider>
102
+ <tracker.EventTrackingWrapper>
103
+ {component}
104
+ </tracker.EventTrackingWrapper>
105
+ </EventBusProvider>
106
+ );
107
+ }
108
+
109
+ return render(
110
+ <EventBusProvider>
111
+ {component}
112
+ </EventBusProvider>
113
+ );
114
+ };
115
+
46
116
  describe('ResourceInfoPanel Component', () => {
47
117
  const defaultProps = {
48
118
  documentEntityTypes: [],
@@ -51,25 +121,30 @@ describe('ResourceInfoPanel Component', () => {
51
121
  primaryByteSize: undefined,
52
122
  };
53
123
 
124
+ beforeEach(() => {
125
+ resetEventBusForTesting();
126
+ vi.clearAllMocks();
127
+ });
128
+
54
129
  describe('Rendering', () => {
55
130
  it('should render locale section', () => {
56
- render(<ResourceInfoPanel {...defaultProps} />);
131
+ renderWithEventBus(<ResourceInfoPanel {...defaultProps} />);
57
132
  expect(screen.getByText('Locale')).toBeInTheDocument();
58
133
  });
59
134
 
60
135
  it('should render locale when provided', () => {
61
- render(<ResourceInfoPanel {...defaultProps} documentLocale="en-US" />);
136
+ renderWithEventBus(<ResourceInfoPanel {...defaultProps} documentLocale="en-US" />);
62
137
  // formatLocaleDisplay is mocked to return "Language: {locale}"
63
138
  expect(screen.getByText('Language: en-US')).toBeInTheDocument();
64
139
  });
65
140
 
66
141
  it('should show "not specified" when locale is undefined', () => {
67
- render(<ResourceInfoPanel {...defaultProps} documentLocale={undefined} />);
142
+ renderWithEventBus(<ResourceInfoPanel {...defaultProps} documentLocale={undefined} />);
68
143
  expect(screen.getByText('Not specified')).toBeInTheDocument();
69
144
  });
70
145
 
71
146
  it('should render entity type tags when provided', () => {
72
- render(
147
+ renderWithEventBus(
73
148
  <ResourceInfoPanel
74
149
  {...defaultProps}
75
150
  documentEntityTypes={['Person', 'Organization', 'Location']}
@@ -83,12 +158,12 @@ describe('ResourceInfoPanel Component', () => {
83
158
  });
84
159
 
85
160
  it('should not render entity type tags section when empty', () => {
86
- render(<ResourceInfoPanel {...defaultProps} documentEntityTypes={[]} />);
161
+ renderWithEventBus(<ResourceInfoPanel {...defaultProps} documentEntityTypes={[]} />);
87
162
  expect(screen.queryByText('Entity Type Tags')).not.toBeInTheDocument();
88
163
  });
89
164
 
90
165
  it('should render representation section when media type provided', () => {
91
- render(
166
+ renderWithEventBus(
92
167
  <ResourceInfoPanel
93
168
  {...defaultProps}
94
169
  primaryMediaType="text/markdown"
@@ -101,7 +176,7 @@ describe('ResourceInfoPanel Component', () => {
101
176
  });
102
177
 
103
178
  it('should render byte size when provided', () => {
104
- render(
179
+ renderWithEventBus(
105
180
  <ResourceInfoPanel
106
181
  {...defaultProps}
107
182
  primaryByteSize={1024}
@@ -114,7 +189,7 @@ describe('ResourceInfoPanel Component', () => {
114
189
  });
115
190
 
116
191
  it('should not render representation section when neither media type nor byte size provided', () => {
117
- render(
192
+ renderWithEventBus(
118
193
  <ResourceInfoPanel
119
194
  {...defaultProps}
120
195
  primaryMediaType={undefined}
@@ -128,12 +203,12 @@ describe('ResourceInfoPanel Component', () => {
128
203
 
129
204
  describe('Styling and Appearance', () => {
130
205
  it('should have proper panel structure', () => {
131
- const { container } = render(<ResourceInfoPanel {...defaultProps} />);
206
+ const { container } = renderWithEventBus(<ResourceInfoPanel {...defaultProps} />);
132
207
  expect(container.querySelector('.semiont-resource-info-panel')).toBeInTheDocument();
133
208
  });
134
209
 
135
210
  it('should style entity type tags appropriately', () => {
136
- render(
211
+ renderWithEventBus(
137
212
  <ResourceInfoPanel
138
213
  {...defaultProps}
139
214
  documentEntityTypes={['TestType']}
@@ -148,7 +223,7 @@ describe('ResourceInfoPanel Component', () => {
148
223
 
149
224
  describe('Accessibility', () => {
150
225
  it('should have semantic heading structure', () => {
151
- render(
226
+ renderWithEventBus(
152
227
  <ResourceInfoPanel
153
228
  {...defaultProps}
154
229
  documentLocale="en-US"
@@ -162,12 +237,10 @@ describe('ResourceInfoPanel Component', () => {
162
237
  });
163
238
 
164
239
  describe('Clone Action', () => {
165
- it('should render clone button when handler provided', () => {
166
- const onClone = vi.fn();
167
- render(
240
+ it('should render clone button', () => {
241
+ renderWithEventBus(
168
242
  <ResourceInfoPanel
169
243
  {...defaultProps}
170
- onClone={onClone}
171
244
  />
172
245
  );
173
246
 
@@ -175,39 +248,30 @@ describe('ResourceInfoPanel Component', () => {
175
248
  expect(screen.getByText('Generate a shareable clone link for this resource')).toBeInTheDocument();
176
249
  });
177
250
 
178
- it('should call onClone when clone button clicked', () => {
179
- const onClone = vi.fn();
180
- render(
251
+ it('should emit resource:clone event when clone button clicked', async () => {
252
+ const tracker = createEventTracker();
253
+ renderWithEventBus(
181
254
  <ResourceInfoPanel
182
255
  {...defaultProps}
183
- onClone={onClone}
184
- />
256
+ />,
257
+ tracker
185
258
  );
186
259
 
187
260
  const button = screen.getByRole('button', { name: /Clone/i });
188
261
  fireEvent.click(button);
189
- expect(onClone).toHaveBeenCalledTimes(1);
190
- });
191
-
192
- it('should not render clone button when handler not provided', () => {
193
- render(
194
- <ResourceInfoPanel
195
- {...defaultProps}
196
- />
197
- );
198
262
 
199
- expect(screen.queryByText('Clone')).not.toBeInTheDocument();
263
+ await waitFor(() => {
264
+ expect(tracker.events.some(e => e.event === 'resource:clone')).toBe(true);
265
+ });
200
266
  });
201
267
  });
202
268
 
203
269
  describe('Archive Actions', () => {
204
270
  it('should render archive button when not archived', () => {
205
- const onArchive = vi.fn();
206
- render(
271
+ renderWithEventBus(
207
272
  <ResourceInfoPanel
208
273
  {...defaultProps}
209
274
  isArchived={false}
210
- onArchive={onArchive}
211
275
  />
212
276
  );
213
277
 
@@ -216,12 +280,10 @@ describe('ResourceInfoPanel Component', () => {
216
280
  });
217
281
 
218
282
  it('should render unarchive button when archived', () => {
219
- const onUnarchive = vi.fn();
220
- render(
283
+ renderWithEventBus(
221
284
  <ResourceInfoPanel
222
285
  {...defaultProps}
223
286
  isArchived={true}
224
- onUnarchive={onUnarchive}
225
287
  />
226
288
  );
227
289
 
@@ -229,46 +291,40 @@ describe('ResourceInfoPanel Component', () => {
229
291
  expect(screen.getByText('Restore this resource to active status')).toBeInTheDocument();
230
292
  });
231
293
 
232
- it('should call onArchive when archive button clicked', () => {
233
- const onArchive = vi.fn();
234
- render(
294
+ it('should emit resource:archive event when archive button clicked', async () => {
295
+ const tracker = createEventTracker();
296
+ renderWithEventBus(
235
297
  <ResourceInfoPanel
236
298
  {...defaultProps}
237
299
  isArchived={false}
238
- onArchive={onArchive}
239
- />
300
+ />,
301
+ tracker
240
302
  );
241
303
 
242
304
  const button = screen.getByRole('button', { name: /Archive/i });
243
305
  fireEvent.click(button);
244
- expect(onArchive).toHaveBeenCalledTimes(1);
306
+
307
+ await waitFor(() => {
308
+ expect(tracker.events.some(e => e.event === 'resource:archive')).toBe(true);
309
+ });
245
310
  });
246
311
 
247
- it('should call onUnarchive when unarchive button clicked', () => {
248
- const onUnarchive = vi.fn();
249
- render(
312
+ it('should emit resource:unarchive event when unarchive button clicked', async () => {
313
+ const tracker = createEventTracker();
314
+ renderWithEventBus(
250
315
  <ResourceInfoPanel
251
316
  {...defaultProps}
252
317
  isArchived={true}
253
- onUnarchive={onUnarchive}
254
- />
318
+ />,
319
+ tracker
255
320
  );
256
321
 
257
322
  const button = screen.getByRole('button', { name: /Unarchive/i });
258
323
  fireEvent.click(button);
259
- expect(onUnarchive).toHaveBeenCalledTimes(1);
260
- });
261
-
262
- it('should not render archive buttons when handlers not provided', () => {
263
- render(
264
- <ResourceInfoPanel
265
- {...defaultProps}
266
- isArchived={false}
267
- />
268
- );
269
324
 
270
- expect(screen.queryByText('Archive')).not.toBeInTheDocument();
271
- expect(screen.queryByText('Unarchive')).not.toBeInTheDocument();
325
+ await waitFor(() => {
326
+ expect(tracker.events.some(e => e.event === 'resource:unarchive')).toBe(true);
327
+ });
272
328
  });
273
329
  });
274
330
  });