@striae-org/striae 4.1.0 → 4.2.1
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/LICENSE +1 -1
- 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 +463 -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 +12 -2
- 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 +24 -1
- package/app/components/audit/viewer/use-audit-viewer-export.ts +1 -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 +12 -14
- package/app/components/colors/colors.module.css +4 -3
- 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 +402 -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 +68 -588
- package/app/components/sidebar/cases/cases-modal.module.css +1 -0
- package/app/components/sidebar/cases/cases-modal.tsx +82 -43
- package/app/components/sidebar/cases/cases.module.css +82 -21
- package/app/components/sidebar/files/files-modal.module.css +1 -0
- package/app/components/sidebar/files/files-modal.tsx +49 -52
- package/app/components/sidebar/notes/addl-notes-modal.tsx +82 -0
- package/app/components/sidebar/notes/{notes-sidebar.tsx → notes-editor-form.tsx} +187 -138
- package/app/components/sidebar/notes/notes-editor-modal.module.css +49 -0
- package/app/components/sidebar/notes/notes-editor-modal.tsx +64 -0
- package/app/components/sidebar/notes/notes.module.css +170 -1
- package/app/components/sidebar/sidebar-container.tsx +16 -28
- package/app/components/sidebar/sidebar.module.css +5 -69
- package/app/components/sidebar/sidebar.tsx +27 -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/{tailwind.css → global.css} +1 -3
- package/app/hooks/useOverlayDismiss.ts +54 -4
- package/app/root.tsx +1 -1
- package/app/routes/auth/login.tsx +785 -774
- package/app/routes/striae/striae.module.css +10 -3
- package/app/routes/striae/striae.tsx +475 -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 +4 -1
- package/app/types/case.ts +29 -0
- package/app/types/import.ts +3 -0
- package/app/utils/data/confirmation-summary/summary-core.ts +279 -0
- package/app/utils/data/data-operations.ts +17 -861
- package/app/utils/data/index.ts +11 -1
- package/app/utils/data/operations/batch-operations.ts +113 -0
- package/app/utils/data/operations/case-operations.ts +168 -0
- package/app/utils/data/operations/confirmation-summary-operations.ts +301 -0
- package/app/utils/data/operations/file-annotation-operations.ts +196 -0
- package/app/utils/data/operations/index.ts +7 -0
- package/app/utils/data/operations/signing-operations.ts +225 -0
- package/app/utils/data/operations/types.ts +42 -0
- package/app/utils/data/operations/validation-operations.ts +48 -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 +426 -22
- package/functions/api/_shared/firebase-auth.ts +2 -7
- package/functions/api/image/[[path]].ts +20 -23
- package/functions/api/pdf/[[path]].ts +27 -8
- package/package.json +7 -12
- package/scripts/deploy-primershear-emails.sh +2 -1
- package/worker-configuration.d.ts +3 -3
- package/workers/audit-worker/package.json +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/package.json +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/package.json +1 -1
- package/workers/image-worker/src/image-worker.example.ts +16 -5
- package/workers/image-worker/worker-configuration.d.ts +7447 -11322
- package/workers/image-worker/wrangler.jsonc.example +1 -1
- package/workers/keys-worker/package.json +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/package.json +1 -1
- package/workers/pdf-worker/src/formats/format-striae.ts +9 -14
- package/workers/pdf-worker/src/pdf-worker.example.ts +37 -58
- package/workers/pdf-worker/src/report-types.ts +3 -3
- package/workers/pdf-worker/worker-configuration.d.ts +7448 -11323
- package/workers/pdf-worker/wrangler.jsonc.example +1 -1
- package/workers/user-worker/package.json +1 -1
- package/workers/user-worker/src/user-worker.example.ts +17 -0
- 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/NOTICE +0 -13
- package/app/components/sidebar/notes/notes-modal.tsx +0 -53
- package/postcss.config.js +0 -6
- package/public/.well-known/keybase.txt +0 -56
- package/tailwind.config.ts +0 -22
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useState, useEffect } from 'react';
|
|
2
|
+
import { useOverlayDismiss } from '~/hooks/useOverlayDismiss';
|
|
2
3
|
import styles from './inactivity-warning.module.css';
|
|
3
4
|
|
|
4
5
|
interface InactivityWarningProps {
|
|
@@ -15,6 +16,15 @@ export const InactivityWarning = ({
|
|
|
15
16
|
onSignOut
|
|
16
17
|
}: InactivityWarningProps) => {
|
|
17
18
|
const [countdown, setCountdown] = useState(remainingSeconds);
|
|
19
|
+
const {
|
|
20
|
+
requestClose,
|
|
21
|
+
overlayProps,
|
|
22
|
+
getCloseButtonProps,
|
|
23
|
+
} = useOverlayDismiss({
|
|
24
|
+
isOpen,
|
|
25
|
+
onClose: onExtendSession,
|
|
26
|
+
closeOnBackdrop: false,
|
|
27
|
+
});
|
|
18
28
|
|
|
19
29
|
useEffect(() => {
|
|
20
30
|
setCountdown(remainingSeconds);
|
|
@@ -46,8 +56,11 @@ export const InactivityWarning = ({
|
|
|
46
56
|
const seconds = countdown % 60;
|
|
47
57
|
|
|
48
58
|
return (
|
|
49
|
-
<div className={styles.overlay}>
|
|
59
|
+
<div className={styles.overlay} aria-label="Close inactivity warning" {...overlayProps}>
|
|
50
60
|
<div className={styles.modal}>
|
|
61
|
+
<button className={styles.closeButton} {...getCloseButtonProps({ ariaLabel: 'Close inactivity warning' })}>
|
|
62
|
+
×
|
|
63
|
+
</button>
|
|
51
64
|
<div className={styles.header}>
|
|
52
65
|
<h3>Session Timeout Warning</h3>
|
|
53
66
|
</div>
|
|
@@ -66,7 +79,7 @@ export const InactivityWarning = ({
|
|
|
66
79
|
|
|
67
80
|
<div className={styles.actions}>
|
|
68
81
|
<button
|
|
69
|
-
onClick={
|
|
82
|
+
onClick={requestClose}
|
|
70
83
|
className={styles.extendButton}
|
|
71
84
|
>
|
|
72
85
|
Extend Session
|
|
@@ -8,7 +8,8 @@ import { useOverlayDismiss } from '~/hooks/useOverlayDismiss';
|
|
|
8
8
|
import { getUserData, updateUserData } from '~/utils/data';
|
|
9
9
|
import { auditService } from '~/services/audit';
|
|
10
10
|
import { handleAuthError, ERROR_MESSAGES } from '~/services/firebase/errors';
|
|
11
|
-
import { FormField, FormButton
|
|
11
|
+
import { FormField, FormButton } from '../form';
|
|
12
|
+
import { Toast } from '~/components/toast/toast';
|
|
12
13
|
import { MfaPhoneUpdateSection } from './mfa-phone-update';
|
|
13
14
|
import styles from './manage-profile.module.css';
|
|
14
15
|
|
|
@@ -26,8 +27,9 @@ export const ManageProfile = ({ isOpen, onClose }: ManageProfileProps) => {
|
|
|
26
27
|
const [email, setEmail] = useState('');
|
|
27
28
|
const [isLoading, setIsLoading] = useState(false);
|
|
28
29
|
const [isMfaBusy, setIsMfaBusy] = useState(false);
|
|
29
|
-
const [
|
|
30
|
-
const [
|
|
30
|
+
const [showToast, setShowToast] = useState(false);
|
|
31
|
+
const [toastMessage, setToastMessage] = useState('');
|
|
32
|
+
const [toastType, setToastType] = useState<'success' | 'error'>('success');
|
|
31
33
|
const [showResetForm, setShowResetForm] = useState(false);
|
|
32
34
|
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
|
33
35
|
const [showAuditViewer, setShowAuditViewer] = useState(false);
|
|
@@ -80,8 +82,7 @@ export const ManageProfile = ({ isOpen, onClose }: ManageProfileProps) => {
|
|
|
80
82
|
const handleUpdateProfile = async (e: React.FormEvent) => {
|
|
81
83
|
e.preventDefault();
|
|
82
84
|
setIsLoading(true);
|
|
83
|
-
|
|
84
|
-
setSuccess('');
|
|
85
|
+
setShowToast(false);
|
|
85
86
|
|
|
86
87
|
const oldDisplayName = user?.displayName || '';
|
|
87
88
|
const oldBadgeId = initialBadgeId;
|
|
@@ -129,7 +130,12 @@ export const ManageProfile = ({ isOpen, onClose }: ManageProfileProps) => {
|
|
|
129
130
|
|
|
130
131
|
setInitialBadgeId(normalizedBadgeId);
|
|
131
132
|
|
|
132
|
-
|
|
133
|
+
setToastType('success');
|
|
134
|
+
setToastMessage(ERROR_MESSAGES.PROFILE_UPDATED);
|
|
135
|
+
setShowToast(true);
|
|
136
|
+
setTimeout(() => {
|
|
137
|
+
window.location.reload();
|
|
138
|
+
}, 1500);
|
|
133
139
|
} catch (err) {
|
|
134
140
|
const { message } = handleAuthError(err);
|
|
135
141
|
|
|
@@ -157,7 +163,9 @@ export const ManageProfile = ({ isOpen, onClose }: ManageProfileProps) => {
|
|
|
157
163
|
);
|
|
158
164
|
}
|
|
159
165
|
|
|
160
|
-
|
|
166
|
+
setToastType('error');
|
|
167
|
+
setToastMessage(message);
|
|
168
|
+
setShowToast(true);
|
|
161
169
|
} finally {
|
|
162
170
|
setIsLoading(false);
|
|
163
171
|
}
|
|
@@ -193,6 +201,13 @@ export const ManageProfile = ({ isOpen, onClose }: ManageProfileProps) => {
|
|
|
193
201
|
}
|
|
194
202
|
|
|
195
203
|
return (
|
|
204
|
+
<>
|
|
205
|
+
<Toast
|
|
206
|
+
message={toastMessage}
|
|
207
|
+
type={toastType}
|
|
208
|
+
isVisible={showToast}
|
|
209
|
+
onClose={() => setShowToast(false)}
|
|
210
|
+
/>
|
|
196
211
|
<div
|
|
197
212
|
className={styles.modalOverlay}
|
|
198
213
|
onMouseDown={handleOverlayMouseDown}
|
|
@@ -282,9 +297,6 @@ export const ManageProfile = ({ isOpen, onClose }: ManageProfileProps) => {
|
|
|
282
297
|
|
|
283
298
|
<MfaPhoneUpdateSection user={user} isOpen={isOpen} onBusyChange={handleMfaBusyChange} />
|
|
284
299
|
|
|
285
|
-
{error && <FormMessage type="error" message={error} />}
|
|
286
|
-
{success && <FormMessage type="success" message={success} />}
|
|
287
|
-
|
|
288
300
|
<div className={styles.buttonGroup}>
|
|
289
301
|
<FormButton variant="primary" type="submit" isLoading={isLoading} loadingText="Updating...">
|
|
290
302
|
Update Profile
|
|
@@ -302,5 +314,6 @@ export const ManageProfile = ({ isOpen, onClose }: ManageProfileProps) => {
|
|
|
302
314
|
</form>
|
|
303
315
|
</div>
|
|
304
316
|
</div>
|
|
317
|
+
</>
|
|
305
318
|
);
|
|
306
319
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback, useEffect, type KeyboardEventHandler, type MouseEventHandler } from 'react';
|
|
1
|
+
import { useCallback, useEffect, type CSSProperties, type KeyboardEventHandler, type MouseEventHandler } from 'react';
|
|
2
2
|
|
|
3
3
|
interface UseOverlayDismissOptions {
|
|
4
4
|
isOpen: boolean;
|
|
@@ -8,6 +8,30 @@ interface UseOverlayDismissOptions {
|
|
|
8
8
|
closeOnBackdrop?: boolean;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
interface CloseButtonOptions {
|
|
12
|
+
ariaLabel?: string;
|
|
13
|
+
title?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const sharedCloseButtonStyle: CSSProperties = {
|
|
17
|
+
position: 'absolute',
|
|
18
|
+
top: '0.6rem',
|
|
19
|
+
right: '0.6rem',
|
|
20
|
+
width: '1.9rem',
|
|
21
|
+
height: '1.9rem',
|
|
22
|
+
borderRadius: '999px',
|
|
23
|
+
border: '1px solid #d6dce2',
|
|
24
|
+
background: '#f8f9fa',
|
|
25
|
+
color: '#495057',
|
|
26
|
+
fontSize: '1.2rem',
|
|
27
|
+
lineHeight: 1,
|
|
28
|
+
display: 'inline-flex',
|
|
29
|
+
alignItems: 'center',
|
|
30
|
+
justifyContent: 'center',
|
|
31
|
+
cursor: 'pointer',
|
|
32
|
+
zIndex: 1,
|
|
33
|
+
};
|
|
34
|
+
|
|
11
35
|
export const useOverlayDismiss = ({
|
|
12
36
|
isOpen,
|
|
13
37
|
onClose,
|
|
@@ -30,7 +54,8 @@ export const useOverlayDismiss = ({
|
|
|
30
54
|
|
|
31
55
|
const handleEscape = (event: KeyboardEvent) => {
|
|
32
56
|
if (event.key === 'Escape') {
|
|
33
|
-
|
|
57
|
+
event.preventDefault();
|
|
58
|
+
requestClose();
|
|
34
59
|
}
|
|
35
60
|
};
|
|
36
61
|
|
|
@@ -39,7 +64,7 @@ export const useOverlayDismiss = ({
|
|
|
39
64
|
return () => {
|
|
40
65
|
document.removeEventListener('keydown', handleEscape);
|
|
41
66
|
};
|
|
42
|
-
}, [isOpen, closeOnEscape, canDismiss,
|
|
67
|
+
}, [isOpen, closeOnEscape, canDismiss, requestClose]);
|
|
43
68
|
|
|
44
69
|
const handleOverlayMouseDown = useCallback<MouseEventHandler<HTMLDivElement>>((event) => {
|
|
45
70
|
if (!closeOnBackdrop || event.target !== event.currentTarget) {
|
|
@@ -60,9 +85,34 @@ export const useOverlayDismiss = ({
|
|
|
60
85
|
}
|
|
61
86
|
}, [closeOnBackdrop, requestClose]);
|
|
62
87
|
|
|
88
|
+
const isBackdropDismissInteractive = closeOnBackdrop && canDismiss;
|
|
89
|
+
|
|
90
|
+
const overlayProps = {
|
|
91
|
+
role: isBackdropDismissInteractive ? 'button' : 'presentation',
|
|
92
|
+
tabIndex: isBackdropDismissInteractive ? 0 : undefined,
|
|
93
|
+
onMouseDown: isBackdropDismissInteractive ? handleOverlayMouseDown : undefined,
|
|
94
|
+
onKeyDown: isBackdropDismissInteractive ? handleOverlayKeyDown : undefined,
|
|
95
|
+
style: { cursor: 'default' as const },
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const getCloseButtonProps = useCallback((options?: CloseButtonOptions) => {
|
|
99
|
+
const ariaLabel = options?.ariaLabel || 'Close modal';
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
type: 'button' as const,
|
|
103
|
+
onClick: requestClose,
|
|
104
|
+
disabled: !canDismiss,
|
|
105
|
+
'aria-label': ariaLabel,
|
|
106
|
+
title: options?.title || ariaLabel,
|
|
107
|
+
style: sharedCloseButtonStyle,
|
|
108
|
+
};
|
|
109
|
+
}, [requestClose, canDismiss]);
|
|
110
|
+
|
|
63
111
|
return {
|
|
64
112
|
requestClose,
|
|
65
113
|
handleOverlayMouseDown,
|
|
66
|
-
handleOverlayKeyDown
|
|
114
|
+
handleOverlayKeyDown,
|
|
115
|
+
overlayProps,
|
|
116
|
+
getCloseButtonProps,
|
|
67
117
|
};
|
|
68
118
|
};
|
package/app/root.tsx
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
import { AuthProvider } from '~/components/auth/auth-provider';
|
|
17
17
|
import { auth } from '~/services/firebase';
|
|
18
18
|
import styles from '~/styles/root.module.css';
|
|
19
|
-
import './
|
|
19
|
+
import './global.css';
|
|
20
20
|
|
|
21
21
|
export const links: LinksFunction = () => [
|
|
22
22
|
{ rel: "preconnect", href: "https://fonts.googleapis.com" },
|