@rivm-loculus-tools/common-frontend 0.1.3 → 0.1.4

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 (126) hide show
  1. package/dist/_chunks/FastaDataImportDialog.js +309 -0
  2. package/dist/_chunks/FastaDataImportDialog.js.map +1 -0
  3. package/dist/_chunks/react.js +11 -0
  4. package/dist/_chunks/react.js.map +1 -0
  5. package/dist/classes/services/FastaDataEventBusService/FastaDataEventBusService.d.ts +10 -0
  6. package/dist/classes/services/FastaDataEventBusService/index.js +16 -0
  7. package/dist/classes/services/FastaDataEventBusService/index.js.map +1 -0
  8. package/dist/components/FastaDataImportDialog/FastaDataImportDialog.d.ts +12 -0
  9. package/dist/components/FastaDataImportDialog/index.js +2 -0
  10. package/dist/components/FastaDataImportDialogLoader/FastaDataImportDialogLoader.d.ts +8 -0
  11. package/dist/components/FastaDataImportDialogLoader/index.js +70 -0
  12. package/dist/components/FastaDataImportDialogLoader/index.js.map +1 -0
  13. package/dist/components/FastaNotLoaded/FastaNotLoaded.d.ts +7 -0
  14. package/dist/components/FastaNotLoaded/index.js +53 -0
  15. package/dist/components/FastaNotLoaded/index.js.map +1 -0
  16. package/dist/components/FastaPageHeaderCenterComponent/FastaPageHeaderCenterComponent.d.ts +6 -0
  17. package/dist/components/FastaPageHeaderCenterComponent/index.js +37 -0
  18. package/dist/components/FastaPageHeaderCenterComponent/index.js.map +1 -0
  19. package/dist/components/FastaPageHeaderImportButton/FastaPageHeaderImportButton.d.ts +1 -0
  20. package/dist/components/FastaPageHeaderImportButton/index.js +26 -0
  21. package/dist/components/FastaPageHeaderImportButton/index.js.map +1 -0
  22. package/dist/components/FastaPageHeaderResetButton/FastaPageHeaderResetButton.d.ts +4 -0
  23. package/dist/components/FastaPageHeaderResetButton/index.js +35 -0
  24. package/dist/components/FastaPageHeaderResetButton/index.js.map +1 -0
  25. package/dist/components/I18nWrapper/I18nWrapper.d.ts +4 -0
  26. package/dist/components/I18nWrapper/index.js +21 -0
  27. package/dist/components/I18nWrapper/index.js.map +1 -0
  28. package/dist/components/PageHeaderDocumentationButton/PageHeaderDocumentationButton.d.ts +1 -0
  29. package/dist/components/PageHeaderDocumentationButton/index.js +24 -0
  30. package/dist/components/PageHeaderDocumentationButton/index.js.map +1 -0
  31. package/dist/components/SearchBar/SearchBar.d.ts +10 -0
  32. package/dist/components/SearchBar/SearchBarNodeCounter.d.ts +4 -0
  33. package/dist/components/SearchBar/index.js +129 -0
  34. package/dist/components/SearchBar/index.js.map +1 -0
  35. package/dist/components/page/ErrorPageCommon.d.ts +4 -0
  36. package/dist/components/page/PageCommon.d.ts +8 -0
  37. package/dist/components/page/PageCommonContext.d.ts +7 -0
  38. package/dist/components/page/PageCommonContextProvider.d.ts +3 -0
  39. package/dist/components/page/PageCommonDrawer.d.ts +5 -0
  40. package/dist/components/page/PageCommonHeader.d.ts +8 -0
  41. package/dist/components/page/index.js +207 -0
  42. package/dist/components/page/index.js.map +1 -0
  43. package/dist/constants/page.d.ts +1 -0
  44. package/dist/constants/page.js +6 -0
  45. package/dist/constants/page.js.map +1 -0
  46. package/dist/models/fasta.d.ts +23 -0
  47. package/dist/models/fasta.js +8 -0
  48. package/dist/models/fasta.js.map +1 -0
  49. package/dist/models/metadata.d.ts +9 -0
  50. package/dist/stores/fastaDataStore/fastaDataStore.d.ts +32 -0
  51. package/dist/stores/fastaDataStore/index.js +57 -0
  52. package/dist/stores/fastaDataStore/index.js.map +1 -0
  53. package/dist/theme/index.js +257 -0
  54. package/dist/theme/index.js.map +1 -0
  55. package/dist/theme/theme.d.ts +1 -0
  56. package/dist/utils/DownloadUtil/DownloadUtil.d.ts +3 -0
  57. package/dist/utils/DownloadUtil/index.js +10 -0
  58. package/dist/utils/DownloadUtil/index.js.map +1 -0
  59. package/dist/utils/ErrorUtil/ErrorUtil.d.ts +3 -0
  60. package/dist/utils/ErrorUtil/index.js +10 -0
  61. package/dist/utils/ErrorUtil/index.js.map +1 -0
  62. package/dist/utils/FastaUtil/FastaUtil.d.ts +6 -0
  63. package/dist/utils/FastaUtil/index.js +63 -0
  64. package/dist/utils/FastaUtil/index.js.map +1 -0
  65. package/dist/utils/MetaDataUtil/MetaDataUtil.d.ts +20 -0
  66. package/dist/utils/MetaDataUtil/index.js +133 -0
  67. package/dist/utils/MetaDataUtil/index.js.map +1 -0
  68. package/dist/utils/UrlUtil/UrlUtil.d.ts +5 -0
  69. package/dist/utils/UrlUtil/index.js +30 -0
  70. package/dist/utils/UrlUtil/index.js.map +1 -0
  71. package/package.json +6 -7
  72. package/CHANGELOG.md +0 -29
  73. package/eslint.config.js +0 -16
  74. package/scripts/update-exports.js +0 -9
  75. package/src/classes/services/FastaDataEventBusService/FastaDataEventBusService.ts +0 -22
  76. package/src/components/FastaDataImportDialog/FastaDataImportDialog.tsx +0 -364
  77. package/src/components/FastaDataImportDialogLoader/FastaDataImportDialogLoader.tsx +0 -124
  78. package/src/components/FastaNotLoaded/FastaNotLoaded.tsx +0 -62
  79. package/src/components/FastaPageHeaderCenterComponent/FastaPageHeaderCenterComponent.tsx +0 -50
  80. package/src/components/FastaPageHeaderImportButton/FastaPageHeaderImportButton.tsx +0 -28
  81. package/src/components/FastaPageHeaderResetButton/FastaPageHeaderResetButton.tsx +0 -50
  82. package/src/components/I18nWrapper/I18nWrapper.tsx +0 -39
  83. package/src/components/PageHeaderDocumentationButton/PageHeaderDocumentationButton.tsx +0 -25
  84. package/src/components/SearchBar/SearchBar.tsx +0 -207
  85. package/src/components/SearchBar/SearchBarNodeCounter.tsx +0 -23
  86. package/src/components/page/ErrorPageCommon.tsx +0 -51
  87. package/src/components/page/PageCommon.tsx +0 -76
  88. package/src/components/page/PageCommonContext.ts +0 -15
  89. package/src/components/page/PageCommonContextProvider.tsx +0 -30
  90. package/src/components/page/PageCommonDrawer.tsx +0 -35
  91. package/src/components/page/PageCommonHeader.tsx +0 -99
  92. package/src/constants/page.ts +0 -1
  93. package/src/index.ts +0 -21
  94. package/src/models/fasta.ts +0 -22
  95. package/src/models/metadata.ts +0 -10
  96. package/src/stores/fastaDataStore/fastaDataStore.ts +0 -103
  97. package/src/theme/fonts/RobotoFlex.woff2 +0 -0
  98. package/src/theme/theme.ts +0 -368
  99. package/src/utils/DownloadUtil/DownloadUtil.ts +0 -10
  100. package/src/utils/ErrorUtil/ErrorUtil.ts +0 -5
  101. package/src/utils/FastaUtil/FastaUtil.ts +0 -109
  102. package/src/utils/MetaDataUtil/MetaDataUtil.ts +0 -292
  103. package/src/utils/UrlUtil/UrlUtil.ts +0 -35
  104. package/tsconfig.build.json +0 -14
  105. package/tsconfig.json +0 -32
  106. package/vite.config.ts +0 -137
  107. /package/{src → dist}/@types/vite-env.d.ts +0 -0
  108. /package/{src/classes/services/FastaDataEventBusService/index.ts → dist/classes/services/FastaDataEventBusService/index.d.ts} +0 -0
  109. /package/{src/components/FastaDataImportDialog/index.ts → dist/components/FastaDataImportDialog/index.d.ts} +0 -0
  110. /package/{src/components/FastaDataImportDialogLoader/index.ts → dist/components/FastaDataImportDialogLoader/index.d.ts} +0 -0
  111. /package/{src/components/FastaNotLoaded/index.ts → dist/components/FastaNotLoaded/index.d.ts} +0 -0
  112. /package/{src/components/FastaPageHeaderCenterComponent/index.ts → dist/components/FastaPageHeaderCenterComponent/index.d.ts} +0 -0
  113. /package/{src/components/FastaPageHeaderImportButton/index.ts → dist/components/FastaPageHeaderImportButton/index.d.ts} +0 -0
  114. /package/{src/components/FastaPageHeaderResetButton/index.ts → dist/components/FastaPageHeaderResetButton/index.d.ts} +0 -0
  115. /package/{src/components/I18nWrapper/index.ts → dist/components/I18nWrapper/index.d.ts} +0 -0
  116. /package/{src/components/PageHeaderDocumentationButton/index.ts → dist/components/PageHeaderDocumentationButton/index.d.ts} +0 -0
  117. /package/{src/components/SearchBar/index.ts → dist/components/SearchBar/index.d.ts} +0 -0
  118. /package/{src/components/page/index.ts → dist/components/page/index.d.ts} +0 -0
  119. /package/{src/.gitkeep → dist/models/metadata.js} +0 -0
  120. /package/{src/stores/fastaDataStore/index.ts → dist/stores/fastaDataStore/index.d.ts} +0 -0
  121. /package/{src/theme/index.ts → dist/theme/index.d.ts} +0 -0
  122. /package/{src/utils/DownloadUtil/index.ts → dist/utils/DownloadUtil/index.d.ts} +0 -0
  123. /package/{src/utils/ErrorUtil/index.ts → dist/utils/ErrorUtil/index.d.ts} +0 -0
  124. /package/{src/utils/FastaUtil/index.ts → dist/utils/FastaUtil/index.d.ts} +0 -0
  125. /package/{src/utils/MetaDataUtil/index.ts → dist/utils/MetaDataUtil/index.d.ts} +0 -0
  126. /package/{src/utils/UrlUtil/index.ts → dist/utils/UrlUtil/index.d.ts} +0 -0
