@apollo-annotation/jbrowse-plugin-apollo 0.1.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.
Files changed (116) hide show
  1. package/README.md +76 -0
  2. package/dist/index.esm.js +10248 -0
  3. package/dist/index.esm.js.map +1 -0
  4. package/dist/index.js +7 -0
  5. package/dist/jbrowse-plugin-apollo.cjs.development.js +10298 -0
  6. package/dist/jbrowse-plugin-apollo.cjs.development.js.map +1 -0
  7. package/dist/jbrowse-plugin-apollo.cjs.production.min.js +2 -0
  8. package/dist/jbrowse-plugin-apollo.cjs.production.min.js.map +1 -0
  9. package/dist/jbrowse-plugin-apollo.umd.development.js +46957 -0
  10. package/dist/jbrowse-plugin-apollo.umd.development.js.map +1 -0
  11. package/dist/jbrowse-plugin-apollo.umd.production.min.js +2 -0
  12. package/dist/jbrowse-plugin-apollo.umd.production.min.js.map +1 -0
  13. package/package.json +130 -0
  14. package/src/ApolloInternetAccount/addMenuItems.ts +94 -0
  15. package/src/ApolloInternetAccount/components/AuthTypeSelector.tsx +121 -0
  16. package/src/ApolloInternetAccount/components/LoginButtons.tsx +62 -0
  17. package/src/ApolloInternetAccount/components/LoginIcons.tsx +74 -0
  18. package/src/ApolloInternetAccount/configSchema.ts +26 -0
  19. package/src/ApolloInternetAccount/index.ts +2 -0
  20. package/src/ApolloInternetAccount/model.ts +448 -0
  21. package/src/ApolloJobModel.ts +117 -0
  22. package/src/ApolloSequenceAdapter/ApolloSequenceAdapter.ts +186 -0
  23. package/src/ApolloSequenceAdapter/configSchema.ts +12 -0
  24. package/src/ApolloSequenceAdapter/index.ts +21 -0
  25. package/src/ApolloSixFrameRenderer/ApolloSixFrameRenderer.tsx +12 -0
  26. package/src/ApolloSixFrameRenderer/components/ApolloRendering.tsx +692 -0
  27. package/src/ApolloSixFrameRenderer/configSchema.ts +7 -0
  28. package/src/ApolloSixFrameRenderer/index.ts +3 -0
  29. package/src/ApolloTextSearchAdapter/ApolloTextSearchAdapter.ts +64 -0
  30. package/src/ApolloTextSearchAdapter/configSchema.ts +24 -0
  31. package/src/ApolloTextSearchAdapter/index.ts +18 -0
  32. package/src/BackendDrivers/BackendDriver.ts +31 -0
  33. package/src/BackendDrivers/CollaborationServerDriver.ts +318 -0
  34. package/src/BackendDrivers/DesktopFileDriver.ts +170 -0
  35. package/src/BackendDrivers/InMemoryFileDriver.ts +76 -0
  36. package/src/BackendDrivers/index.ts +4 -0
  37. package/src/ChangeManager.ts +148 -0
  38. package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +248 -0
  39. package/src/LinearApolloDisplay/components/index.ts +1 -0
  40. package/src/LinearApolloDisplay/configSchema.ts +16 -0
  41. package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +422 -0
  42. package/src/LinearApolloDisplay/glyphs/CanonicalGeneGlyph.ts +1191 -0
  43. package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +151 -0
  44. package/src/LinearApolloDisplay/glyphs/Glyph.ts +382 -0
  45. package/src/LinearApolloDisplay/glyphs/ImplicitExonGeneGlyph.ts +697 -0
  46. package/src/LinearApolloDisplay/glyphs/index.ts +4 -0
  47. package/src/LinearApolloDisplay/index.ts +2 -0
  48. package/src/LinearApolloDisplay/stateModel/base.ts +146 -0
  49. package/src/LinearApolloDisplay/stateModel/getGlyph.ts +39 -0
  50. package/src/LinearApolloDisplay/stateModel/glyphs.ts +45 -0
  51. package/src/LinearApolloDisplay/stateModel/index.ts +20 -0
  52. package/src/LinearApolloDisplay/stateModel/layouts.ts +230 -0
  53. package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +513 -0
  54. package/src/LinearApolloDisplay/stateModel/rendering.ts +441 -0
  55. package/src/LinearApolloDisplay/stateModel/trackHeightMixin.ts +43 -0
  56. package/src/LinearApolloDisplay/types.ts +1 -0
  57. package/src/OntologyManager/OntologyStore/__snapshots__/fulltext.test.ts.snap +208 -0
  58. package/src/OntologyManager/OntologyStore/__snapshots__/index.test.ts.snap +18846 -0
  59. package/src/OntologyManager/OntologyStore/fulltext-stopwords.ts +137 -0
  60. package/src/OntologyManager/OntologyStore/fulltext.test.ts +94 -0
  61. package/src/OntologyManager/OntologyStore/fulltext.ts +264 -0
  62. package/src/OntologyManager/OntologyStore/index.test.ts +130 -0
  63. package/src/OntologyManager/OntologyStore/index.ts +526 -0
  64. package/src/OntologyManager/OntologyStore/indexeddb-schema.ts +89 -0
  65. package/src/OntologyManager/OntologyStore/indexeddb-storage.ts +180 -0
  66. package/src/OntologyManager/OntologyStore/obo-graph-json-schema.ts +110 -0
  67. package/src/OntologyManager/OntologyStore/prefixes.ts +35 -0
  68. package/src/OntologyManager/index.ts +173 -0
  69. package/src/SixFrameFeatureDisplay/components/TrackLines.tsx +19 -0
  70. package/src/SixFrameFeatureDisplay/components/index.ts +1 -0
  71. package/src/SixFrameFeatureDisplay/configSchema.ts +21 -0
  72. package/src/SixFrameFeatureDisplay/index.ts +2 -0
  73. package/src/SixFrameFeatureDisplay/stateModel.ts +413 -0
  74. package/src/TabularEditor/HybridGrid/ChangeHandling.ts +88 -0
  75. package/src/TabularEditor/HybridGrid/Feature.tsx +346 -0
  76. package/src/TabularEditor/HybridGrid/FeatureAttributes.tsx +34 -0
  77. package/src/TabularEditor/HybridGrid/Highlight.tsx +40 -0
  78. package/src/TabularEditor/HybridGrid/HybridGrid.tsx +138 -0
  79. package/src/TabularEditor/HybridGrid/NumberCell.tsx +77 -0
  80. package/src/TabularEditor/HybridGrid/ToolBar.tsx +59 -0
  81. package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +119 -0
  82. package/src/TabularEditor/HybridGrid/index.ts +1 -0
  83. package/src/TabularEditor/TabularEditorPane.tsx +34 -0
  84. package/src/TabularEditor/index.ts +3 -0
  85. package/src/TabularEditor/model.ts +44 -0
  86. package/src/TabularEditor/types.ts +3 -0
  87. package/src/components/AddAssembly.tsx +464 -0
  88. package/src/components/AddChildFeature.tsx +247 -0
  89. package/src/components/AddFeature.tsx +252 -0
  90. package/src/components/CopyFeature.tsx +328 -0
  91. package/src/components/DeleteAssembly.tsx +185 -0
  92. package/src/components/DeleteFeature.tsx +90 -0
  93. package/src/components/Dialog.tsx +47 -0
  94. package/src/components/DownloadGFF3.tsx +213 -0
  95. package/src/components/ImportFeatures.tsx +295 -0
  96. package/src/components/ManageChecks.tsx +280 -0
  97. package/src/components/ManageUsers.tsx +218 -0
  98. package/src/components/ModifyFeatureAttribute.tsx +457 -0
  99. package/src/components/OntologyTermAutocomplete.tsx +240 -0
  100. package/src/components/OntologyTermMultiSelect.tsx +349 -0
  101. package/src/components/OpenLocalFile.tsx +178 -0
  102. package/src/components/ViewChangeLog.tsx +208 -0
  103. package/src/components/ViewCheckResults.tsx +151 -0
  104. package/src/components/index.ts +12 -0
  105. package/src/config.ts +10 -0
  106. package/src/declare.d.ts +3 -0
  107. package/src/extensions/annotationFromPileup.ts +208 -0
  108. package/src/extensions/index.ts +1 -0
  109. package/src/index.ts +394 -0
  110. package/src/makeDisplayComponent.tsx +244 -0
  111. package/src/session/ClientDataStore.ts +282 -0
  112. package/src/session/index.ts +1 -0
  113. package/src/session/session.ts +373 -0
  114. package/src/types.ts +10 -0
  115. package/src/util/index.ts +31 -0
  116. package/src/util/loadAssemblyIntoClient.ts +291 -0
