@opencloning/ui 1.2.0 → 1.3.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.
Files changed (31) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/package.json +4 -3
  3. package/src/components/assembler/Assembler.cy.jsx +364 -0
  4. package/src/components/assembler/Assembler.jsx +298 -205
  5. package/src/components/assembler/AssemblerPart.cy.jsx +52 -0
  6. package/src/components/assembler/AssemblerPart.jsx +51 -79
  7. package/src/components/assembler/ExistingSyntaxDialog.cy.jsx +251 -0
  8. package/src/components/assembler/ExistingSyntaxDialog.jsx +104 -0
  9. package/src/components/assembler/PlasmidSyntaxTable.jsx +83 -0
  10. package/src/components/assembler/assembler_utils.js +134 -0
  11. package/src/components/assembler/assembler_utils.test.js +193 -0
  12. package/src/components/assembler/assembly_component.module.css +1 -1
  13. package/src/components/assembler/graph_utils.js +153 -0
  14. package/src/components/assembler/graph_utils.test.js +239 -0
  15. package/src/components/assembler/index.js +9 -0
  16. package/src/components/assembler/useAssembler.js +59 -22
  17. package/src/components/assembler/useCombinatorialAssembly.js +76 -0
  18. package/src/components/assembler/usePlasmidsLogic.js +82 -0
  19. package/src/components/eLabFTW/utils.js +0 -9
  20. package/src/components/index.js +2 -0
  21. package/src/components/navigation/SelectTemplateDialog.jsx +0 -1
  22. package/src/components/primers/DownloadPrimersButton.jsx +0 -1
  23. package/src/components/primers/PrimerList.jsx +4 -3
  24. package/src/components/primers/import_primers/ImportPrimersButton.jsx +0 -1
  25. package/src/version.js +1 -1
  26. package/vitest.config.js +2 -4
  27. package/src/components/DraggableDialogPaper.jsx +0 -16
  28. package/src/components/assembler/AssemblePartWidget.jsx +0 -252
  29. package/src/components/assembler/StopIcon.jsx +0 -34
  30. package/src/components/assembler/assembler_data2.json +0 -50
  31. package/src/components/assembler/moclo.json +0 -110