@@ -1,364 +0,0 @@
1
- import type {
2
- ChangeEvent,
3
- ReactElement,
4
- SyntheticEvent,
5
- } from 'react';
6
- import {
7
- useCallback,
8
- useEffect,
9
- useState,
10
- } from 'react';
11
- import {
12
- Alert,
13
- Box,
14
- CircularProgress,
15
- Paper,
16
- Tab,
17
- Tabs,
18
- TextField,
19
- Typography,
20
- } from '@mui/material';
21
- import DnaIcon from '@mui/icons-material/Biotech';
22
- import TableChartIcon from '@mui/icons-material/TableChart';
23
- import { FileDropZone } from '@gen-epix/ui-core-components/components/FileDropZone';
24
- import type {
25
- WithDialogRefMethods,
26
- WithDialogRenderProps,
27
- } from '@gen-epix/ui-core-components/hoc/withDialog';
28
- import { withDialog } from '@gen-epix/ui-core-components/hoc/withDialog';
29
- import type { DialogAction } from '@gen-epix/ui-core-components/components/Dialog';
30
-
31
-
32
- enum FASTA_TAB {
33
- DROP = 0,
34
- URL = 1,
35
- PASTE = 2,
36
- }
37
-
38
- enum META_DATA_TAB {
39
- DROP = 0,
40
- URL = 1,
41
- PASTE = 2,
42
- }
43
-
44
- export interface FastaDataImportDialogOpenProps {
45
- initialErrorMessage?: string;
46
- }
47
-
48
- export interface FastaDataImportDialogProps extends WithDialogRenderProps<FastaDataImportDialogOpenProps> {
49
- extraActions?: DialogAction[];
50
- onDataChange: (fasta: string, metaData?: string) => void;
51
- onError: (error: unknown) => void;
52
- }
53
-
54
- export type FastaDataImportDialogRefMethods = WithDialogRefMethods<FastaDataImportDialogProps, FastaDataImportDialogOpenProps>;
55
-
56
- export const FastaDataImportDialog = withDialog<FastaDataImportDialogProps, FastaDataImportDialogOpenProps>((
57
- {
58
- extraActions,
59
- onActionsChange,
60
- onClose,
61
- onDataChange,
62
- onDisableBackdropClickChange,
63
- onError,
64
- onNoCloseButtonChange,
65
- openProps,
66
- }: FastaDataImportDialogProps,
67
- ): ReactElement => {
68
- // FASTA state
69
- const [fastaTab, setFastaTab] = useState(FASTA_TAB.DROP);
70
- const [fastaFile, setFastaFile] = useState<FileList | null>(null);
71
- const [fastaUrl, setFastaUrl] = useState('');
72
- const [fastaText, setFastaText] = useState('');
73
-
74
- // Metadata state
75
- const [metadataTab, setMetadataTab] = useState(META_DATA_TAB.DROP);
76
- const [metadataFile, setMetadataFile] = useState<FileList | null>(null);
77
- const [metadataUrl, setMetadataUrl] = useState('');
78
- const [metadataText, setMetadataText] = useState('');
79
-
80
- const [isLoading, setIsLoading] = useState(false);
81
- const [errorMsg, setErrorMsg] = useState<null | string>(null);
82
-
83
- useEffect(() => {
84
- setErrorMsg(openProps?.initialErrorMessage ?? null);
85
- }, [openProps]);
86
-
87
- useEffect(() => {
88
- if (onNoCloseButtonChange) {
89
- onNoCloseButtonChange(!!openProps?.initialErrorMessage);
90
- }
91
- if (onDisableBackdropClickChange) {
92
- onDisableBackdropClickChange(!!openProps?.initialErrorMessage);
93
- }
94
- }, [onDisableBackdropClickChange, onNoCloseButtonChange, openProps?.initialErrorMessage]);
95
-
96
- const onCloseError = useCallback(() => setErrorMsg(null), []);
97
- const onChangeFastaTab = useCallback((_event: SyntheticEvent, value: number) => {
98
- setFastaTab(value);
99
- }, []);
100
- const onChangeMetadataTab = useCallback((_event: SyntheticEvent, value: number) => {
101
- setMetadataTab(value);
102
- }, []);
103
- const onFileSelectedFasta = useCallback((file: FileList) => setFastaFile(file), []);
104
- const onFileSelectedMetadata = useCallback((file: FileList) => setMetadataFile(file), []);
105
- const onChangeFastaUrl = useCallback((event: ChangeEvent<HTMLInputElement>) => {
106
- setFastaUrl(event.target.value);
107
- }, []);
108
- const onChangeFastaText = useCallback((event: ChangeEvent<HTMLInputElement>) => {
109
- setFastaText(event.target.value);
110
- }, []);
111
- const onChangeMetadataUrl = useCallback((event: ChangeEvent<HTMLInputElement>) => {
112
- setMetadataUrl(event.target.value);
113
- }, []);
114
- const onChangeMetadataText = useCallback((event: ChangeEvent<HTMLInputElement>) => {
115
- setMetadataText(event.target.value);
116
- }, []);
117
-
118
- const onClickLoadData = useCallback(async () => {
119
- setErrorMsg(null);
120
- setIsLoading(true);
121
-
122
- try {
123
- // 1. Resolve FASTA content
124
- let fastaContent = '';
125
- if (fastaTab === FASTA_TAB.DROP && fastaFile) {
126
- fastaContent = await fastaFile[0].text();
127
- } else if (fastaTab === FASTA_TAB.URL && fastaUrl.trim()) {
128
- const res = await fetch(fastaUrl.trim());
129
- if (!res.ok) {
130
- throw new Error(`Failed to fetch FASTA from URL (${res.status} ${res.statusText})`);
131
- }
132
- fastaContent = await res.text();
133
- } else if (fastaTab === FASTA_TAB.PASTE && fastaText.trim()) {
134
- fastaContent = fastaText.trim();
135
- }
136
-
137
- if (!fastaContent?.trim()) {
138
- throw new Error('Please provide FASTA sequence data via file, URL, or paste.');
139
- }
140
-
141
- // 2. Resolve Metadata content (optional)
142
- let metadataContent = '';
143
- if (metadataTab === META_DATA_TAB.DROP && metadataFile) {
144
- metadataContent = await metadataFile[0].text();
145
- } else if (metadataTab === META_DATA_TAB.URL && metadataUrl.trim()) {
146
- const res = await fetch(metadataUrl.trim());
147
- if (!res.ok) {
148
- throw new Error(`Failed to fetch Metadata from URL (${res.status} ${res.statusText})`);
149
- }
150
- metadataContent = await res.text();
151
- } else if (metadataTab === META_DATA_TAB.PASTE && metadataText.trim()) {
152
- metadataContent = metadataText.trim();
153
- }
154
- onDataChange(fastaContent, metadataContent);
155
- if (onClose) {
156
- onClose();
157
- }
158
- } catch (err: unknown) {
159
- console.error('Data import failed:', err);
160
- onError(err);
161
- } finally {
162
- setIsLoading(false);
163
- }
164
- }, [fastaFile, fastaTab, fastaText, fastaUrl, metadataFile, metadataTab, metadataText, metadataUrl, onClose, onDataChange, onError]);
165
-
166
-
167
- useEffect(() => {
168
- const actions: DialogAction[] = [
169
- {
170
- disabled: isLoading,
171
- label: isLoading ? 'Processing...' : 'Load & Calculate',
172
- onClick: onClickLoadData,
173
- startIcon: isLoading ? (
174
- <CircularProgress
175
- color={'inherit'}
176
- size={18}
177
- />
178
- ) : undefined,
179
- variant: 'contained',
180
- },
181
- ];
182
- if (extraActions?.length) {
183
- actions.unshift(...extraActions);
184
- }
185
- if (onActionsChange) {
186
- onActionsChange(actions);
187
- }
188
- }, [onActionsChange, onClickLoadData, isLoading, extraActions]);
189
-
190
- return (
191
- <>
192
- {errorMsg && (
193
- <Alert
194
- onClose={onCloseError}
195
- severity={'error'}
196
- sx={{
197
- marginBottom: 2,
198
- }}
199
- >
200
- {errorMsg}
201
- </Alert>
202
- )}
203
- <Box sx={{ display: 'grid', gap: 3, gridTemplateColumns: { md: '1fr 1fr', xs: '1fr' } }}>
204
- {/* FASTA Sequences Group */}
205
- <Paper
206
- sx={{ borderRadius: 2, p: 2.5 }}
207
- variant={'outlined'}
208
- >
209
- <Box sx={{ alignItems: 'center', display: 'flex', gap: 1, mb: 1.5 }}>
210
- <DnaIcon color={'primary'} />
211
- <Typography
212
- sx={{ fontWeight: 700 }}
213
- variant={'subtitle1'}
214
- >
215
- {'1. FASTA Sequences (Required)'}
216
- </Typography>
217
- </Box>
218
- <Typography
219
- color={'text.secondary'}
220
- sx={{ display: 'block', mb: 2 }}
221
- variant={'caption'}
222
- >
223
- {'Pre-aligned nucleotide or amino-acid sequence data.'}
224
- </Typography>
225
- <Tabs
226
- onChange={onChangeFastaTab}
227
- sx={{ mb: 2, minHeight: 36 }}
228
- value={fastaTab}
229
- >
230
- <Tab
231
- label={'File Upload'}
232
- sx={{ fontSize: '0.85rem', py: 0.5 }}
233
- />
234
- <Tab
235
- label={'Public URL'}
236
- sx={{ fontSize: '0.85rem', py: 0.5 }}
237
- />
238
- <Tab
239
- label={'Direct Paste'}
240
- sx={{ fontSize: '0.85rem', py: 0.5 }}
241
- />
242
- </Tabs>
243
- {fastaTab === FASTA_TAB.DROP && (
244
- <FileDropZone
245
- accept={'.fasta,.fa,.fna,.aln'}
246
- files={fastaFile}
247
- helperText={'Drag & drop .fasta / .fa alignment file'}
248
- onFilesSelected={onFileSelectedFasta}
249
- />
250
- )}
251
- {fastaTab === FASTA_TAB.URL && (
252
- <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5, justifyContent: 'center', minHeight: 180 }}>
253
- <TextField
254
- fullWidth
255
- helperText={'Enter a publicly accessible URL to a FASTA alignment'}
256
- label={'FASTA URL'}
257
- onChange={onChangeFastaUrl}
258
- placeholder={'https://example.com/sequences.fasta'}
259
- value={fastaUrl}
260
- variant={'outlined'}
261
- />
262
- </Box>
263
- )}
264
- {fastaTab === FASTA_TAB.PASTE && (
265
- <Box sx={{ minHeight: 180 }}>
266
- <TextField
267
- fullWidth
268
- label={'Paste FASTA Content'}
269
- multiline
270
- onChange={onChangeFastaText}
271
- placeholder={'>seq1&#10;ACTG...&#10;>seq2&#10;ACTG...'}
272
- rows={6}
273
- sx={{ fontFamily: 'monospace' }}
274
- value={fastaText}
275
- variant={'outlined'}
276
- />
277
- </Box>
278
- )}
279
- </Paper>
280
- {/* TSV Metadata Group */}
281
- <Paper
282
- sx={{ borderRadius: 2, p: 2.5 }}
283
- variant={'outlined'}
284
- >
285
- <Box sx={{ alignItems: 'center', display: 'flex', gap: 1, mb: 1.5 }}>
286
- <TableChartIcon color={'primary'} />
287
- <Typography
288
- sx={{ fontWeight: 700 }}
289
- variant={'subtitle1'}
290
- >
291
- {'2. TSV Metadata (Optional)'}
292
- </Typography>
293
- </Box>
294
- <Typography
295
- color={'text.primary'}
296
- sx={{ display: 'block', mb: 2 }}
297
- variant={'caption'}
298
- >
299
- {'Sample attributes for coloring, search & custom leaf labels.'}
300
- </Typography>
301
- <Tabs
302
- onChange={onChangeMetadataTab}
303
- sx={{ mb: 2, minHeight: 36 }}
304
- value={metadataTab}
305
- >
306
- <Tab
307
- label={'File Upload'}
308
- sx={{ fontSize: '0.85rem', py: 0.5 }}
309
- />
310
- <Tab
311
- label={'Public URL'}
312
- sx={{ fontSize: '0.85rem', py: 0.5 }}
313
- />
314
- <Tab
315
- label={'Direct Paste'}
316
- sx={{ fontSize: '0.85rem', py: 0.5 }}
317
- />
318
- </Tabs>
319
- {metadataTab === META_DATA_TAB.DROP && (
320
- <FileDropZone
321
- accept={'.tsv,.txt,.csv'}
322
- files={metadataFile}
323
- label={'TSV Metadata File'}
324
- onFilesSelected={onFileSelectedMetadata}
325
- />
326
- )}
327
- {metadataTab === META_DATA_TAB.URL && (
328
- <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5, justifyContent: 'center', minHeight: 180 }}>
329
- <TextField
330
- fullWidth
331
- helperText={'Enter a publicly accessible URL to a TSV metadata file'}
332
- label={'Metadata TSV URL'}
333
- onChange={onChangeMetadataUrl}
334
- placeholder={'https://example.com/metadata.tsv'}
335
- value={metadataUrl}
336
- variant={'outlined'}
337
- />
338
- </Box>
339
- )}
340
- {metadataTab === META_DATA_TAB.PASTE && (
341
- <Box sx={{ minHeight: 180 }}>
342
- <TextField
343
- fullWidth
344
- label={'Paste TSV Content'}
345
- multiline
346
- onChange={onChangeMetadataText}
347
- placeholder={'SampleID&#9;Country&#9;Date&#10;Sample1&#9;NL&#9;2024-01-01'}
348
- rows={6}
349
- sx={{ fontFamily: 'monospace' }}
350
- value={metadataText}
351
- variant={'outlined'}
352
- />
353
- </Box>
354
- )}
355
- </Paper>
356
- </Box>
357
- </>
358
- );
359
- }, {
360
- defaultTitle: 'Load Phylogenetic Data',
361
- fullWidth: true,
362
- maxWidth: 'xl',
363
- testId: 'FastaDataImportDialog',
364
- });
@@ -1,124 +0,0 @@
1
- import type { DialogAction } from '@gen-epix/ui-core-components/components/Dialog';
2
- import {
3
- useCallback,
4
- useEffect,
5
- useRef,
6
- } from 'react';
7
- import type { StoreApi } from 'zustand';
8
- import { useStore } from 'zustand';
9
-
10
- import { FastaDataEventBusService } from '../../classes/services/FastaDataEventBusService';
11
- import { LOADING_STATUS } from '../../models/fasta';
12
- import type { FastaDataStore } from '../../stores/fastaDataStore';
13
- import { UrlUtil } from '../../utils/UrlUtil';
14
- import type { FastaDataImportDialogRefMethods } from '../FastaDataImportDialog/FastaDataImportDialog';
15
- import { FastaDataImportDialog } from '../FastaDataImportDialog/FastaDataImportDialog';
16
- import { ErrorUtil } from '../../utils/ErrorUtil';
17
-
18
-
19
- export type FastaDataImportDialogLoaderProps = {
20
- extraActions: DialogAction[];
21
- store: StoreApi<FastaDataStore>;
22
- };
23
-
24
- export const FastaDataImportDialogLoader = ({ extraActions, store }: FastaDataImportDialogLoaderProps) => {
25
- const setData = useStore(store, (state) => state.setData);
26
- const setLoadingStatus = useStore(store, (state) => state.setLoadingStatus);
27
- const fastaDataImportDialogRef = useRef<FastaDataImportDialogRefMethods>(null);
28
-
29
- useEffect(() => {
30
- const removers = [
31
- // eslint-disable-next-line @eslint-react/web-api-no-leaked-event-listener
32
- FastaDataEventBusService.getInstance().addEventListener('onShowImportDialog', (initialErrorMessage?: string) => {
33
- fastaDataImportDialogRef.current?.open(initialErrorMessage ? { initialErrorMessage } : undefined);
34
- }),
35
- // eslint-disable-next-line @eslint-react/web-api-no-leaked-event-listener
36
- FastaDataEventBusService.getInstance().addEventListener('onCloseImportDialog', () => {
37
- fastaDataImportDialogRef.current?.close();
38
- }),
39
- ];
40
- return () => {
41
- removers.forEach((remove) => remove());
42
- };
43
- }, []);
44
-
45
- useEffect(() => {
46
- // Scan URL parameters for deep-linking
47
- const urlParams = new URLSearchParams(window.location.search);
48
- const inputFastaUrl = urlParams.get('input-fasta');
49
- const inputMetadataUrl = urlParams.get('input-metadata');
50
-
51
- const handleDeepLinking = async () => {
52
- if (inputFastaUrl) {
53
- setLoadingStatus(LOADING_STATUS.LOADING);
54
- try {
55
- const fastaRes = await fetch(inputFastaUrl);
56
- if (!fastaRes.ok) {
57
- throw new Error(`FASTA fetch failed (${fastaRes.status})`);
58
- }
59
- const fastaText = await fastaRes.text();
60
-
61
- if (!fastaText.trim()) {
62
- setLoadingStatus(LOADING_STATUS.ERROR);
63
- throw new Error('The input-fasta URL returned no sequence data. Check that the URL and requested accession(s) are correct.');
64
- }
65
-
66
- let metaText: string | undefined;
67
- if (inputMetadataUrl) {
68
- try {
69
- const metaRes = await fetch(inputMetadataUrl);
70
- if (metaRes.ok) {
71
- metaText = await metaRes.text();
72
- }
73
- } catch (metaErr) {
74
- console.warn('[App] Failed to auto-fetch metadata:', metaErr);
75
- }
76
- }
77
-
78
- await setData(fastaText, metaText);
79
- } catch (fastaErr) {
80
- console.error('[App] Failed to auto-load FASTA:', fastaErr);
81
- const message = fastaErr instanceof Error ? fastaErr.message : 'Failed to auto-load FASTA from the provided URL.';
82
- FastaDataEventBusService.getInstance().emit('onShowImportDialog', message);
83
- }
84
- } else {
85
- // PV1-02: Show data loading modal if no data provided via URL query params
86
- FastaDataEventBusService.getInstance().emit('onShowImportDialog');
87
- }
88
- };
89
-
90
- void handleDeepLinking();
91
- }, [setData, setLoadingStatus]);
92
-
93
- const handleError = useCallback((errorMessage: string) => {
94
- fastaDataImportDialogRef.current?.close();
95
- FastaDataEventBusService.getInstance().emit('onShowImportDialog', errorMessage);
96
- }, []);
97
-
98
- const onDataChange = useCallback(async (fastaContent: string, metadataContent?: string) => {
99
- try {
100
- await setData(fastaContent, metadataContent);
101
- fastaDataImportDialogRef.current?.close();
102
- } catch (e) {
103
- handleError(ErrorUtil.getErrorMessage(e, 'Unknown error'));
104
- } finally {
105
- // clear any search params from the URL
106
- UrlUtil.clearSearchParams();
107
- }
108
- }, [handleError, setData]);
109
-
110
- const onError = useCallback((errorMessage: unknown) => {
111
- handleError(ErrorUtil.getErrorMessage(errorMessage, 'Unknown error'));
112
- }, [handleError]);
113
-
114
- return (
115
- <>
116
- <FastaDataImportDialog
117
- extraActions={extraActions}
118
- onDataChange={onDataChange}
119
- onError={onError}
120
- ref={fastaDataImportDialogRef}
121
- />
122
- </>
123
- );
124
- };
@@ -1,62 +0,0 @@
1
- import {
2
- Box,
3
- Button,
4
- Typography,
5
- } from '@mui/material';
6
- import FileUploadOutlinedIcon from '@mui/icons-material/FileUploadOutlined';
7
- import type { ReactNode } from 'react';
8
- import { useCallback } from 'react';
9
-
10
- import { FastaDataEventBusService } from '../../classes/services/FastaDataEventBusService';
11
-
12
- export type FastaNotLoadedProps = {
13
- description: ReactNode;
14
- icon: ReactNode;
15
- title: ReactNode;
16
- };
17
-
18
- export const FastaNotLoaded = ({ description, icon, title }: FastaNotLoadedProps) => {
19
- const onClickLoadData = useCallback(() => {
20
- FastaDataEventBusService.getInstance().emit('onShowImportDialog');
21
- }, []);
22
-
23
- return (
24
- <Box
25
- sx={{
26
- alignItems: 'center',
27
- display: 'flex',
28
- flexDirection: 'column',
29
- gap: 2,
30
- height: '100%',
31
- justifyContent: 'center',
32
- p: 3,
33
- width: '100%',
34
- }}
35
- >
36
- {icon}
37
- <Typography
38
- color={'text.secondary'}
39
- sx={{ fontWeight: 600 }}
40
- variant={'h6'}
41
- >
42
- {title}
43
- </Typography>
44
- <Typography
45
- color={'text.secondary'}
46
- sx={{ maxWidth: 450, textAlign: 'center' }}
47
- variant={'body2'}
48
- >
49
- {description}
50
- </Typography>
51
- <Button
52
- color={'primary'}
53
- onClick={onClickLoadData}
54
- startIcon={<FileUploadOutlinedIcon />}
55
- sx={{ mt: 1 }}
56
- variant={'contained'}
57
- >
58
- {'Load Data'}
59
- </Button>
60
- </Box>
61
- );
62
- };
@@ -1,50 +0,0 @@
1
- import {
2
- Box,
3
- Chip,
4
- } from '@mui/material';
5
- import type { StoreApi } from 'zustand';
6
- import { useStore } from 'zustand';
7
-
8
- import type { FastaDataStore } from '../../stores/fastaDataStore';
9
-
10
-
11
- export type FastaPageHeaderCenterComponentProps = {
12
- store: StoreApi<FastaDataStore>;
13
- };
14
-
15
- export const FastaPageHeaderCenterComponent = ({ store }: FastaPageHeaderCenterComponentProps) => {
16
- const parsedFasta = useStore(store, (state) => state.parsedFasta);
17
- const parsedMetadata = useStore(store, (state) => state.parsedMetadata);
18
-
19
- const seqCount = parsedFasta?.sequences?.length || 0;
20
- const metaCount = parsedMetadata?.records?.length || 0;
21
-
22
- return (
23
- <Box sx={{ alignItems: 'center', display: 'flex', gap: 1 }}>
24
- {seqCount > 0 && (
25
- <Chip
26
- label={`${seqCount} Sequences`}
27
- size={'small'}
28
- sx={{
29
- backgroundColor: 'rgba(255, 255, 255, 0.2)',
30
- color: '#FFFFFF',
31
- fontSize: '0.75rem',
32
- fontWeight: 600,
33
- }}
34
- />
35
- )}
36
- {metaCount > 0 && (
37
- <Chip
38
- label={`${metaCount} Metadata Records`}
39
- size={'small'}
40
- sx={{
41
- backgroundColor: 'rgba(255, 255, 255, 0.2)',
42
- color: '#FFFFFF',
43
- fontSize: '0.75rem',
44
- fontWeight: 600,
45
- }}
46
- />
47
- )}
48
- </Box>
49
- );
50
- };
@@ -1,28 +0,0 @@
1
- import FileUploadOutlinedIcon from '@mui/icons-material/FileUploadOutlined';
2
- import { Button } from '@mui/material';
3
- import { useCallback } from 'react';
4
-
5
- import { FastaDataEventBusService } from '../../classes/services/FastaDataEventBusService';
6
-
7
- export const FastaPageHeaderImportButton = () => {
8
- const onImportDataButtonClick = useCallback(() => FastaDataEventBusService.getInstance().emit('onShowImportDialog'), []);
9
-
10
- return (
11
- <Button
12
- color={'inherit'}
13
- onClick={onImportDataButtonClick}
14
- size={'small'}
15
- startIcon={<FileUploadOutlinedIcon />}
16
- sx={{
17
- '&:hover': {
18
- backgroundColor: 'rgba(255, 255, 255, 0.25)',
19
- },
20
- backgroundColor: 'rgba(255, 255, 255, 0.15)',
21
- color: '#FFFFFF',
22
- }}
23
- variant={'contained'}
24
- >
25
- {'Import Data'}
26
- </Button>
27
- );
28
- };
@@ -1,50 +0,0 @@
1
- import RestartAltIcon from '@mui/icons-material/RestartAlt';
2
- import {
3
- IconButton,
4
- Tooltip,
5
- } from '@mui/material';
6
- import {
7
- useCallback,
8
- useRef,
9
- } from 'react';
10
- import { Confirmation } from '@gen-epix/ui-core-components/components/Confirmation';
11
- import type { ConfirmationRefMethods } from '@gen-epix/ui-core-components/components/Confirmation';
12
- import { t } from 'i18next';
13
-
14
- export type FastaPageHeaderResetButtonProps = {
15
- onReset: () => void;
16
- };
17
-
18
- export const FastaPageHeaderResetButton = ({ onReset }: FastaPageHeaderResetButtonProps) => {
19
- const confirmationRef = useRef<ConfirmationRefMethods>(null);
20
- const onClickResetSession = useCallback(() => {
21
- confirmationRef.current?.open();
22
- }, []);
23
-
24
- const onConfirm = useCallback(() => {
25
- onReset();
26
- }, [onReset]);
27
-
28
- return (
29
- <>
30
- <Tooltip title={'Reset current session and dataset'}>
31
- <IconButton
32
- color={'inherit'}
33
- onClick={onClickResetSession}
34
- size={'small'}
35
- sx={{ opacity: 0.85 }}
36
- >
37
- <RestartAltIcon fontSize={'small'} />
38
- </IconButton>
39
- </Tooltip>
40
- <Confirmation
41
- body={t`Are you sure you want to reset the current session and dataset?`}
42
- cancelLabel={t`Cancel`}
43
- confirmLabel={t`Reset`}
44
- onConfirm={onConfirm}
45
- ref={confirmationRef}
46
- title={t`Reset current session and dataset?`}
47
- />
48
- </>
49
- );
50
- };