@striae-org/striae 4.1.0 → 4.2.0
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/.env.example +8 -0
- package/app/components/actions/case-export/core-export.ts +14 -8
- package/app/components/actions/case-export/data-processing.ts +1 -0
- package/app/components/actions/case-export/download-handlers.ts +7 -0
- package/app/components/actions/case-export/metadata-helpers.ts +2 -1
- package/app/components/actions/case-import/confirmation-import.ts +12 -2
- package/app/components/actions/case-import/orchestrator.ts +78 -32
- package/app/components/actions/case-import/storage-operations.ts +97 -8
- package/app/components/actions/case-import/zip-processing.ts +159 -86
- package/app/components/actions/case-manage.ts +430 -8
- package/app/components/actions/confirm-export.ts +9 -2
- package/app/components/actions/image-manage.ts +77 -44
- package/app/components/audit/user-audit-viewer.tsx +19 -8
- package/app/components/audit/user-audit.module.css +21 -0
- package/app/components/audit/viewer/audit-entries-list.tsx +7 -0
- package/app/components/audit/viewer/audit-filters-panel.tsx +1 -0
- package/app/components/audit/viewer/audit-viewer-utils.ts +2 -0
- package/app/components/audit/viewer/use-audit-viewer-data.ts +21 -1
- package/app/components/canvas/box-annotations/box-annotations.module.css +22 -18
- package/app/components/canvas/box-annotations/box-annotations.tsx +15 -0
- package/app/components/canvas/canvas.module.css +64 -54
- package/app/components/canvas/canvas.tsx +14 -16
- package/app/components/canvas/confirmation/confirmation.module.css +1 -0
- package/app/components/canvas/confirmation/confirmation.tsx +6 -12
- package/app/components/navbar/case-modals/archive-case-modal.module.css +110 -0
- package/app/components/navbar/case-modals/archive-case-modal.tsx +129 -0
- package/app/components/navbar/case-modals/open-case-modal.module.css +81 -0
- package/app/components/navbar/case-modals/open-case-modal.tsx +120 -0
- package/app/components/navbar/case-modals/rename-case-modal.module.css +81 -0
- package/app/components/navbar/case-modals/rename-case-modal.tsx +107 -0
- package/app/components/navbar/navbar.module.css +447 -0
- package/app/components/navbar/navbar.tsx +377 -0
- package/app/components/public-signing-key-modal/public-signing-key-modal.module.css +1 -0
- package/app/components/public-signing-key-modal/public-signing-key-modal.tsx +15 -16
- package/app/components/sidebar/case-export/case-export.module.css +1 -0
- package/app/components/sidebar/case-export/case-export.tsx +8 -46
- package/app/components/sidebar/case-import/case-import.module.css +23 -0
- package/app/components/sidebar/case-import/case-import.tsx +64 -16
- package/app/components/sidebar/case-import/components/CasePreviewSection.tsx +20 -1
- package/app/components/sidebar/case-import/components/ConfirmationDialog.tsx +15 -0
- package/app/components/sidebar/cases/case-sidebar.tsx +25 -519
- package/app/components/sidebar/cases/cases-modal.module.css +1 -0
- package/app/components/sidebar/cases/cases-modal.tsx +6 -8
- package/app/components/sidebar/cases/cases.module.css +62 -21
- package/app/components/sidebar/files/files-modal.module.css +1 -0
- package/app/components/sidebar/files/files-modal.tsx +12 -13
- package/app/components/sidebar/notes/notes-editor-modal.module.css +49 -0
- package/app/components/sidebar/notes/notes-editor-modal.tsx +66 -0
- package/app/components/sidebar/notes/notes-modal.tsx +7 -8
- package/app/components/sidebar/notes/notes-sidebar.tsx +199 -113
- package/app/components/sidebar/notes/notes.module.css +153 -0
- package/app/components/sidebar/sidebar-container.tsx +15 -28
- package/app/components/sidebar/sidebar.module.css +5 -69
- package/app/components/sidebar/sidebar.tsx +24 -125
- package/app/components/sidebar/upload/image-upload-zone.module.css +13 -13
- package/app/components/user/inactivity-warning.module.css +1 -0
- package/app/components/user/inactivity-warning.tsx +15 -2
- package/app/components/user/manage-profile.tsx +23 -10
- package/app/hooks/useOverlayDismiss.ts +52 -4
- package/app/routes/auth/login.tsx +785 -774
- package/app/routes/striae/striae.module.css +10 -3
- package/app/routes/striae/striae.tsx +469 -30
- package/app/services/audit/audit.service.ts +173 -27
- package/app/services/audit/builders/audit-event-builders-case-file.ts +43 -0
- package/app/services/audit/builders/audit-event-builders-workflow.ts +2 -0
- package/app/services/audit/builders/index.ts +1 -0
- package/app/types/audit.ts +3 -1
- package/app/types/case.ts +29 -0
- package/app/types/import.ts +3 -0
- package/app/utils/data/permissions.ts +16 -1
- package/app/utils/forensics/audit-export-signature.ts +5 -1
- package/app/utils/forensics/confirmation-signature.ts +3 -0
- package/app/utils/forensics/export-verification.ts +497 -22
- package/package.json +3 -3
- package/scripts/deploy-primershear-emails.sh +2 -1
- package/worker-configuration.d.ts +1 -1
- package/workers/audit-worker/worker-configuration.d.ts +7448 -11323
- package/workers/audit-worker/wrangler.jsonc.example +1 -1
- package/workers/data-worker/worker-configuration.d.ts +7448 -11323
- package/workers/data-worker/wrangler.jsonc.example +1 -1
- package/workers/image-worker/worker-configuration.d.ts +7447 -11322
- package/workers/image-worker/wrangler.jsonc.example +1 -1
- package/workers/keys-worker/worker-configuration.d.ts +7447 -11322
- package/workers/keys-worker/wrangler.jsonc.example +1 -1
- package/workers/pdf-worker/src/formats/format-striae.ts +8 -7
- package/workers/pdf-worker/worker-configuration.d.ts +7448 -11323
- package/workers/pdf-worker/wrangler.jsonc.example +1 -1
- package/workers/user-worker/worker-configuration.d.ts +7448 -11323
- package/workers/user-worker/wrangler.jsonc.example +1 -1
- package/wrangler.toml.example +1 -1
- package/public/.well-known/keybase.txt +0 -56
|
@@ -20,8 +20,9 @@ export const CasesModal = ({ isOpen, onClose, onSelectCase, currentCase, user }:
|
|
|
20
20
|
const [error, setError] = useState<string>('');
|
|
21
21
|
const [currentPage, setCurrentPage] = useState(0);
|
|
22
22
|
const {
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
requestClose,
|
|
24
|
+
overlayProps,
|
|
25
|
+
getCloseButtonProps
|
|
25
26
|
} = useOverlayDismiss({
|
|
26
27
|
isOpen,
|
|
27
28
|
onClose
|
|
@@ -141,16 +142,13 @@ export const CasesModal = ({ isOpen, onClose, onSelectCase, currentCase, user }:
|
|
|
141
142
|
return (
|
|
142
143
|
<div
|
|
143
144
|
className={styles.modalOverlay}
|
|
144
|
-
onMouseDown={handleOverlayMouseDown}
|
|
145
|
-
onKeyDown={handleOverlayKeyDown}
|
|
146
|
-
role="button"
|
|
147
|
-
tabIndex={0}
|
|
148
145
|
aria-label="Close cases dialog"
|
|
146
|
+
{...overlayProps}
|
|
149
147
|
>
|
|
150
148
|
<div className={styles.modal}>
|
|
151
149
|
<header className={styles.modalHeader}>
|
|
152
150
|
<h2>All Cases</h2>
|
|
153
|
-
<button
|
|
151
|
+
<button className={styles.closeButton} {...getCloseButtonProps({ ariaLabel: 'Close cases dialog' })}>×</button>
|
|
154
152
|
</header>
|
|
155
153
|
|
|
156
154
|
<div className={styles.modalContent}>
|
|
@@ -178,7 +176,7 @@ export const CasesModal = ({ isOpen, onClose, onSelectCase, currentCase, user }:
|
|
|
178
176
|
className={`${styles.caseItem} ${currentCase === caseNum ? styles.active : ''} ${confirmationClass}`}
|
|
179
177
|
onClick={() => {
|
|
180
178
|
onSelectCase(caseNum);
|
|
181
|
-
|
|
179
|
+
requestClose();
|
|
182
180
|
}}
|
|
183
181
|
>
|
|
184
182
|
{caseNum}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
/* Case Management */
|
|
2
2
|
.caseSection {
|
|
3
|
-
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
gap: 0.75rem;
|
|
6
|
+
height: 100%;
|
|
7
|
+
min-height: 0;
|
|
8
|
+
margin-bottom: 0;
|
|
4
9
|
}
|
|
5
10
|
|
|
6
11
|
.caseSection h4 {
|
|
@@ -141,17 +146,18 @@
|
|
|
141
146
|
}
|
|
142
147
|
|
|
143
148
|
.filesModalSection {
|
|
144
|
-
margin:
|
|
149
|
+
margin: 0.25rem 0 0;
|
|
145
150
|
}
|
|
146
151
|
|
|
147
152
|
.filesModalButton {
|
|
148
153
|
width: 100%;
|
|
149
|
-
padding: 0.75rem;
|
|
154
|
+
padding: 0.625rem 0.75rem;
|
|
150
155
|
background-color: #17a2b8;
|
|
151
156
|
color: white;
|
|
152
157
|
border: none;
|
|
153
158
|
border-radius: 6px;
|
|
154
159
|
font-weight: 500;
|
|
160
|
+
font-size: 0.9rem;
|
|
155
161
|
cursor: pointer;
|
|
156
162
|
transition: all 0.2s;
|
|
157
163
|
box-sizing: border-box;
|
|
@@ -179,16 +185,39 @@
|
|
|
179
185
|
|
|
180
186
|
/* Files Section */
|
|
181
187
|
.filesSection {
|
|
182
|
-
|
|
188
|
+
display: flex;
|
|
189
|
+
flex: 1;
|
|
190
|
+
flex-direction: column;
|
|
191
|
+
gap: 0.625rem;
|
|
192
|
+
min-height: 0;
|
|
193
|
+
margin-top: 0.25rem;
|
|
183
194
|
}
|
|
184
195
|
|
|
185
196
|
.filesSection h4 {
|
|
186
|
-
margin-bottom:
|
|
187
|
-
font-size: 1.
|
|
197
|
+
margin-bottom: 0;
|
|
198
|
+
font-size: 1.1rem;
|
|
188
199
|
font-weight: 900;
|
|
189
200
|
text-align: center;
|
|
190
201
|
}
|
|
191
202
|
|
|
203
|
+
.emptyCaseHeader {
|
|
204
|
+
margin-top: 0.75rem;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.fileListPlaceholder {
|
|
208
|
+
display: flex;
|
|
209
|
+
align-items: center;
|
|
210
|
+
justify-content: center;
|
|
211
|
+
min-height: 5rem;
|
|
212
|
+
padding: 0.875rem;
|
|
213
|
+
border: 1px dashed #dee2e6;
|
|
214
|
+
border-radius: 6px;
|
|
215
|
+
background: #f8f9fa;
|
|
216
|
+
color: #6c757d;
|
|
217
|
+
font-size: 0.875rem;
|
|
218
|
+
text-align: center;
|
|
219
|
+
}
|
|
220
|
+
|
|
192
221
|
.emptyState {
|
|
193
222
|
color: #6c757d;
|
|
194
223
|
font-size: 0.9rem;
|
|
@@ -207,10 +236,20 @@
|
|
|
207
236
|
border: 1px solid #dee2e6;
|
|
208
237
|
border-radius: 6px;
|
|
209
238
|
overflow: hidden;
|
|
210
|
-
|
|
239
|
+
flex: 1;
|
|
240
|
+
min-height: 0;
|
|
241
|
+
max-height: none;
|
|
211
242
|
overflow-y: auto;
|
|
212
243
|
}
|
|
213
244
|
|
|
245
|
+
.fileListMessage {
|
|
246
|
+
padding: 0.875rem;
|
|
247
|
+
color: #6c757d;
|
|
248
|
+
font-size: 0.875rem;
|
|
249
|
+
text-align: center;
|
|
250
|
+
background: #f8f9fa;
|
|
251
|
+
}
|
|
252
|
+
|
|
214
253
|
.fileList::-webkit-scrollbar {
|
|
215
254
|
width: 6px;
|
|
216
255
|
}
|
|
@@ -231,7 +270,7 @@
|
|
|
231
270
|
.fileItem {
|
|
232
271
|
display: flex;
|
|
233
272
|
align-items: center;
|
|
234
|
-
padding: 0.
|
|
273
|
+
padding: 0.375rem 0.625rem;
|
|
235
274
|
border-bottom: 1px solid #dee2e6;
|
|
236
275
|
background: white;
|
|
237
276
|
transition: background-color 0.2s;
|
|
@@ -240,13 +279,14 @@
|
|
|
240
279
|
.fileButton {
|
|
241
280
|
flex: 1;
|
|
242
281
|
text-align: left;
|
|
243
|
-
padding: 0.
|
|
282
|
+
padding: 0.375rem;
|
|
244
283
|
background: none;
|
|
245
284
|
border: none;
|
|
246
285
|
cursor: pointer;
|
|
247
286
|
overflow: hidden;
|
|
248
287
|
text-overflow: ellipsis;
|
|
249
288
|
white-space: nowrap;
|
|
289
|
+
font-size: 0.875rem;
|
|
250
290
|
}
|
|
251
291
|
|
|
252
292
|
.fileItem:last-child {
|
|
@@ -335,14 +375,14 @@
|
|
|
335
375
|
background: none;
|
|
336
376
|
border: none;
|
|
337
377
|
color: #dc3545;
|
|
338
|
-
font-size:
|
|
378
|
+
font-size: 1rem;
|
|
339
379
|
cursor: pointer;
|
|
340
|
-
padding: 0.
|
|
380
|
+
padding: 0.375rem;
|
|
341
381
|
display: flex;
|
|
342
382
|
align-items: center;
|
|
343
383
|
justify-content: center;
|
|
344
|
-
min-width:
|
|
345
|
-
height:
|
|
384
|
+
min-width: 28px;
|
|
385
|
+
height: 28px;
|
|
346
386
|
}
|
|
347
387
|
|
|
348
388
|
.deleteButton:hover {
|
|
@@ -404,18 +444,19 @@
|
|
|
404
444
|
/* Notes Toggle */
|
|
405
445
|
|
|
406
446
|
.sidebarToggle {
|
|
407
|
-
margin-
|
|
408
|
-
padding:
|
|
447
|
+
margin-top: 0;
|
|
448
|
+
padding: 0;
|
|
409
449
|
}
|
|
410
450
|
|
|
411
451
|
.sidebarToggle button {
|
|
412
452
|
width: 100%;
|
|
413
|
-
padding: 0.75rem;
|
|
453
|
+
padding: 0.625rem 0.75rem;
|
|
414
454
|
background-color: var(--primary);
|
|
415
455
|
color: white;
|
|
416
456
|
border: none;
|
|
417
457
|
border-radius: 6px;
|
|
418
458
|
font-weight: 500;
|
|
459
|
+
font-size: 0.9rem;
|
|
419
460
|
cursor: pointer;
|
|
420
461
|
transition: all 0.2s;
|
|
421
462
|
}
|
|
@@ -643,27 +684,27 @@
|
|
|
643
684
|
background: #fff3cd;
|
|
644
685
|
border: 1px solid #ffeaa7;
|
|
645
686
|
border-radius: 4px;
|
|
646
|
-
padding: 0.75rem;
|
|
647
|
-
margin-bottom:
|
|
687
|
+
padding: 0.625rem 0.75rem;
|
|
688
|
+
margin-bottom: 0;
|
|
648
689
|
}
|
|
649
690
|
|
|
650
691
|
.caseNumber {
|
|
651
692
|
margin: 0;
|
|
652
|
-
font-size:
|
|
693
|
+
font-size: 0.95rem;
|
|
653
694
|
font-weight: 600;
|
|
654
695
|
}
|
|
655
696
|
|
|
656
697
|
/* Case Confirmation Status Indicators */
|
|
657
698
|
.caseNumber.caseNotConfirmed {
|
|
658
699
|
background-color: #fffacd;
|
|
659
|
-
padding: 0.75rem;
|
|
700
|
+
padding: 0.625rem 0.75rem;
|
|
660
701
|
border-radius: 4px;
|
|
661
702
|
margin: 0;
|
|
662
703
|
}
|
|
663
704
|
|
|
664
705
|
.caseNumber.caseConfirmed {
|
|
665
706
|
background-color: #c8e6c9;
|
|
666
|
-
padding: 0.75rem;
|
|
707
|
+
padding: 0.625rem 0.75rem;
|
|
667
708
|
border-radius: 4px;
|
|
668
709
|
margin: 0;
|
|
669
710
|
}
|
|
@@ -35,8 +35,9 @@ export const FilesModal = ({ isOpen, onClose, onFileSelect, currentCase, files,
|
|
|
35
35
|
const [deletingFileId, setDeletingFileId] = useState<string | null>(null);
|
|
36
36
|
const [fileConfirmationStatus, setFileConfirmationStatus] = useState<FileConfirmationStatus>({});
|
|
37
37
|
const {
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
requestClose,
|
|
39
|
+
overlayProps,
|
|
40
|
+
getCloseButtonProps
|
|
40
41
|
} = useOverlayDismiss({
|
|
41
42
|
isOpen,
|
|
42
43
|
onClose
|
|
@@ -98,7 +99,7 @@ export const FilesModal = ({ isOpen, onClose, onFileSelect, currentCase, files,
|
|
|
98
99
|
|
|
99
100
|
const handleFileSelect = (file: FileData) => {
|
|
100
101
|
onFileSelect?.(file);
|
|
101
|
-
|
|
102
|
+
requestClose();
|
|
102
103
|
};
|
|
103
104
|
|
|
104
105
|
const handleDeleteFile = async (fileId: string, event: React.MouseEvent) => {
|
|
@@ -116,10 +117,15 @@ export const FilesModal = ({ isOpen, onClose, onFileSelect, currentCase, files,
|
|
|
116
117
|
setDeletingFileId(fileId);
|
|
117
118
|
|
|
118
119
|
try {
|
|
119
|
-
await deleteFile(user, currentCase, fileId);
|
|
120
|
+
const deleteResult = await deleteFile(user, currentCase, fileId);
|
|
120
121
|
// Remove the deleted file from the list
|
|
121
122
|
const updatedFiles = files.filter(f => f.id !== fileId);
|
|
122
123
|
setFiles(updatedFiles);
|
|
124
|
+
|
|
125
|
+
if (deleteResult.imageMissing) {
|
|
126
|
+
setError(`File record deleted. Image asset "${deleteResult.fileName}" was not found and was skipped.`);
|
|
127
|
+
setTimeout(() => setError(null), 4000);
|
|
128
|
+
}
|
|
123
129
|
|
|
124
130
|
// Adjust page if needed
|
|
125
131
|
const newTotalPages = Math.ceil(updatedFiles.length / FILES_PER_PAGE);
|
|
@@ -161,20 +167,13 @@ export const FilesModal = ({ isOpen, onClose, onFileSelect, currentCase, files,
|
|
|
161
167
|
return (
|
|
162
168
|
<div
|
|
163
169
|
className={styles.modalOverlay}
|
|
164
|
-
onMouseDown={handleOverlayMouseDown}
|
|
165
|
-
onKeyDown={handleOverlayKeyDown}
|
|
166
|
-
role="button"
|
|
167
|
-
tabIndex={0}
|
|
168
170
|
aria-label="Close files dialog"
|
|
171
|
+
{...overlayProps}
|
|
169
172
|
>
|
|
170
173
|
<div className={styles.modal}>
|
|
171
174
|
<div className={styles.modalHeader}>
|
|
172
175
|
<h2>Files in Case {currentCase}</h2>
|
|
173
|
-
<button
|
|
174
|
-
className={styles.closeButton}
|
|
175
|
-
onClick={onClose}
|
|
176
|
-
aria-label="Close modal"
|
|
177
|
-
>
|
|
176
|
+
<button className={styles.closeButton} {...getCloseButtonProps({ ariaLabel: 'Close files dialog' })}>
|
|
178
177
|
×
|
|
179
178
|
</button>
|
|
180
179
|
</div>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
.overlay {
|
|
2
|
+
position: fixed;
|
|
3
|
+
inset: 0;
|
|
4
|
+
background-color: color-mix(in lab, var(--background) 56%, transparent);
|
|
5
|
+
display: flex;
|
|
6
|
+
justify-content: center;
|
|
7
|
+
align-items: center;
|
|
8
|
+
z-index: var(--zIndex5);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.modal {
|
|
12
|
+
position: relative;
|
|
13
|
+
width: min(900px, calc(100vw - 2rem));
|
|
14
|
+
max-height: calc(100vh - 4rem);
|
|
15
|
+
background: var(--backgroundLight);
|
|
16
|
+
border-radius: var(--spaceXS);
|
|
17
|
+
box-shadow: 0 var(--spaceXS) var(--spaceL)
|
|
18
|
+
color-mix(in lab, var(--black) 16%, transparent);
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
overflow: hidden;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.header {
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
justify-content: space-between;
|
|
28
|
+
padding: var(--spaceM) var(--spaceL);
|
|
29
|
+
border-bottom: 1px solid color-mix(in lab, var(--text) 12%, transparent);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.title {
|
|
33
|
+
margin: 0;
|
|
34
|
+
color: var(--textTitle);
|
|
35
|
+
font-size: var(--fontSizeBodyM);
|
|
36
|
+
font-weight: var(--fontWeightMedium);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.closeButton {
|
|
40
|
+
background: none;
|
|
41
|
+
border: none;
|
|
42
|
+
color: var(--textLight);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.content {
|
|
46
|
+
padding: var(--spaceM) var(--spaceL);
|
|
47
|
+
overflow-y: auto;
|
|
48
|
+
max-height: calc(100vh - 11rem);
|
|
49
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { User } from 'firebase/auth';
|
|
2
|
+
import { useOverlayDismiss } from '~/hooks/useOverlayDismiss';
|
|
3
|
+
import { NotesSidebar } from './notes-sidebar';
|
|
4
|
+
import styles from './notes-editor-modal.module.css';
|
|
5
|
+
|
|
6
|
+
interface NotesEditorModalProps {
|
|
7
|
+
isOpen: boolean;
|
|
8
|
+
onClose: () => void;
|
|
9
|
+
currentCase: string;
|
|
10
|
+
user: User;
|
|
11
|
+
imageId: string;
|
|
12
|
+
originalFileName?: string;
|
|
13
|
+
onAnnotationRefresh?: () => void;
|
|
14
|
+
isUploading?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const NotesEditorModal = ({
|
|
18
|
+
isOpen,
|
|
19
|
+
onClose,
|
|
20
|
+
currentCase,
|
|
21
|
+
user,
|
|
22
|
+
imageId,
|
|
23
|
+
originalFileName,
|
|
24
|
+
onAnnotationRefresh,
|
|
25
|
+
isUploading = false,
|
|
26
|
+
}: NotesEditorModalProps) => {
|
|
27
|
+
const {
|
|
28
|
+
requestClose,
|
|
29
|
+
overlayProps,
|
|
30
|
+
getCloseButtonProps,
|
|
31
|
+
} = useOverlayDismiss({
|
|
32
|
+
isOpen,
|
|
33
|
+
onClose,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
if (!isOpen) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div className={styles.overlay} aria-label="Close image notes dialog" {...overlayProps}>
|
|
42
|
+
<div className={styles.modal} role="dialog" aria-modal="true" aria-label="Image Notes">
|
|
43
|
+
<div className={styles.header}>
|
|
44
|
+
<h2 className={styles.title}>Image Notes</h2>
|
|
45
|
+
<button className={styles.closeButton} {...getCloseButtonProps({ ariaLabel: 'Close image notes dialog' })}>
|
|
46
|
+
×
|
|
47
|
+
</button>
|
|
48
|
+
</div>
|
|
49
|
+
<div className={styles.content}>
|
|
50
|
+
<NotesSidebar
|
|
51
|
+
currentCase={currentCase}
|
|
52
|
+
onReturn={requestClose}
|
|
53
|
+
user={user}
|
|
54
|
+
imageId={imageId}
|
|
55
|
+
onAnnotationRefresh={onAnnotationRefresh}
|
|
56
|
+
originalFileName={originalFileName}
|
|
57
|
+
isUploading={isUploading}
|
|
58
|
+
showReturnButton={false}
|
|
59
|
+
stickyActionBar={true}
|
|
60
|
+
compactLayout={true}
|
|
61
|
+
/>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
@@ -12,8 +12,9 @@ interface NotesModalProps {
|
|
|
12
12
|
export const NotesModal = ({ isOpen, onClose, notes, onSave }: NotesModalProps) => {
|
|
13
13
|
const [tempNotes, setTempNotes] = useState(notes);
|
|
14
14
|
const {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
requestClose,
|
|
16
|
+
overlayProps,
|
|
17
|
+
getCloseButtonProps
|
|
17
18
|
} = useOverlayDismiss({
|
|
18
19
|
isOpen,
|
|
19
20
|
onClose
|
|
@@ -23,19 +24,17 @@ export const NotesModal = ({ isOpen, onClose, notes, onSave }: NotesModalProps)
|
|
|
23
24
|
|
|
24
25
|
const handleSave = () => {
|
|
25
26
|
onSave(tempNotes);
|
|
26
|
-
|
|
27
|
+
requestClose();
|
|
27
28
|
};
|
|
28
29
|
|
|
29
30
|
return (
|
|
30
31
|
<div
|
|
31
32
|
className={styles.modalOverlay}
|
|
32
|
-
onMouseDown={handleOverlayMouseDown}
|
|
33
|
-
onKeyDown={handleOverlayKeyDown}
|
|
34
|
-
role="button"
|
|
35
|
-
tabIndex={0}
|
|
36
33
|
aria-label="Close notes dialog"
|
|
34
|
+
{...overlayProps}
|
|
37
35
|
>
|
|
38
36
|
<div className={styles.modal}>
|
|
37
|
+
<button {...getCloseButtonProps({ ariaLabel: 'Close notes dialog' })}>×</button>
|
|
39
38
|
<h5 className={styles.modalTitle}>Additional Notes</h5>
|
|
40
39
|
<textarea
|
|
41
40
|
value={tempNotes}
|
|
@@ -45,7 +44,7 @@ export const NotesModal = ({ isOpen, onClose, notes, onSave }: NotesModalProps)
|
|
|
45
44
|
/>
|
|
46
45
|
<div className={styles.modalButtons}>
|
|
47
46
|
<button onClick={handleSave} className={styles.saveButton}>Save</button>
|
|
48
|
-
<button onClick={
|
|
47
|
+
<button onClick={requestClose} className={styles.cancelButton}>Cancel</button>
|
|
49
48
|
</div>
|
|
50
49
|
</div>
|
|
51
50
|
</div>
|