@@ -0,0 +1,247 @@
1
+ import { AbstractSessionModel } from '@jbrowse/core/util'
2
+ import {
3
+ Button,
4
+ DialogActions,
5
+ DialogContent,
6
+ DialogContentText,
7
+ FormControl,
8
+ InputLabel,
9
+ MenuItem,
10
+ Select,
11
+ SelectChangeEvent,
12
+ TextField,
13
+ } from '@mui/material'
14
+ import { AnnotationFeatureI } from 'apollo-mst'
15
+ import { AddFeatureChange } from 'apollo-shared'
16
+ import ObjectID from 'bson-objectid'
17
+ import React, { useState } from 'react'
18
+
19
+ import { ChangeManager } from '../ChangeManager'
20
+ import { isOntologyClass } from '../OntologyManager'
21
+ import OntologyStore from '../OntologyManager/OntologyStore'
22
+ import { ApolloSessionModel } from '../session'
23
+ import { Dialog } from './Dialog'
24
+ import { OntologyTermAutocomplete } from './OntologyTermAutocomplete'
25
+
26
+ interface AddChildFeatureProps {
27
+ session: ApolloSessionModel
28
+ handleClose(): void
29
+ sourceFeature: AnnotationFeatureI
30
+ sourceAssemblyId: string
31
+ changeManager: ChangeManager
32
+ }
33
+
34
+ enum PhaseEnum {
35
+ zero = 0,
36
+ one = 1,
37
+ two = 2,
38
+ }
39
+
40
+ export function AddChildFeature({
41
+ changeManager,
42
+ handleClose,
43
+ session,
44
+ sourceAssemblyId,
45
+ sourceFeature,
46
+ }: AddChildFeatureProps) {
47
+ const { notify } = session as unknown as AbstractSessionModel
48
+ const [end, setEnd] = useState(String(sourceFeature.end))
49
+ const [start, setStart] = useState(String(sourceFeature.start + 1))
50
+ const [type, setType] = useState('')
51
+ const [phase, setPhase] = useState('')
52
+ const [phaseAsNumber, setPhaseAsNumber] = useState<PhaseEnum>()
53
+ const [showPhase, setShowPhase] = useState<boolean>(false)
54
+ const [errorMessage, setErrorMessage] = useState('')
55
+ const [typeWarningText, setTypeWarningText] = useState('')
56
+
57
+ async function fetchValidDescendantTerms(
58
+ parentFeature: AnnotationFeatureI | undefined,
59
+ ontologyStore: OntologyStore,
60
+ _signal: AbortSignal,
61
+ ) {
62
+ if (!parentFeature) {
63
+ return
64
+ }
65
+ // since this is a child of an existing feature, restrict the autocomplete choices to valid
66
+ // parts of that feature
67
+ const parentTypeTerms = await ontologyStore.getTermsWithLabelOrSynonym(
68
+ parentFeature.type,
69
+ { includeSubclasses: false },
70
+ )
71
+ // eslint-disable-next-line unicorn/no-array-callback-reference
72
+ const parentTypeClassTerms = parentTypeTerms.filter(isOntologyClass)
73
+ if (parentTypeTerms.length === 0) {
74
+ return
75
+ }
76
+ const subpartTerms = await ontologyStore.getClassesThat(
77
+ 'part_of',
78
+ parentTypeClassTerms,
79
+ )
80
+ if (subpartTerms.length > 0) {
81
+ setTypeWarningText('')
82
+ } else {
83
+ setTypeWarningText(
84
+ `Type "${parentFeature.type}" does not have any children in the ontology`,
85
+ )
86
+ }
87
+ return subpartTerms
88
+ }
89
+
90
+ async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
91
+ event.preventDefault()
92
+ setErrorMessage('')
93
+ if (showPhase && phase === '') {
94
+ setErrorMessage('The phase is REQUIRED for all CDS features.')
95
+ return
96
+ }
97
+ const change = new AddFeatureChange({
98
+ changedIds: [sourceFeature._id],
99
+ typeName: 'AddFeatureChange',
100
+ assembly: sourceAssemblyId,
101
+ addedFeature: {
102
+ _id: new ObjectID().toHexString(),
103
+ gffId: '',
104
+ refSeq: sourceFeature.refSeq,
105
+ start: Number(start) - 1,
106
+ end: Number(end),
107
+ type,
108
+ phase: phaseAsNumber,
109
+ },
110
+ parentFeatureId: sourceFeature._id,
111
+ })
112
+ await changeManager.submit?.(change)
113
+ notify('Feature added successfully', 'success')
114
+ handleClose()
115
+ event.preventDefault()
116
+ }
117
+ function handleChangeType(newType: string) {
118
+ setErrorMessage('')
119
+ setType(newType)
120
+ if (newType.startsWith('CDS')) {
121
+ setShowPhase(true)
122
+ setPhase('')
123
+ } else {
124
+ setShowPhase(false)
125
+ }
126
+ }
127
+ async function handleChangePhase(e: SelectChangeEvent<string>) {
128
+ setErrorMessage('')
129
+ setPhase(e.target.value)
130
+
131
+ switch (Number(e.target.value)) {
132
+ case 0: {
133
+ setPhaseAsNumber(PhaseEnum.zero)
134
+ break
135
+ }
136
+ case 1: {
137
+ setPhaseAsNumber(PhaseEnum.one)
138
+ break
139
+ }
140
+ case 2: {
141
+ setPhaseAsNumber(PhaseEnum.two)
142
+ break
143
+ }
144
+ default: {
145
+ // eslint-disable-next-line unicorn/no-useless-undefined
146
+ setPhaseAsNumber(undefined)
147
+ }
148
+ }
149
+ }
150
+ const error = Number(end) <= Number(start)
151
+ return (
152
+ <Dialog
153
+ open
154
+ title="Add new child feature"
155
+ handleClose={handleClose}
156
+ maxWidth={false}
157
+ data-testid="add-feature-dialog"
158
+ >
159
+ <form onSubmit={onSubmit}>
160
+ <DialogContent style={{ display: 'flex', flexDirection: 'column' }}>
161
+ <TextField
162
+ margin="dense"
163
+ id="start"
164
+ label="Start"
165
+ type="number"
166
+ fullWidth
167
+ variant="outlined"
168
+ value={start}
169
+ onChange={(e) => setStart(e.target.value)}
170
+ />
171
+ <TextField
172
+ margin="dense"
173
+ id="end"
174
+ label="End"
175
+ type="number"
176
+ fullWidth
177
+ variant="outlined"
178
+ value={end}
179
+ onChange={(e) => setEnd(e.target.value)}
180
+ error={error}
181
+ helperText={error ? '"End" must be greater than "Start"' : null}
182
+ />
183
+ {/* <Select value={type} onChange={handleChangeType} label="Type">
184
+ {(possibleChildTypes ?? []).map((option) => (
185
+ <MenuItem key={option} value={option}>
186
+ {option}
187
+ </MenuItem>
188
+ ))}
189
+ </Select> */}
190
+ <OntologyTermAutocomplete
191
+ session={session}
192
+ ontologyName="Sequence Ontology"
193
+ style={{ width: 170 }}
194
+ value={type}
195
+ filterTerms={isOntologyClass}
196
+ fetchValidTerms={fetchValidDescendantTerms.bind(
197
+ null,
198
+ sourceFeature,
199
+ )}
200
+ renderInput={(params) => (
201
+ <TextField
202
+ {...params}
203
+ label="Type"
204
+ variant="outlined"
205
+ fullWidth
206
+ error={Boolean(typeWarningText)}
207
+ helperText={typeWarningText}
208
+ />
209
+ )}
210
+ onChange={(oldValue, newValue) => {
211
+ if (newValue) {
212
+ handleChangeType(newValue)
213
+ }
214
+ }}
215
+ />
216
+ {showPhase ? (
217
+ <FormControl>
218
+ <InputLabel>Phase</InputLabel>
219
+ <Select value={phase} onChange={handleChangePhase}>
220
+ <MenuItem value={0}>0</MenuItem>
221
+ <MenuItem value={1}>1</MenuItem>
222
+ <MenuItem value={2}>2</MenuItem>
223
+ </Select>
224
+ </FormControl>
225
+ ) : null}
226
+ </DialogContent>
227
+ <DialogActions>
228
+ <Button
229
+ variant="contained"
230
+ type="submit"
231
+ disabled={error || !(start && end && type)}
232
+ >
233
+ Submit
234
+ </Button>
235
+ <Button variant="outlined" type="submit" onClick={handleClose}>
236
+ Cancel
237
+ </Button>
238
+ </DialogActions>
239
+ </form>
240
+ {errorMessage ? (
241
+ <DialogContent>
242
+ <DialogContentText color="error">{errorMessage}</DialogContentText>
243
+ </DialogContent>
244
+ ) : null}
245
+ </Dialog>
246
+ )
247
+ }
@@ -0,0 +1,252 @@
1
+ import { AbstractSessionModel, Region } from '@jbrowse/core/util/types'
2
+ import {
3
+ Button,
4
+ DialogActions,
5
+ DialogContent,
6
+ DialogContentText,
7
+ FormControl,
8
+ InputLabel,
9
+ MenuItem,
10
+ Select,
11
+ SelectChangeEvent,
12
+ TextField,
13
+ } from '@mui/material'
14
+ import { AddFeatureChange } from 'apollo-shared'
15
+ import ObjectID from 'bson-objectid'
16
+ import React, { useState } from 'react'
17
+
18
+ import { ChangeManager } from '../ChangeManager'
19
+ import { isOntologyClass } from '../OntologyManager'
20
+ import { ApolloSessionModel } from '../session'
21
+ import { Dialog } from './Dialog'
22
+ import { OntologyTermAutocomplete } from './OntologyTermAutocomplete'
23
+
24
+ interface AddFeatureProps {
25
+ session: ApolloSessionModel
26
+ handleClose(): void
27
+ region: Region
28
+ changeManager: ChangeManager
29
+ }
30
+
31
+ enum PhaseEnum {
32
+ zero = 0,
33
+ one = 1,
34
+ two = 2,
35
+ }
36
+
37
+ export function AddFeature({
38
+ changeManager,
39
+ handleClose,
40
+ region,
41
+ session,
42
+ }: AddFeatureProps) {
43
+ const { notify } = session as unknown as AbstractSessionModel
44
+ const [end, setEnd] = useState(String(region.end))
45
+ const [start, setStart] = useState(String(region.start + 1))
46
+ const [type, setType] = useState('')
47
+ const [phase, setPhase] = useState('')
48
+ const [strand, setStrand] = useState<1 | -1 | undefined>()
49
+ const [phaseAsNumber, setPhaseAsNumber] = useState<PhaseEnum>()
50
+ const [showPhase, setShowPhase] = useState<boolean>(false)
51
+ const [errorMessage, setErrorMessage] = useState('')
52
+
53
+ async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
54
+ event.preventDefault()
55
+ setErrorMessage('')
56
+ if (showPhase && phase === '') {
57
+ setErrorMessage('The phase is REQUIRED for all CDS features.')
58
+ return
59
+ }
60
+
61
+ let refSeqId
62
+ for (const [, asm] of session.apolloDataStore.assemblies ?? new Map()) {
63
+ if (asm._id === region.assemblyName) {
64
+ for (const [, refseq] of asm.refSeqs ?? new Map()) {
65
+ if (refseq.name === region.refName) {
66
+ refSeqId = refseq._id
67
+ }
68
+ }
69
+ }
70
+ }
71
+
72
+ if (!refSeqId) {
73
+ setErrorMessage('Invalid refseq id')
74
+ return
75
+ }
76
+
77
+ const id = new ObjectID().toHexString()
78
+ const change = new AddFeatureChange({
79
+ changedIds: [id],
80
+ typeName: 'AddFeatureChange',
81
+ assembly: region.assemblyName,
82
+ addedFeature: {
83
+ _id: id,
84
+ gffId: '',
85
+ refSeq: refSeqId,
86
+ start: Number(start) - 1,
87
+ end: Number(end),
88
+ type,
89
+ phase: phaseAsNumber,
90
+ strand,
91
+ },
92
+ })
93
+ await changeManager.submit?.(change)
94
+ notify('Feature added successfully', 'success')
95
+ handleClose()
96
+ event.preventDefault()
97
+ }
98
+
99
+ function handleChangeType(newType: string) {
100
+ setErrorMessage('')
101
+ setType(newType)
102
+ if (newType.startsWith('CDS')) {
103
+ setShowPhase(true)
104
+ setPhase('')
105
+ } else {
106
+ setShowPhase(false)
107
+ }
108
+ }
109
+
110
+ function handleChangeStrand(e: SelectChangeEvent<string>) {
111
+ setErrorMessage('')
112
+
113
+ switch (Number(e.target.value)) {
114
+ case 1: {
115
+ setStrand(1)
116
+ break
117
+ }
118
+ case -1: {
119
+ setStrand(-1)
120
+ break
121
+ }
122
+ default: {
123
+ // eslint-disable-next-line unicorn/no-useless-undefined
124
+ setStrand(undefined)
125
+ }
126
+ }
127
+ }
128
+
129
+ async function handleChangePhase(e: SelectChangeEvent<string>) {
130
+ setErrorMessage('')
131
+ setPhase(e.target.value)
132
+
133
+ switch (Number(e.target.value)) {
134
+ case 0: {
135
+ setPhaseAsNumber(PhaseEnum.zero)
136
+ break
137
+ }
138
+ case 1: {
139
+ setPhaseAsNumber(PhaseEnum.one)
140
+ break
141
+ }
142
+ case 2: {
143
+ setPhaseAsNumber(PhaseEnum.two)
144
+ break
145
+ }
146
+ default: {
147
+ // eslint-disable-next-line unicorn/no-useless-undefined
148
+ setPhaseAsNumber(undefined)
149
+ }
150
+ }
151
+ }
152
+
153
+ const error = Number(end) <= Number(start)
154
+
155
+ return (
156
+ <Dialog
157
+ open
158
+ title="Add new feature"
159
+ handleClose={handleClose}
160
+ maxWidth={false}
161
+ data-testid="add-feature-dialog"
162
+ >
163
+ <form onSubmit={onSubmit}>
164
+ <DialogContent style={{ display: 'flex', flexDirection: 'column' }}>
165
+ <TextField
166
+ margin="dense"
167
+ id="start"
168
+ label="Start"
169
+ type="number"
170
+ fullWidth
171
+ variant="outlined"
172
+ value={Number(start)}
173
+ onChange={(e) => setStart(e.target.value)}
174
+ />
175
+ <TextField
176
+ margin="dense"
177
+ id="end"
178
+ label="End"
179
+ type="number"
180
+ fullWidth
181
+ variant="outlined"
182
+ value={end}
183
+ onChange={(e) => setEnd(e.target.value)}
184
+ error={error}
185
+ helperText={error ? '"End" must be greater than "Start"' : null}
186
+ />
187
+ <OntologyTermAutocomplete
188
+ session={session}
189
+ ontologyName="Sequence Ontology"
190
+ style={{ width: 170 }}
191
+ value={type}
192
+ filterTerms={isOntologyClass}
193
+ renderInput={(params) => (
194
+ <TextField
195
+ {...params}
196
+ label="Type"
197
+ variant="outlined"
198
+ fullWidth
199
+ />
200
+ )}
201
+ onChange={(oldValue, newValue) => {
202
+ if (newValue) {
203
+ handleChangeType(newValue)
204
+ }
205
+ }}
206
+ />
207
+ <FormControl>
208
+ <InputLabel id="demo-simple-select-label">Strand</InputLabel>
209
+ <Select
210
+ labelId="demo-simple-select-label"
211
+ id="demo-simple-select"
212
+ label="Strand"
213
+ value={strand?.toString()}
214
+ onChange={handleChangeStrand}
215
+ >
216
+ <MenuItem value={undefined}></MenuItem>
217
+ <MenuItem value={1}>+</MenuItem>
218
+ <MenuItem value={-1}>-</MenuItem>
219
+ </Select>
220
+ </FormControl>
221
+ {showPhase ? (
222
+ <FormControl>
223
+ <InputLabel>Phase</InputLabel>
224
+ <Select value={phase} onChange={handleChangePhase}>
225
+ <MenuItem value={0}>0</MenuItem>
226
+ <MenuItem value={1}>1</MenuItem>
227
+ <MenuItem value={2}>2</MenuItem>
228
+ </Select>
229
+ </FormControl>
230
+ ) : null}
231
+ </DialogContent>
232
+ <DialogActions>
233
+ <Button
234
+ variant="contained"
235
+ type="submit"
236
+ disabled={error || !(start && end && type)}
237
+ >
238
+ Submit
239
+ </Button>
240
+ <Button variant="outlined" type="submit" onClick={handleClose}>
241
+ Cancel
242
+ </Button>
243
+ </DialogActions>
244
+ </form>
245
+ {errorMessage ? (
246
+ <DialogContent>
247
+ <DialogContentText color="error">{errorMessage}</DialogContentText>
248
+ </DialogContent>
249
+ ) : null}
250
+ </Dialog>
251
+ )
252
+ }