@@ -1,252 +0,0 @@
1
- import React from 'react'
2
- import { TextField, FormControl, InputLabel, Select, MenuItem, Box, Grid, Paper, Typography, Table, TableContainer, TableHead, TableBody, TableRow, TableCell, Button } from '@mui/material'
3
- import { ContentCopy as ContentCopyIcon } from '@mui/icons-material'
4
- import AssemblerPart from './AssemblerPart'
5
-
6
- /* eslint-disable camelcase */
7
- const defaultData = {
8
- header: 'Header',
9
- body: 'helper text / body text',
10
- glyph: 'cds-stop',
11
- left_overhang: 'CATG',
12
- right_overhang: 'TATG',
13
- left_inside: 'AAAATA',
14
- right_inside: 'AATG',
15
- left_codon_start: 2,
16
- right_codon_start: 1,
17
- color: 'greenyellow',
18
- }
19
- /* eslint-enable camelcase */
20
-
21
- const glyphOptions = [
22
- 'assembly-scar',
23
- 'cds',
24
- 'cds-stop',
25
- 'chromosomal-locus',
26
- 'engineered-region',
27
- 'five-prime-sticky-restriction-site',
28
- 'origin-of-replication',
29
- 'primer-binding-site',
30
- 'promoter',
31
- 'ribosome-entry-site',
32
- 'specific-recombination-site',
33
- 'terminator',
34
- 'three-prime-sticky-restriction-site',
35
- ]
36
-
37
- function AssemblePartWidget() {
38
- const [formData, setFormData] = React.useState(defaultData)
39
-
40
- const handleChange = (field) => (event) => {
41
- const value = event.target.value
42
- setFormData((prev) => ({
43
- ...prev,
44
- [field]: field === 'left_codon_start' || field === 'right_codon_start'
45
- ? (value === '' ? '' : parseInt(value, 10) || 0)
46
- : value,
47
- }))
48
- }
49
-
50
- const handleCopyRow = async () => {
51
- const keys = Object.keys(formData)
52
- const headers = keys.join('\t')
53
- const values = keys.map((key) => String(formData[key])).join('\t')
54
- const tsvData = `${headers}\n${values}`
55
-
56
- try {
57
- if (window.navigator && window.navigator.clipboard) {
58
- await window.navigator.clipboard.writeText(tsvData)
59
- }
60
- } catch (err) {
61
- // eslint-disable-next-line no-console
62
- console.error('Failed to copy to clipboard:', err)
63
- }
64
- }
65
-
66
- return (
67
- <Box sx={{
68
- p: 1.5,
69
- maxHeight: '100vh',
70
- overflowY: 'auto',
71
- overflowX: 'hidden'
72
- }}>
73
- <Grid container spacing={2}>
74
- <Grid item xs={12} md={6}>
75
- <Paper sx={{ p: 1.5 }}>
76
- <Typography variant="h6" gutterBottom sx={{ mb: 1.5 }}>
77
- Part Configuration
78
- </Typography>
79
- <Box component="form" sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
80
- <TextField
81
- size="small"
82
- label="Header"
83
- value={formData.header}
84
- onChange={handleChange('header')}
85
- fullWidth
86
- />
87
- <TextField
88
- size="small"
89
- label="Body"
90
- value={formData.body}
91
- onChange={handleChange('body')}
92
- fullWidth
93
- multiline
94
- rows={2}
95
- />
96
- <FormControl fullWidth size="small">
97
- <InputLabel id="glyph-select-label">Glyph</InputLabel>
98
- <Select
99
- labelId="glyph-select-label"
100
- value={formData.glyph}
101
- label="Glyph"
102
- onChange={handleChange('glyph')}
103
- >
104
- {glyphOptions.map((option) => (
105
- <MenuItem key={option} value={option}>
106
- {option}
107
- </MenuItem>
108
- ))}
109
- </Select>
110
- </FormControl>
111
- <TextField
112
- size="small"
113
- label="Color"
114
- value={formData.color}
115
- onChange={handleChange('color')}
116
- fullWidth
117
- helperText="CSS color name or hex code"
118
- />
119
- <Typography variant="subtitle2" sx={{ mt: 0.5, mb: 0.5 }}>
120
- Left Side
121
- </Typography>
122
- <TextField
123
- size="small"
124
- label="Left Overhang"
125
- value={formData.left_overhang}
126
- onChange={handleChange('left_overhang')}
127
- error={formData.left_overhang.length !== 4}
128
- helperText={formData.left_overhang.length !== 4 ? 'Must be 4 bases' : ''}
129
- fullWidth
130
- />
131
- <TextField
132
- size="small"
133
- label="Left Inside"
134
- value={formData.left_inside}
135
- onChange={handleChange('left_inside')}
136
- fullWidth
137
- />
138
- <TextField
139
- size="small"
140
- label="Left Codon Start"
141
- type="number"
142
- value={formData.left_codon_start}
143
- onChange={handleChange('left_codon_start')}
144
- fullWidth
145
- inputProps={{ min: 0 }}
146
- helperText="If the left side is translated, where the codon starts"
147
- />
148
- <Typography variant="subtitle2" sx={{ mt: 0.5, mb: 0.5 }}>
149
- Right Side
150
- </Typography>
151
- <TextField
152
- size="small"
153
- label="Right Overhang"
154
- value={formData.right_overhang}
155
- onChange={handleChange('right_overhang')}
156
- fullWidth
157
- />
158
- <TextField
159
- size="small"
160
- label="Right Inside"
161
- value={formData.right_inside}
162
- onChange={handleChange('right_inside')}
163
- fullWidth
164
- />
165
- <TextField
166
- size="small"
167
- label="Right Codon Start"
168
- type="number"
169
- value={formData.right_codon_start}
170
- onChange={handleChange('right_codon_start')}
171
- fullWidth
172
- inputProps={{ min: 0 }}
173
- helperText="If the right side is translated, where the codon starts"
174
- />
175
- </Box>
176
- </Paper>
177
- </Grid>
178
- <Grid item xs={12} md={6}>
179
- <Paper sx={{ p: 1.5 }}>
180
- <Typography variant="h6" gutterBottom sx={{ mb: 1.5 }}>
181
- Preview
182
- </Typography>
183
- <Box sx={{ mt: 1, display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
184
- {(formData.header || formData.body) && (
185
- <Box sx={{
186
- textAlign: 'center',
187
- mb: 1.5,
188
- display: 'flex',
189
- flexDirection: 'column',
190
- gap: 0.5
191
- }}>
192
- {formData.header && (
193
- <Typography variant="h6" sx={{ fontWeight: 'bold' }}>
194
- {formData.header}
195
- </Typography>
196
- )}
197
- {formData.body && (
198
- <Typography variant="body2" sx={{ color: 'text.secondary' }}>
199
- {formData.body}
200
- </Typography>
201
- )}
202
- </Box>
203
- )}
204
- <AssemblerPart data={formData} />
205
- </Box>
206
- </Paper>
207
- </Grid>
208
- </Grid>
209
- <Box sx={{ mt: 2 }}>
210
- <Paper sx={{ p: 1.5 }}>
211
- <Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 1.5 }}>
212
- <Typography variant="h6">
213
- JSON Data
214
- </Typography>
215
- <Button
216
- size="small"
217
- variant="outlined"
218
- startIcon={<ContentCopyIcon />}
219
- onClick={handleCopyRow}
220
- >
221
- Copy Row
222
- </Button>
223
- </Box>
224
- <TableContainer>
225
- <Table size="small" sx={{ '& .MuiTableCell-root': { py: 0.5, px: 1 } }}>
226
- <TableHead>
227
- <TableRow>
228
- {Object.keys(formData).map((key) => (
229
- <TableCell key={key} sx={{ fontWeight: 'bold' }}>
230
- {key}
231
- </TableCell>
232
- ))}
233
- </TableRow>
234
- </TableHead>
235
- <TableBody>
236
- <TableRow>
237
- {Object.keys(formData).map((key) => (
238
- <TableCell key={key}>
239
- {String(formData[key])}
240
- </TableCell>
241
- ))}
242
- </TableRow>
243
- </TableBody>
244
- </Table>
245
- </TableContainer>
246
- </Paper>
247
- </Box>
248
- </Box>
249
- )
250
- }
251
-
252
- export default AssemblePartWidget
@@ -1,34 +0,0 @@
1
- import React from 'react'
2
-
3
- function StopIcon({ color = 'currentColor', size = 24, ...props }) {
4
- return (
5
- <svg xmlns="http://www.w3.org/2000/svg"
6
- viewBox="0 0 24 24"
7
- width={size} height={size}
8
- role="img"
9
- aria-label="Stop sign icon"
10
- {...props}
11
- >
12
- <mask id="stop-mask">
13
- {/* Octagon area (visible part) */}
14
- <polygon fill="white"
15
- points="7.07,2 16.93,2 22,7.07 22,16.93 16.93,22 7.07,22 2,16.93 2,7.07" />
16
- {/* Text area (cut out) */}
17
- <text x="12" y="12.3"
18
- fill="black"
19
- fontFamily="Arial, Helvetica, sans-serif"
20
- fontWeight="700"
21
- fontSize="7.2"
22
- textAnchor="middle"
23
- dominantBaseline="middle">STOP</text>
24
- </mask>
25
-
26
- {/* Octagon using mask */}
27
- <rect width="24" height="24" fill={color} mask="url(#stop-mask)" />
28
- </svg>
29
- )
30
- }
31
-
32
- export default StopIcon
33
-
34
-
@@ -1,50 +0,0 @@
1
- [
2
- {
3
- "name": "A",
4
- "overhang": "GGAG"
5
- },
6
- {
7
- "name": "B",
8
- "overhang": "TACT"
9
- },
10
- {
11
- "name": "T1",
12
- "overhang": "CCAT"
13
- },
14
- {
15
- "name": "T2",
16
- "overhang": "GTCA"
17
- },
18
- {
19
- "name": "T3",
20
- "overhang": "TCCA"
21
- },
22
- {
23
- "name": "C",
24
- "overhang": "AATG"
25
- },
26
- {
27
- "name": "D",
28
- "overhang": "AGGT"
29
- },
30
- {
31
- "name": "T4",
32
- "overhang": "TTCG"
33
- },
34
- {
35
- "name": "T5",
36
- "overhang": "CGGC"
37
- },
38
- {
39
- "name": "E",
40
- "overhang": "GCTT"
41
- },
42
- {
43
- "name": "F",
44
- "overhang": "CGCT"
45
- },
46
- {
47
- "name": "backbone",
48
- "overhang": "GGAG"
49
- }
50
- ]
@@ -1,110 +0,0 @@
1
- [
2
- {
3
- "header": "Assembly connector",
4
- "body": "",
5
- "glyph": "three-prime-sticky-restriction-site",
6
- "left_overhang": "CCCT",
7
- "right_overhang": "AACG",
8
- "left_inside": "",
9
- "right_inside": "",
10
- "left_codon_start": null,
11
- "right_codon_start": null,
12
- "color": "#92C3DC"
13
- },
14
- {
15
- "header": "Promoter",
16
- "body": "",
17
- "glyph": "promoter",
18
- "left_overhang": "AACG",
19
- "right_overhang": "TATG",
20
- "left_inside": "",
21
- "right_inside": "",
22
- "left_codon_start": null,
23
- "right_codon_start": null,
24
- "color": "#B2D06E"
25
- },
26
- {
27
- "header": "Coding sequence",
28
- "body": "You can use the ATG from the fusion site as translation start. If possible omit STOP codon and make your protein in frame with the Ser.",
29
- "glyph": "cds",
30
- "left_overhang": "TATG",
31
- "right_overhang": "ATCC",
32
- "left_inside": "",
33
- "right_inside": "",
34
- "left_codon_start": 2,
35
- "right_codon_start": 2,
36
- "color": "#F1EC9B"
37
- },
38
- {
39
- "header": "Terminator",
40
- "body": "",
41
- "glyph": "terminator",
42
- "left_overhang": "ATCC",
43
- "right_overhang": "GCTG",
44
- "left_inside": "",
45
- "right_inside": "",
46
- "left_codon_start": null,
47
- "right_codon_start": null,
48
- "color": "#E2929E"
49
- },
50
- {
51
- "header": "Assembly connector",
52
- "body": "",
53
- "glyph": "three-prime-sticky-restriction-site",
54
- "left_overhang": "GCTG",
55
- "right_overhang": "TACA",
56
- "left_inside": "",
57
- "right_inside": "",
58
- "left_codon_start": null,
59
- "right_codon_start": null,
60
- "color": "#7C6AA9"
61
- },
62
- {
63
- "header": "Yeast marker",
64
- "body": "",
65
- "glyph": "engineered-region",
66
- "left_overhang": "TACA",
67
- "right_overhang": "GAGT",
68
- "left_inside": "",
69
- "right_inside": "",
70
- "left_codon_start": null,
71
- "right_codon_start": null,
72
- "color": "#EFD198"
73
- },
74
- {
75
- "header": "Yeast plasmid origin of replication",
76
- "body": "",
77
- "glyph": "origin-of-replication",
78
- "left_overhang": "GAGT",
79
- "right_overhang": "CCGA",
80
- "left_inside": "",
81
- "right_inside": "",
82
- "left_codon_start": null,
83
- "right_codon_start": null,
84
- "color": "#85643E"
85
- },
86
- {
87
- "header": "Bacterial marker and origin",
88
- "body": "",
89
- "glyph": "engineered-region",
90
- "left_overhang": "CCGA",
91
- "right_overhang": "CCCT",
92
- "left_inside": "",
93
- "right_inside": "",
94
- "left_codon_start": null,
95
- "right_codon_start": null,
96
- "color": "#7F7F7F"
97
- },
98
- {
99
- "header": "Dummy",
100
- "body": "promoter text",
101
- "glyph": "cds-stop",
102
- "left_overhang": "CATG",
103
- "right_overhang": "TATG",
104
- "left_inside": "AAAATA",
105
- "right_inside": "AATG",
106
- "left_codon_start": 2,
107
- "right_codon_start": 1,
108
- "color": "greenyellow"
109
- }
110
- ]