@semiont/react-ui 0.4.7 → 0.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{PdfAnnotationCanvas.client-LF6DDTCV.mjs → PdfAnnotationCanvas.client-CW6SKH2U.mjs} +7 -25
- package/dist/PdfAnnotationCanvas.client-CW6SKH2U.mjs.map +1 -0
- package/dist/{EventBusContext-DUIMowqQ.d.mts → TranslationManager-CudgH3gw.d.mts} +1 -74
- package/dist/{ar-3URRW77J.mjs → ar-R4CRNXEF.mjs} +3 -2
- package/dist/ar-R4CRNXEF.mjs.map +1 -0
- package/dist/{bn-DCQD3XZ5.mjs → bn-CZKGRHTA.mjs} +3 -2
- package/dist/bn-CZKGRHTA.mjs.map +1 -0
- package/dist/{chunk-XMCUHQ2Y.mjs → chunk-BQJWOK4C.mjs} +15 -34
- package/dist/chunk-BQJWOK4C.mjs.map +1 -0
- package/dist/{chunk-5JZFKRLW.mjs → chunk-HNZOXH4L.mjs} +33 -35
- package/dist/chunk-HNZOXH4L.mjs.map +1 -0
- package/dist/{chunk-PWIVZQ4X.mjs → chunk-HVMAGUFA.mjs} +3 -2
- package/dist/chunk-HVMAGUFA.mjs.map +1 -0
- package/dist/{chunk-4RMWYJUJ.mjs → chunk-OL5UST25.mjs} +31 -31
- package/dist/{cs-23KOZUFE.mjs → cs-4WIB2IHH.mjs} +3 -2
- package/dist/cs-4WIB2IHH.mjs.map +1 -0
- package/dist/{da-OIQ66A42.mjs → da-JWYEUYPX.mjs} +3 -2
- package/dist/da-JWYEUYPX.mjs.map +1 -0
- package/dist/{de-FCCLKE2X.mjs → de-GWUQZGER.mjs} +3 -2
- package/dist/de-GWUQZGER.mjs.map +1 -0
- package/dist/{el-3ADITCGI.mjs → el-DM2GT7P5.mjs} +3 -2
- package/dist/el-DM2GT7P5.mjs.map +1 -0
- package/dist/{en-LNW2A3RA.mjs → en-IUV4ZXKH.mjs} +2 -2
- package/dist/{es-POQEEYIW.mjs → es-6LVQIM3D.mjs} +3 -2
- package/dist/es-6LVQIM3D.mjs.map +1 -0
- package/dist/{fa-RQPXVELG.mjs → fa-IRUJY3QI.mjs} +3 -2
- package/dist/fa-IRUJY3QI.mjs.map +1 -0
- package/dist/{fi-UXOVOUGT.mjs → fi-53FBOEVT.mjs} +3 -2
- package/dist/fi-53FBOEVT.mjs.map +1 -0
- package/dist/{fr-6W2T3R7G.mjs → fr-Q5KY7QL6.mjs} +3 -2
- package/dist/fr-Q5KY7QL6.mjs.map +1 -0
- package/dist/{he-65UHPZIU.mjs → he-HJNKULBY.mjs} +3 -2
- package/dist/he-HJNKULBY.mjs.map +1 -0
- package/dist/{hi-SGJIVPTN.mjs → hi-UYZ4X6CR.mjs} +3 -2
- package/dist/hi-UYZ4X6CR.mjs.map +1 -0
- package/dist/{id-EYJJQCS2.mjs → id-UAQMH6U2.mjs} +3 -2
- package/dist/id-UAQMH6U2.mjs.map +1 -0
- package/dist/index.css +48 -0
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +176 -125
- package/dist/index.mjs +556 -781
- package/dist/index.mjs.map +1 -1
- package/dist/{it-IZGQEDO7.mjs → it-C7QEBNFA.mjs} +3 -2
- package/dist/it-C7QEBNFA.mjs.map +1 -0
- package/dist/{ja-SR272JSY.mjs → ja-THS6AOSJ.mjs} +3 -2
- package/dist/ja-THS6AOSJ.mjs.map +1 -0
- package/dist/{ko-YWTXVVXE.mjs → ko-XKK3TWQG.mjs} +3 -2
- package/dist/ko-XKK3TWQG.mjs.map +1 -0
- package/dist/{ms-3K2XSJGM.mjs → ms-GSK7LIF7.mjs} +3 -2
- package/dist/ms-GSK7LIF7.mjs.map +1 -0
- package/dist/{nl-YIGP4SLE.mjs → nl-KUBWITGY.mjs} +3 -2
- package/dist/nl-KUBWITGY.mjs.map +1 -0
- package/dist/{no-IFYIL3ND.mjs → no-ECWZUHT6.mjs} +3 -2
- package/dist/no-ECWZUHT6.mjs.map +1 -0
- package/dist/{pl-6MWSASJR.mjs → pl-PLVWSZWS.mjs} +3 -2
- package/dist/pl-PLVWSZWS.mjs.map +1 -0
- package/dist/{pt-NZNN6WUN.mjs → pt-AL74ZTKB.mjs} +3 -2
- package/dist/pt-AL74ZTKB.mjs.map +1 -0
- package/dist/{ro-NF3SMUJS.mjs → ro-WTPHLHGS.mjs} +3 -2
- package/dist/ro-WTPHLHGS.mjs.map +1 -0
- package/dist/{sv-ZHM7GSTD.mjs → sv-QCLI7SG4.mjs} +3 -2
- package/dist/sv-QCLI7SG4.mjs.map +1 -0
- package/dist/test-utils.d.mts +1 -4
- package/dist/test-utils.mjs +4 -6
- package/dist/test-utils.mjs.map +1 -1
- package/dist/{th-LX4NO5BJ.mjs → th-WCKVZU6U.mjs} +3 -2
- package/dist/th-WCKVZU6U.mjs.map +1 -0
- package/dist/{tr-DZ4GDSRR.mjs → tr-2CAFS2XS.mjs} +3 -2
- package/dist/tr-2CAFS2XS.mjs.map +1 -0
- package/dist/{uk-KC5KVVBY.mjs → uk-TDE4JLCY.mjs} +3 -2
- package/dist/uk-TDE4JLCY.mjs.map +1 -0
- package/dist/{vi-KNCR3OXZ.mjs → vi-KKXZ4PCX.mjs} +3 -2
- package/dist/vi-KKXZ4PCX.mjs.map +1 -0
- package/dist/{zh-M2HV2A27.mjs → zh-VH4XN5PV.mjs} +3 -2
- package/dist/zh-VH4XN5PV.mjs.map +1 -0
- package/package.json +1 -1
- package/src/components/Toolbar.tsx +15 -0
- package/src/components/__tests__/AnnotateReferencesProgressWidget.test.tsx +2 -6
- package/src/components/__tests__/Toolbar.test.tsx +2 -6
- package/src/components/annotation/__tests__/AnnotateToolbar.test.tsx +1 -2
- package/src/components/image-annotation/SvgDrawingCanvas.tsx +4 -7
- package/src/components/modals/ConfigureGenerationStep.tsx +54 -60
- package/src/components/modals/ReferenceWizardModal.tsx +3 -3
- package/src/components/navigation/__tests__/ObservableLink.test.tsx +2 -6
- package/src/components/navigation/__tests__/SimpleNavigation.test.tsx +2 -6
- package/src/components/pdf-annotation/PdfAnnotationCanvas.tsx +3 -9
- package/src/components/resource/AnnotateView.tsx +4 -5
- package/src/components/resource/AnnotationHistory.tsx +2 -5
- package/src/components/resource/BrowseView.tsx +2 -3
- package/src/components/resource/HistoryEvent.tsx +3 -3
- package/src/components/resource/__tests__/BrowseView.test.tsx +1 -2
- package/src/components/resource/__tests__/ResourceViewer.mode-switch.test.tsx +8 -8
- package/src/components/resource/event-formatting.ts +22 -19
- package/src/components/resource/panels/__tests__/AssessmentEntry.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/AssessmentPanel.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/AssistSection.test.tsx +0 -2
- package/src/components/resource/panels/__tests__/CommentEntry.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/CommentsPanel.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/HighlightEntry.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/HighlightPanel.annotationProgress.test.tsx +0 -2
- package/src/components/resource/panels/__tests__/ReferenceEntry.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/ReferencesPanel.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/ResourceInfoPanel.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/TagEntry.test.tsx +1 -2
- package/src/components/resource/panels/__tests__/TaggingPanel.test.tsx +1 -2
- package/src/components/settings/__tests__/SettingsPanel.test.tsx +1 -2
- package/src/components/viewers/ImageViewer.tsx +2 -8
- package/src/components/viewers/__tests__/ImageViewer.test.tsx +3 -16
- package/src/features/auth/__tests__/SignInForm.a11y.test.tsx +8 -0
- package/src/features/auth/auth.css +62 -0
- package/src/features/auth/components/SignInForm.tsx +139 -29
- package/src/features/resource-compose/__tests__/ResourceComposePage.test.tsx +2 -6
- package/src/features/resource-discovery/__tests__/ResourceDiscoveryPage.test.tsx +1 -2
- package/src/features/resource-viewer/__tests__/AnnotationCreationPending.test.tsx +1 -2
- package/src/features/resource-viewer/__tests__/AnnotationDeletionIntegration.test.tsx +1 -2
- package/src/features/resource-viewer/__tests__/AnnotationProgressDismissal.test.tsx +1 -2
- package/src/features/resource-viewer/__tests__/BindFlowIntegration.test.tsx +1 -2
- package/src/features/resource-viewer/__tests__/DetectionFlowBug.test.tsx +1 -2
- package/src/features/resource-viewer/__tests__/DetectionFlowIntegration.test.tsx +1 -2
- package/src/features/resource-viewer/__tests__/ResourceMutations.test.tsx +9 -10
- package/src/features/resource-viewer/__tests__/ResourceViewerPage.test.tsx +9 -6
- package/src/features/resource-viewer/__tests__/ToastNotifications.test.tsx +2 -12
- package/src/features/resource-viewer/__tests__/YieldFlowIntegration.test.tsx +1 -2
- package/src/features/resource-viewer/__tests__/annotation-progress-flow.test.tsx +16 -6
- package/src/features/resource-viewer/components/ResourceViewerPage.tsx +45 -75
- package/src/styles/core/forms.css +32 -0
- package/src/styles/core/sliders.css +5 -0
- package/translations/ar.json +3 -2
- package/translations/bn.json +3 -2
- package/translations/cs.json +3 -2
- package/translations/da.json +3 -2
- package/translations/de.json +3 -2
- package/translations/el.json +3 -2
- package/translations/en.json +4 -3
- package/translations/es.json +3 -2
- package/translations/fa.json +3 -2
- package/translations/fi.json +3 -2
- package/translations/fr.json +3 -2
- package/translations/he.json +3 -2
- package/translations/hi.json +3 -2
- package/translations/id.json +3 -2
- package/translations/it.json +3 -2
- package/translations/ja.json +3 -2
- package/translations/ko.json +3 -2
- package/translations/ms.json +3 -2
- package/translations/nl.json +3 -2
- package/translations/no.json +3 -2
- package/translations/pl.json +3 -2
- package/translations/pt.json +3 -2
- package/translations/ro.json +3 -2
- package/translations/sv.json +3 -2
- package/translations/th.json +3 -2
- package/translations/tr.json +3 -2
- package/translations/uk.json +3 -2
- package/translations/vi.json +3 -2
- package/translations/zh.json +3 -2
- package/dist/PdfAnnotationCanvas.client-LF6DDTCV.mjs.map +0 -1
- package/dist/ar-3URRW77J.mjs.map +0 -1
- package/dist/bn-DCQD3XZ5.mjs.map +0 -1
- package/dist/chunk-5JZFKRLW.mjs.map +0 -1
- package/dist/chunk-PWIVZQ4X.mjs.map +0 -1
- package/dist/chunk-XMCUHQ2Y.mjs.map +0 -1
- package/dist/cs-23KOZUFE.mjs.map +0 -1
- package/dist/da-OIQ66A42.mjs.map +0 -1
- package/dist/de-FCCLKE2X.mjs.map +0 -1
- package/dist/el-3ADITCGI.mjs.map +0 -1
- package/dist/es-POQEEYIW.mjs.map +0 -1
- package/dist/fa-RQPXVELG.mjs.map +0 -1
- package/dist/fi-UXOVOUGT.mjs.map +0 -1
- package/dist/fr-6W2T3R7G.mjs.map +0 -1
- package/dist/he-65UHPZIU.mjs.map +0 -1
- package/dist/hi-SGJIVPTN.mjs.map +0 -1
- package/dist/id-EYJJQCS2.mjs.map +0 -1
- package/dist/it-IZGQEDO7.mjs.map +0 -1
- package/dist/ja-SR272JSY.mjs.map +0 -1
- package/dist/ko-YWTXVVXE.mjs.map +0 -1
- package/dist/ms-3K2XSJGM.mjs.map +0 -1
- package/dist/nl-YIGP4SLE.mjs.map +0 -1
- package/dist/no-IFYIL3ND.mjs.map +0 -1
- package/dist/pl-6MWSASJR.mjs.map +0 -1
- package/dist/pt-NZNN6WUN.mjs.map +0 -1
- package/dist/ro-NF3SMUJS.mjs.map +0 -1
- package/dist/sv-ZHM7GSTD.mjs.map +0 -1
- package/dist/th-LX4NO5BJ.mjs.map +0 -1
- package/dist/tr-DZ4GDSRR.mjs.map +0 -1
- package/dist/uk-KC5KVVBY.mjs.map +0 -1
- package/dist/vi-KNCR3OXZ.mjs.map +0 -1
- package/dist/zh-M2HV2A27.mjs.map +0 -1
- /package/dist/{chunk-4RMWYJUJ.mjs.map → chunk-OL5UST25.mjs.map} +0 -0
- /package/dist/{en-LNW2A3RA.mjs.map → en-IUV4ZXKH.mjs.map} +0 -0
|
@@ -70,7 +70,7 @@ export function ConfigureGenerationStep({
|
|
|
70
70
|
};
|
|
71
71
|
|
|
72
72
|
return (
|
|
73
|
-
<form onSubmit={handleSubmit} className="semiont-form">
|
|
73
|
+
<form onSubmit={handleSubmit} className="semiont-form semiont-form--scrollable">
|
|
74
74
|
{/* Resource Title */}
|
|
75
75
|
<div className="semiont-form__field">
|
|
76
76
|
<label htmlFor="wizard-title" className="semiont-form__label">
|
|
@@ -115,73 +115,67 @@ export function ConfigureGenerationStep({
|
|
|
115
115
|
id="wizard-prompt"
|
|
116
116
|
value={prompt}
|
|
117
117
|
onChange={(e) => setPrompt(e.target.value)}
|
|
118
|
-
rows={
|
|
118
|
+
rows={2}
|
|
119
119
|
className="semiont-textarea"
|
|
120
120
|
placeholder={t.additionalInstructionsPlaceholder}
|
|
121
121
|
/>
|
|
122
122
|
</div>
|
|
123
123
|
|
|
124
|
-
{/* Language
|
|
125
|
-
<div className="semiont-
|
|
126
|
-
<
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
{lang.
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
</p>
|
|
144
|
-
</div>
|
|
124
|
+
{/* Language / Creativity / Max Length — compact inline row */}
|
|
125
|
+
<div className="semiont-form__inline-row">
|
|
126
|
+
<div className="semiont-form__field semiont-form__field--inline">
|
|
127
|
+
<label htmlFor="wizard-language" className="semiont-form__label">
|
|
128
|
+
{t.language}
|
|
129
|
+
</label>
|
|
130
|
+
<select
|
|
131
|
+
id="wizard-language"
|
|
132
|
+
value={language}
|
|
133
|
+
onChange={(e) => setLanguage(e.target.value)}
|
|
134
|
+
className="semiont-select"
|
|
135
|
+
>
|
|
136
|
+
{LOCALES.map((lang) => (
|
|
137
|
+
<option key={lang.code} value={lang.code}>
|
|
138
|
+
{lang.nativeName}
|
|
139
|
+
</option>
|
|
140
|
+
))}
|
|
141
|
+
</select>
|
|
142
|
+
</div>
|
|
145
143
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
144
|
+
<div className="semiont-form__field semiont-form__field--inline semiont-form__field--grow">
|
|
145
|
+
<label htmlFor="wizard-temperature" className="semiont-form__label">
|
|
146
|
+
{t.creativity} ({temperature.toFixed(1)})
|
|
147
|
+
</label>
|
|
148
|
+
<input
|
|
149
|
+
id="wizard-temperature"
|
|
150
|
+
type="range"
|
|
151
|
+
min="0"
|
|
152
|
+
max="1"
|
|
153
|
+
step="0.1"
|
|
154
|
+
value={temperature}
|
|
155
|
+
onChange={(e) => setTemperature(parseFloat(e.target.value))}
|
|
156
|
+
className="semiont-slider"
|
|
157
|
+
/>
|
|
158
|
+
<div className="semiont-slider__labels semiont-slider__labels--small">
|
|
159
|
+
<span>{t.creativityFocused}</span>
|
|
160
|
+
<span>{t.creativityCreative}</span>
|
|
161
|
+
</div>
|
|
164
162
|
</div>
|
|
165
|
-
</div>
|
|
166
163
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
<p className="semiont-form__help">
|
|
183
|
-
{t.maxLengthHelp}
|
|
184
|
-
</p>
|
|
164
|
+
<div className="semiont-form__field semiont-form__field--inline semiont-form__field--narrow">
|
|
165
|
+
<label htmlFor="wizard-maxTokens" className="semiont-form__label">
|
|
166
|
+
{t.maxLength}
|
|
167
|
+
</label>
|
|
168
|
+
<input
|
|
169
|
+
id="wizard-maxTokens"
|
|
170
|
+
type="number"
|
|
171
|
+
min="100"
|
|
172
|
+
max="4000"
|
|
173
|
+
step="100"
|
|
174
|
+
value={maxTokens}
|
|
175
|
+
onChange={(e) => setMaxTokens(parseInt(e.target.value))}
|
|
176
|
+
className="semiont-input"
|
|
177
|
+
/>
|
|
178
|
+
</div>
|
|
185
179
|
</div>
|
|
186
180
|
|
|
187
181
|
{/* Action Buttons */}
|
|
@@ -115,10 +115,9 @@ export function ReferenceWizardModal({
|
|
|
115
115
|
if (!isOpen) return;
|
|
116
116
|
|
|
117
117
|
const subscription = eventBus.get('match:search-results').subscribe((event) => {
|
|
118
|
-
|
|
119
|
-
if (annotationId && e.referenceId === annotationId) {
|
|
118
|
+
if (annotationId && event.referenceId === annotationId) {
|
|
120
119
|
setIsSearching(false);
|
|
121
|
-
setWizardStep({ step: 'search-results', results:
|
|
120
|
+
setWizardStep({ step: 'search-results', results: event.response as ScoredResult[] });
|
|
122
121
|
}
|
|
123
122
|
});
|
|
124
123
|
|
|
@@ -149,6 +148,7 @@ export function ReferenceWizardModal({
|
|
|
149
148
|
setIsSearching(true);
|
|
150
149
|
const contextWithHint = userHint ? { ...context, userHint } : context;
|
|
151
150
|
eventBus.get('match:search-requested').next({
|
|
151
|
+
correlationId: crypto.randomUUID(),
|
|
152
152
|
referenceId: annotationId,
|
|
153
153
|
context: contextWithHint,
|
|
154
154
|
limit: config.limit,
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import { describe, it, expect,
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { screen, fireEvent } from '@testing-library/react';
|
|
4
4
|
import '@testing-library/jest-dom';
|
|
5
|
-
import { renderWithProviders
|
|
5
|
+
import { renderWithProviders } from '../../../test-utils';
|
|
6
6
|
import { ObservableLink } from '../ObservableLink';
|
|
7
7
|
|
|
8
8
|
describe('ObservableLink', () => {
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
resetEventBusForTesting();
|
|
11
|
-
});
|
|
12
|
-
|
|
13
9
|
it('renders anchor with href', () => {
|
|
14
10
|
renderWithProviders(
|
|
15
11
|
<ObservableLink href="/discover">Discover</ObservableLink>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { describe, it, expect,
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { screen, fireEvent } from '@testing-library/react';
|
|
4
4
|
import '@testing-library/jest-dom';
|
|
5
|
-
import { renderWithProviders
|
|
5
|
+
import { renderWithProviders } from '../../../test-utils';
|
|
6
6
|
import { SimpleNavigation } from '../SimpleNavigation';
|
|
7
7
|
import type { SimpleNavigationItem } from '../SimpleNavigation';
|
|
8
8
|
|
|
@@ -36,10 +36,6 @@ const defaultProps = {
|
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
describe('SimpleNavigation', () => {
|
|
39
|
-
beforeEach(() => {
|
|
40
|
-
resetEventBusForTesting();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
39
|
describe('title visibility', () => {
|
|
44
40
|
it('renders title when not collapsed', () => {
|
|
45
41
|
renderWithProviders(<SimpleNavigation {...defaultProps} />);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import React, { useRef, useState, useCallback, useEffect, useMemo } from 'react';
|
|
4
4
|
import { createHoverHandlers } from '../../hooks/useBeckonFlow';
|
|
5
|
-
import type { components
|
|
5
|
+
import type { components } from '@semiont/core';
|
|
6
6
|
import { getTargetSelector } from '@semiont/api-client';
|
|
7
7
|
import type { SelectionMotivation } from '../annotation/AnnotateToolbar';
|
|
8
8
|
import type { EventBus } from "@semiont/core"
|
|
@@ -48,7 +48,7 @@ function getMotivationColor(motivation: SelectionMotivation | null): { stroke: s
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
interface PdfAnnotationCanvasProps {
|
|
51
|
-
|
|
51
|
+
pdfUrl: string;
|
|
52
52
|
existingAnnotations?: Annotation[];
|
|
53
53
|
drawingMode: DrawingMode;
|
|
54
54
|
selectedMotivation?: SelectionMotivation | null;
|
|
@@ -66,7 +66,7 @@ interface PdfAnnotationCanvasProps {
|
|
|
66
66
|
* @emits beckon:hover - Annotation hovered or unhovered. Payload: { annotationId: string | null }
|
|
67
67
|
*/
|
|
68
68
|
export function PdfAnnotationCanvas({
|
|
69
|
-
|
|
69
|
+
pdfUrl,
|
|
70
70
|
existingAnnotations = [],
|
|
71
71
|
drawingMode,
|
|
72
72
|
selectedMotivation,
|
|
@@ -75,12 +75,6 @@ export function PdfAnnotationCanvas({
|
|
|
75
75
|
selectedAnnotationId,
|
|
76
76
|
hoverDelayMs = 150
|
|
77
77
|
}: PdfAnnotationCanvasProps) {
|
|
78
|
-
const pdfUrl = useMemo(() => {
|
|
79
|
-
return `/api/resources/${resourceUri}`;
|
|
80
|
-
}, [resourceUri]);
|
|
81
|
-
|
|
82
|
-
// Removed excessive logging
|
|
83
|
-
|
|
84
78
|
// PDF state
|
|
85
79
|
const [pdfDoc, setPdfDoc] = useState<PDFDocumentProxy | null>(null);
|
|
86
80
|
const [numPages, setNumPages] = useState<number>(0);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useRef, useEffect, useCallback, lazy, Suspense } from 'react';
|
|
4
|
-
import { resourceId as toResourceId } from '@semiont/core';
|
|
5
4
|
import { getMimeCategory, isPdfMimeType } from '@semiont/api-client';
|
|
6
5
|
import { ANNOTATORS } from '../../lib/annotation-registry';
|
|
7
6
|
import { segmentTextWithAnnotations } from '../../lib/text-segmentation';
|
|
@@ -244,10 +243,10 @@ export function AnnotateView({
|
|
|
244
243
|
annotators={ANNOTATORS}
|
|
245
244
|
/>
|
|
246
245
|
<div className="semiont-annotate-view__content">
|
|
247
|
-
{
|
|
246
|
+
{content && (
|
|
248
247
|
<Suspense fallback={<div className="semiont-annotate-view__loading">Loading PDF viewer...</div>}>
|
|
249
248
|
<PdfAnnotationCanvas
|
|
250
|
-
|
|
249
|
+
pdfUrl={content}
|
|
251
250
|
existingAnnotations={allAnnotations}
|
|
252
251
|
drawingMode={selectedMotivation ? selectedShape : null}
|
|
253
252
|
selectedMotivation={selectedMotivation}
|
|
@@ -275,9 +274,9 @@ export function AnnotateView({
|
|
|
275
274
|
annotators={ANNOTATORS}
|
|
276
275
|
/>
|
|
277
276
|
<div className="semiont-annotate-view__content">
|
|
278
|
-
{
|
|
277
|
+
{content && (
|
|
279
278
|
<SvgDrawingCanvas
|
|
280
|
-
|
|
279
|
+
imageUrl={content}
|
|
281
280
|
existingAnnotations={allAnnotations}
|
|
282
281
|
drawingMode={selectedMotivation ? selectedShape : null}
|
|
283
282
|
selectedMotivation={selectedMotivation}
|
|
@@ -5,7 +5,6 @@ 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 type { StoredEvent } from '@semiont/core';
|
|
9
8
|
import { getAnnotationUriFromEvent } from '@semiont/core';
|
|
10
9
|
import { HistoryEvent } from './HistoryEvent';
|
|
11
10
|
|
|
@@ -39,13 +38,11 @@ export function AnnotationHistory({ rUri, hoveredAnnotationId, onEventHover, onE
|
|
|
39
38
|
// Sort events by oldest first (most recent at bottom)
|
|
40
39
|
// Filter out all job events - they're represented by annotation.body.updated events instead
|
|
41
40
|
const events = !eventsData?.events ? [] : [...eventsData.events]
|
|
42
|
-
.filter((e
|
|
41
|
+
.filter((e) => {
|
|
43
42
|
const eventType = e.event.type;
|
|
44
43
|
return eventType !== 'job.started' && eventType !== 'job.progress' && eventType !== 'job.completed';
|
|
45
44
|
})
|
|
46
|
-
.sort((a
|
|
47
|
-
a.metadata.sequenceNumber - b.metadata.sequenceNumber
|
|
48
|
-
);
|
|
45
|
+
.sort((a, b) => a.metadata.sequenceNumber - b.metadata.sequenceNumber);
|
|
49
46
|
|
|
50
47
|
// Scroll to bottom when History is first shown or when events change
|
|
51
48
|
useEffect(() => {
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import { useEffect, useRef, useCallback, useMemo, memo, lazy, Suspense } from 'react';
|
|
4
4
|
import ReactMarkdown from 'react-markdown';
|
|
5
5
|
import remarkGfm from 'remark-gfm';
|
|
6
|
-
import { resourceId as toResourceId } from '@semiont/core';
|
|
7
6
|
import { getMimeCategory, isPdfMimeType } from '@semiont/api-client';
|
|
8
7
|
import { ANNOTATORS } from '../../lib/annotation-registry';
|
|
9
8
|
import { createHoverHandlers } from '../../hooks/useBeckonFlow';
|
|
@@ -240,7 +239,7 @@ export const BrowseView = memo(function BrowseView({
|
|
|
240
239
|
<div ref={containerRef} className="semiont-browse-view__content">
|
|
241
240
|
<Suspense fallback={<div className="semiont-browse-view__loading">Loading PDF viewer...</div>}>
|
|
242
241
|
<PdfAnnotationCanvas
|
|
243
|
-
|
|
242
|
+
pdfUrl={content}
|
|
244
243
|
existingAnnotations={allAnnotations}
|
|
245
244
|
drawingMode={null}
|
|
246
245
|
selectedMotivation={null}
|
|
@@ -264,7 +263,7 @@ export const BrowseView = memo(function BrowseView({
|
|
|
264
263
|
/>
|
|
265
264
|
<div ref={containerRef} className="semiont-browse-view__content">
|
|
266
265
|
<ImageViewer
|
|
267
|
-
|
|
266
|
+
imageUrl={content}
|
|
268
267
|
mimeType={mimeType}
|
|
269
268
|
alt="Resource content"
|
|
270
269
|
/>
|
|
@@ -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 {
|
|
5
|
+
import type { StoredEventLike, ResourceEventType } from '@semiont/core';
|
|
6
6
|
import { getAnnotationUriFromEvent } from '@semiont/core';
|
|
7
7
|
import {
|
|
8
8
|
formatEventType,
|
|
@@ -16,9 +16,9 @@ import {
|
|
|
16
16
|
type TranslateFn = (key: string, params?: Record<string, string | number>) => string;
|
|
17
17
|
|
|
18
18
|
interface Props {
|
|
19
|
-
event:
|
|
19
|
+
event: StoredEventLike;
|
|
20
20
|
annotations: any[]; // Unified annotations array (all types)
|
|
21
|
-
allEvents:
|
|
21
|
+
allEvents: StoredEventLike[];
|
|
22
22
|
isRelated: boolean;
|
|
23
23
|
t: TranslateFn;
|
|
24
24
|
Link: React.ComponentType<LinkComponentProps>;
|
|
@@ -3,7 +3,7 @@ import React from 'react';
|
|
|
3
3
|
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
4
4
|
import { BrowseView } from '../BrowseView';
|
|
5
5
|
import type { components } from '@semiont/core';
|
|
6
|
-
import { EventBusProvider,
|
|
6
|
+
import { EventBusProvider, useEventBus } from '../../../contexts/EventBusContext';
|
|
7
7
|
|
|
8
8
|
type Annotation = components['schemas']['Annotation'];
|
|
9
9
|
|
|
@@ -214,7 +214,6 @@ describe('BrowseView Component', () => {
|
|
|
214
214
|
};
|
|
215
215
|
|
|
216
216
|
beforeEach(() => {
|
|
217
|
-
resetEventBusForTesting();
|
|
218
217
|
vi.clearAllMocks();
|
|
219
218
|
mockNewAnnotationIds = new Set();
|
|
220
219
|
|
|
@@ -75,19 +75,19 @@ const mockTranslationManager = {
|
|
|
75
75
|
function TestWrapper({ children }: { children: React.ReactNode }) {
|
|
76
76
|
return (
|
|
77
77
|
<TranslationProvider translationManager={mockTranslationManager}>
|
|
78
|
-
<
|
|
79
|
-
<
|
|
80
|
-
<
|
|
81
|
-
<
|
|
78
|
+
<EventBusProvider>
|
|
79
|
+
<AuthTokenProvider token="test-token">
|
|
80
|
+
<ApiClientProvider baseUrl="http://localhost:4000">
|
|
81
|
+
<QueryClientProvider client={queryClient}>
|
|
82
82
|
<ResourceAnnotationsProvider>
|
|
83
83
|
<CacheProvider cacheManager={mockCacheManager}>
|
|
84
84
|
{children}
|
|
85
85
|
</CacheProvider>
|
|
86
86
|
</ResourceAnnotationsProvider>
|
|
87
|
-
</
|
|
88
|
-
</
|
|
89
|
-
</
|
|
90
|
-
</
|
|
87
|
+
</QueryClientProvider>
|
|
88
|
+
</ApiClientProvider>
|
|
89
|
+
</AuthTokenProvider>
|
|
90
|
+
</EventBusProvider>
|
|
91
91
|
</TranslationProvider>
|
|
92
92
|
);
|
|
93
93
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* No React dependencies - safe to use in any JavaScript environment.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type {
|
|
8
|
+
import type { StoredEventLike, ResourceEventType } 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';
|
|
@@ -144,17 +144,18 @@ function truncateText(text: string, maxLength = 50): string {
|
|
|
144
144
|
* Get display content from event payload - complete implementation
|
|
145
145
|
*/
|
|
146
146
|
export function getEventDisplayContent(
|
|
147
|
-
event:
|
|
147
|
+
event: StoredEventLike,
|
|
148
148
|
annotations: Annotation[], // Unified annotations array (all types)
|
|
149
|
-
allEvents:
|
|
149
|
+
allEvents: StoredEventLike[]
|
|
150
150
|
): { exact: string; isQuoted: boolean; isTag: boolean } | null {
|
|
151
151
|
const eventData = event.event;
|
|
152
|
+
const payload = eventData.payload as any;
|
|
152
153
|
|
|
153
154
|
// Use type discriminators for proper narrowing
|
|
154
155
|
switch (eventData.type) {
|
|
155
156
|
case 'resource.created':
|
|
156
157
|
case 'resource.cloned': {
|
|
157
|
-
return { exact:
|
|
158
|
+
return { exact: payload.name, isQuoted: false, isTag: false };
|
|
158
159
|
}
|
|
159
160
|
|
|
160
161
|
// Unified annotation events
|
|
@@ -162,7 +163,7 @@ export function getEventDisplayContent(
|
|
|
162
163
|
// Find current annotation to get its text
|
|
163
164
|
// payload.annotationId is just the UUID, but annotation.id is the full URI
|
|
164
165
|
const annotation = annotations.find(a =>
|
|
165
|
-
a.id.endsWith(`/annotations/${
|
|
166
|
+
a.id.endsWith(`/annotations/${payload.annotationId}`)
|
|
166
167
|
);
|
|
167
168
|
|
|
168
169
|
if (annotation?.target) {
|
|
@@ -184,11 +185,11 @@ export function getEventDisplayContent(
|
|
|
184
185
|
// payload.annotationId is just the UUID, but annotation.id in the added event is the full URI
|
|
185
186
|
const addedEvent = allEvents.find(e =>
|
|
186
187
|
e.event.type === 'annotation.added' &&
|
|
187
|
-
e.event.payload.annotation.id.endsWith(`/annotations/${
|
|
188
|
+
(e.event.payload as any).annotation.id.endsWith(`/annotations/${payload.annotationId}`)
|
|
188
189
|
);
|
|
189
190
|
if (addedEvent && addedEvent.event.type === 'annotation.added') {
|
|
190
191
|
try {
|
|
191
|
-
const target = addedEvent.event.payload.annotation.target;
|
|
192
|
+
const target = (addedEvent.event.payload as any).annotation.target;
|
|
192
193
|
if (typeof target !== 'string' && target.selector) {
|
|
193
194
|
const exact = getExactText(target.selector);
|
|
194
195
|
if (exact) {
|
|
@@ -205,7 +206,7 @@ export function getEventDisplayContent(
|
|
|
205
206
|
case 'annotation.added': {
|
|
206
207
|
// New unified event structure - annotation is in payload
|
|
207
208
|
try {
|
|
208
|
-
const target =
|
|
209
|
+
const target = payload.annotation.target;
|
|
209
210
|
if (typeof target !== 'string' && target.selector) {
|
|
210
211
|
const exact = getExactText(target.selector);
|
|
211
212
|
if (exact) {
|
|
@@ -220,14 +221,14 @@ export function getEventDisplayContent(
|
|
|
220
221
|
|
|
221
222
|
case 'entitytag.added':
|
|
222
223
|
case 'entitytag.removed': {
|
|
223
|
-
return { exact:
|
|
224
|
+
return { exact: payload.entityType, isQuoted: false, isTag: true };
|
|
224
225
|
}
|
|
225
226
|
|
|
226
227
|
case 'job.completed': {
|
|
227
228
|
// Find the annotation that was used to generate the resource
|
|
228
|
-
if (
|
|
229
|
+
if (payload.annotationUri) {
|
|
229
230
|
const annotation = annotations.find(a =>
|
|
230
|
-
a.id ===
|
|
231
|
+
a.id === payload.annotationUri
|
|
231
232
|
);
|
|
232
233
|
|
|
233
234
|
if (annotation?.target) {
|
|
@@ -260,12 +261,13 @@ export function getEventDisplayContent(
|
|
|
260
261
|
/**
|
|
261
262
|
* Get entity types from event payload
|
|
262
263
|
*/
|
|
263
|
-
export function getEventEntityTypes(event:
|
|
264
|
+
export function getEventEntityTypes(event: StoredEventLike): string[] {
|
|
264
265
|
const eventData = event.event;
|
|
266
|
+
const payload = eventData.payload as any;
|
|
265
267
|
|
|
266
268
|
if (eventData.type === 'annotation.added') {
|
|
267
|
-
const motivation =
|
|
268
|
-
const body =
|
|
269
|
+
const motivation = payload.annotation.motivation;
|
|
270
|
+
const body = payload.annotation.body;
|
|
269
271
|
if (motivation === 'linking' && body && 'entityTypes' in body) {
|
|
270
272
|
return (body as any).entityTypes ?? [];
|
|
271
273
|
}
|
|
@@ -289,13 +291,14 @@ export interface ResourceCreationDetails {
|
|
|
289
291
|
/**
|
|
290
292
|
* Get resource creation details from event
|
|
291
293
|
*/
|
|
292
|
-
export function getResourceCreationDetails(event:
|
|
294
|
+
export function getResourceCreationDetails(event: StoredEventLike): ResourceCreationDetails | null {
|
|
293
295
|
const eventData = event.event;
|
|
296
|
+
const payload = eventData.payload as any;
|
|
294
297
|
|
|
295
298
|
if (eventData.type === 'resource.created') {
|
|
296
299
|
return {
|
|
297
300
|
type: 'created',
|
|
298
|
-
method:
|
|
301
|
+
method: payload.creationMethod || 'unknown',
|
|
299
302
|
userId: eventData.userId,
|
|
300
303
|
metadata: undefined,
|
|
301
304
|
};
|
|
@@ -304,10 +307,10 @@ export function getResourceCreationDetails(event: StoredEvent): ResourceCreation
|
|
|
304
307
|
if (eventData.type === 'resource.cloned') {
|
|
305
308
|
return {
|
|
306
309
|
type: 'cloned',
|
|
307
|
-
method:
|
|
310
|
+
method: payload.creationMethod || 'clone',
|
|
308
311
|
userId: eventData.userId,
|
|
309
|
-
sourceDocId:
|
|
310
|
-
parentResourceId:
|
|
312
|
+
sourceDocId: payload.parentResourceId,
|
|
313
|
+
parentResourceId: payload.parentResourceId,
|
|
311
314
|
metadata: undefined,
|
|
312
315
|
};
|
|
313
316
|
}
|
|
@@ -2,7 +2,7 @@ import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { screen } from '@testing-library/react';
|
|
4
4
|
import '@testing-library/jest-dom';
|
|
5
|
-
import { renderWithProviders
|
|
5
|
+
import { renderWithProviders } from '../../../../test-utils';
|
|
6
6
|
import userEvent from '@testing-library/user-event';
|
|
7
7
|
import type { components } from '@semiont/core';
|
|
8
8
|
|
|
@@ -56,7 +56,6 @@ describe('AssessmentEntry', () => {
|
|
|
56
56
|
|
|
57
57
|
beforeEach(() => {
|
|
58
58
|
vi.clearAllMocks();
|
|
59
|
-
resetEventBusForTesting();
|
|
60
59
|
mockGetAnnotationExactText.mockReturnValue('Selected passage text');
|
|
61
60
|
});
|
|
62
61
|
|
|
@@ -5,7 +5,7 @@ import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
|
5
5
|
import userEvent from '@testing-library/user-event';
|
|
6
6
|
import '@testing-library/jest-dom';
|
|
7
7
|
import { AssessmentPanel } from '../AssessmentPanel';
|
|
8
|
-
import { EventBusProvider,
|
|
8
|
+
import { EventBusProvider, useEventBus } from '../../../../contexts/EventBusContext';
|
|
9
9
|
import type { components } from '@semiont/core';
|
|
10
10
|
|
|
11
11
|
type Annotation = components['schemas']['Annotation'];
|
|
@@ -178,7 +178,6 @@ describe('AssessmentPanel Component', () => {
|
|
|
178
178
|
};
|
|
179
179
|
|
|
180
180
|
beforeEach(() => {
|
|
181
|
-
resetEventBusForTesting();
|
|
182
181
|
vi.clearAllMocks();
|
|
183
182
|
|
|
184
183
|
// Mock scrollIntoView for jsdom
|
|
@@ -17,7 +17,6 @@ import { screen } from '@testing-library/react';
|
|
|
17
17
|
import { renderWithProviders } from '../../../../test-utils';
|
|
18
18
|
import userEvent from '@testing-library/user-event';
|
|
19
19
|
import { AssistSection } from '../AssistSection';
|
|
20
|
-
import { resetEventBusForTesting } from '../../../../contexts/EventBusContext';
|
|
21
20
|
import type { EventBus } from "@semiont/core"
|
|
22
21
|
|
|
23
22
|
// Mock translations
|
|
@@ -56,7 +55,6 @@ vi.mock('../../../../contexts/TranslationContext', () => ({
|
|
|
56
55
|
describe('AssistSection', () => {
|
|
57
56
|
beforeEach(() => {
|
|
58
57
|
vi.clearAllMocks();
|
|
59
|
-
resetEventBusForTesting();
|
|
60
58
|
// Clear localStorage
|
|
61
59
|
if (typeof window !== 'undefined') {
|
|
62
60
|
localStorage.clear();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { screen, fireEvent, waitFor } from '@testing-library/react';
|
|
4
|
-
import { renderWithProviders
|
|
4
|
+
import { renderWithProviders } from '../../../../test-utils';
|
|
5
5
|
import userEvent from '@testing-library/user-event';
|
|
6
6
|
import '@testing-library/jest-dom';
|
|
7
7
|
import { CommentEntry } from '../CommentEntry';
|
|
@@ -105,7 +105,6 @@ describe('CommentEntry Component', () => {
|
|
|
105
105
|
|
|
106
106
|
beforeEach(() => {
|
|
107
107
|
vi.clearAllMocks();
|
|
108
|
-
resetEventBusForTesting(); // Reset event bus between tests
|
|
109
108
|
mockGetCommentText.mockReturnValue('This is a test comment');
|
|
110
109
|
mockGetAnnotationExactText.mockReturnValue('This is th');
|
|
111
110
|
|
|
@@ -5,7 +5,7 @@ import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
|
5
5
|
import userEvent from '@testing-library/user-event';
|
|
6
6
|
import '@testing-library/jest-dom';
|
|
7
7
|
import { CommentsPanel } from '../CommentsPanel';
|
|
8
|
-
import { EventBusProvider,
|
|
8
|
+
import { EventBusProvider, useEventBus } from '../../../../contexts/EventBusContext';
|
|
9
9
|
import type { components } from '@semiont/core';
|
|
10
10
|
|
|
11
11
|
type Annotation = components['schemas']['Annotation'];
|
|
@@ -178,7 +178,6 @@ describe('CommentsPanel Component', () => {
|
|
|
178
178
|
};
|
|
179
179
|
|
|
180
180
|
beforeEach(() => {
|
|
181
|
-
resetEventBusForTesting();
|
|
182
181
|
vi.clearAllMocks();
|
|
183
182
|
|
|
184
183
|
// Mock scrollIntoView for jsdom
|
|
@@ -2,7 +2,7 @@ import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { screen, fireEvent } from '@testing-library/react';
|
|
4
4
|
import '@testing-library/jest-dom';
|
|
5
|
-
import { renderWithProviders
|
|
5
|
+
import { renderWithProviders } from '../../../../test-utils';
|
|
6
6
|
import userEvent from '@testing-library/user-event';
|
|
7
7
|
import type { components } from '@semiont/core';
|
|
8
8
|
|
|
@@ -52,7 +52,6 @@ describe('HighlightEntry', () => {
|
|
|
52
52
|
|
|
53
53
|
beforeEach(() => {
|
|
54
54
|
vi.clearAllMocks();
|
|
55
|
-
resetEventBusForTesting();
|
|
56
55
|
mockGetAnnotationExactText.mockReturnValue('This is the highlighted text');
|
|
57
56
|
});
|
|
58
57
|
|
|
@@ -17,7 +17,6 @@ import { screen } from '@testing-library/react';
|
|
|
17
17
|
import { renderWithProviders } from '../../../../test-utils';
|
|
18
18
|
import { HighlightPanel } from '../HighlightPanel';
|
|
19
19
|
import type { components } from '@semiont/core';
|
|
20
|
-
import { resetEventBusForTesting } from '../../../../contexts/EventBusContext';
|
|
21
20
|
|
|
22
21
|
type Annotation = components['schemas']['Annotation'];
|
|
23
22
|
|
|
@@ -53,7 +52,6 @@ describe('HighlightPanel + AssistSection Integration', () => {
|
|
|
53
52
|
|
|
54
53
|
beforeEach(() => {
|
|
55
54
|
vi.clearAllMocks();
|
|
56
|
-
resetEventBusForTesting();
|
|
57
55
|
|
|
58
56
|
mockAnnotations = [
|
|
59
57
|
{
|