@jbrowse/plugin-data-management 1.7.4 → 1.7.7

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.
@@ -27,6 +27,8 @@ var _configuration = require("@jbrowse/core/configuration");
27
27
 
28
28
  var _mobxReact = require("mobx-react");
29
29
 
30
+ var _mobxStateTree = require("mobx-state-tree");
31
+
30
32
  var _lab = require("@material-ui/lab");
31
33
 
32
34
  var _ConfirmTrack = _interopRequireDefault(require("./ConfirmTrack"));
@@ -76,11 +78,19 @@ function AddTrackWidget(_ref) {
76
78
 
77
79
  var classes = useStyles();
78
80
  var session = (0, _util.getSession)(model);
81
+
82
+ var _getEnv = (0, _mobxStateTree.getEnv)(session),
83
+ pluginManager = _getEnv.pluginManager;
84
+
85
+ var rootModel = pluginManager.rootModel;
86
+ var jobsManager = rootModel.jobsManager;
79
87
  var assembly = model.assembly,
80
88
  trackAdapter = model.trackAdapter,
81
89
  trackData = model.trackData,
82
90
  trackName = model.trackName,
83
- trackType = model.trackType;
91
+ trackType = model.trackType,
92
+ textIndexTrack = model.textIndexTrack,
93
+ textIndexingConf = model.textIndexingConf;
84
94
 
85
95
  var _useState3 = (0, _react.useState)(),
86
96
  _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
@@ -110,7 +120,7 @@ function AddTrackWidget(_ref) {
110
120
 
111
121
  function _handleNext() {
112
122
  _handleNext = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
113
- var trackId, assemblyInstance;
123
+ var trackId, assemblyInstance, textSearchingDefault, attr, indexName, indexingParams, newEntry;
114
124
  return _regenerator.default.wrap(function _callee$(_context) {
115
125
  while (1) {
116
126
  switch (_context.prev = _context.next) {
@@ -138,9 +148,35 @@ function AddTrackWidget(_ref) {
138
148
  sequenceAdapter: (0, _configuration.getConf)(assemblyInstance, ['sequence', 'adapter'])
139
149
  })
140
150
  });
151
+ textSearchingDefault = {
152
+ attributes: ['Name', 'ID'],
153
+ exclude: ['CDS', 'exon']
154
+ };
141
155
 
142
156
  if (model.view) {
143
157
  model.view.showTrack(trackId);
158
+
159
+ if (_util.isElectron) {
160
+ if (textIndexTrack && (0, _util.supportedIndexingAdapters)(trackAdapter.type)) {
161
+ attr = textIndexingConf || textSearchingDefault;
162
+ indexName = trackName + '-index';
163
+ indexingParams = _objectSpread(_objectSpread({}, attr), {}, {
164
+ assemblies: [assembly],
165
+ tracks: [trackId],
166
+ indexType: 'perTrack',
167
+ name: indexName,
168
+ timestamp: new Date().toISOString()
169
+ });
170
+ newEntry = {
171
+ indexingParams: indexingParams,
172
+ name: indexName,
173
+ cancelCallback: function cancelCallback() {
174
+ jobsManager.abortJob();
175
+ }
176
+ };
177
+ jobsManager.queueJob(newEntry);
178
+ }
179
+ }
144
180
  } else {
145
181
  session.notify('Open a new view, or use the track selector in an existing view, to view this track', 'info');
146
182
  }
@@ -2,12 +2,16 @@
2
2
 
3
3
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
4
 
5
+ var _typeof = require("@babel/runtime/helpers/typeof");
6
+
5
7
  Object.defineProperty(exports, "__esModule", {
6
8
  value: true
7
9
  });
8
10
  exports.default = void 0;
9
11
 
10
- var _react = _interopRequireDefault(require("react"));
12
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
13
+
14
+ var _react = _interopRequireWildcard(require("react"));
11
15
 
12
16
  var _configuration = require("@jbrowse/core/configuration");
13
17
 
@@ -15,16 +19,36 @@ var _util = require("@jbrowse/core/util");
15
19
 
16
20
  var _core = require("@material-ui/core");
17
21
 
22
+ var _Delete = _interopRequireDefault(require("@material-ui/icons/Delete"));
23
+
24
+ var _Add = _interopRequireDefault(require("@material-ui/icons/Add"));
25
+
18
26
  var _mobxReact = require("mobx-react");
19
27
 
20
28
  var _mobxStateTree = require("mobx-state-tree");
21
29
 
22
30
  var _tracks = require("@jbrowse/core/util/tracks");
23
31
 
32
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
33
+
34
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
35
+
36
+ // icons
24
37
  var useStyles = (0, _core.makeStyles)(function (theme) {
25
38
  return {
26
39
  spacing: {
27
40
  marginBottom: theme.spacing(3)
41
+ },
42
+ paper: {
43
+ display: 'flex',
44
+ flexDirection: 'column',
45
+ padding: theme.spacing(1)
46
+ },
47
+ spacer: {
48
+ height: theme.spacing(8)
49
+ },
50
+ card: {
51
+ marginTop: theme.spacing(1)
28
52
  }
29
53
  };
30
54
  });
@@ -88,9 +112,108 @@ function getTrackTypes(pluginManager) {
88
112
  return pluginManager.getElementTypesInGroup('track');
89
113
  }
90
114
 
91
- var TrackAdapterSelector = (0, _mobxReact.observer)(function (_ref2) {
115
+ var TextIndexingConfig = (0, _mobxReact.observer)(function (_ref2) {
92
116
  var model = _ref2.model;
93
117
  var classes = useStyles();
118
+
119
+ var _useState = (0, _react.useState)(''),
120
+ _useState2 = (0, _slicedToArray2.default)(_useState, 2),
121
+ value1 = _useState2[0],
122
+ setValue1 = _useState2[1];
123
+
124
+ var _useState3 = (0, _react.useState)(''),
125
+ _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
126
+ value2 = _useState4[0],
127
+ setValue2 = _useState4[1];
128
+
129
+ var _useState5 = (0, _react.useState)(['Name', 'ID']),
130
+ _useState6 = (0, _slicedToArray2.default)(_useState5, 2),
131
+ attributes = _useState6[0],
132
+ setAttributes = _useState6[1];
133
+
134
+ var _useState7 = (0, _react.useState)(['CDS', 'exon']),
135
+ _useState8 = (0, _slicedToArray2.default)(_useState7, 2),
136
+ exclude = _useState8[0],
137
+ setExclude = _useState8[1];
138
+
139
+ var sections = [{
140
+ label: 'Indexing attributes',
141
+ values: attributes
142
+ }, {
143
+ label: 'Feature types to exclude',
144
+ values: exclude
145
+ }];
146
+ (0, _react.useEffect)(function () {
147
+ model.setTextIndexingConf({
148
+ attributes: attributes,
149
+ exclude: exclude
150
+ });
151
+ }, [model, attributes, exclude]);
152
+ return /*#__PURE__*/_react.default.createElement(_core.Paper, {
153
+ className: classes.paper
154
+ }, /*#__PURE__*/_react.default.createElement(_core.InputLabel, null, "Indexing configuration"), sections.map(function (section, index) {
155
+ return /*#__PURE__*/_react.default.createElement(_core.Card, {
156
+ raised: true,
157
+ key: section.label,
158
+ className: classes.card
159
+ }, /*#__PURE__*/_react.default.createElement(_core.CardContent, null, /*#__PURE__*/_react.default.createElement(_core.InputLabel, null, section.label), /*#__PURE__*/_react.default.createElement(_core.List, {
160
+ disablePadding: true
161
+ }, section.values.map(function (val, idx) {
162
+ return /*#__PURE__*/_react.default.createElement(_core.ListItem, {
163
+ key: idx,
164
+ disableGutters: true
165
+ }, /*#__PURE__*/_react.default.createElement(_core.TextField, {
166
+ value: val,
167
+ InputProps: {
168
+ endAdornment: /*#__PURE__*/_react.default.createElement(_core.InputAdornment, {
169
+ position: "end"
170
+ }, /*#__PURE__*/_react.default.createElement(_core.IconButton, {
171
+ color: "secondary",
172
+ onClick: function onClick() {
173
+ var newAttr = section.values.filter(function (a, i) {
174
+ return i !== idx;
175
+ });
176
+ index === 0 ? setAttributes(newAttr) : setExclude(newAttr);
177
+ }
178
+ }, /*#__PURE__*/_react.default.createElement(_Delete.default, null)))
179
+ }
180
+ }));
181
+ }), /*#__PURE__*/_react.default.createElement(_core.ListItem, {
182
+ disableGutters: true
183
+ }, /*#__PURE__*/_react.default.createElement(_core.TextField, {
184
+ value: index === 0 ? value1 : value2,
185
+ placeholder: "add new",
186
+ onChange: function onChange(event) {
187
+ index === 0 ? setValue1(event.target.value) : setValue2(event.target.value);
188
+ },
189
+ InputProps: {
190
+ endAdornment: /*#__PURE__*/_react.default.createElement(_core.InputAdornment, {
191
+ position: "end"
192
+ }, /*#__PURE__*/_react.default.createElement(_core.IconButton, {
193
+ onClick: function onClick() {
194
+ if (index === 0) {
195
+ var newAttr = attributes;
196
+ newAttr.push(value1);
197
+ setAttributes(newAttr);
198
+ setValue1('');
199
+ } else {
200
+ var newFeat = exclude;
201
+ newFeat.push(value2);
202
+ setExclude(newFeat);
203
+ setValue2('');
204
+ }
205
+ },
206
+ disabled: index === 0 ? value1 === '' : value2 === '',
207
+ color: "secondary",
208
+ "data-testid": "stringArrayAdd-Feat"
209
+ }, /*#__PURE__*/_react.default.createElement(_Add.default, null)))
210
+ }
211
+ })))));
212
+ }));
213
+ });
214
+ var TrackAdapterSelector = (0, _mobxReact.observer)(function (_ref3) {
215
+ var model = _ref3.model;
216
+ var classes = useStyles();
94
217
  var session = (0, _util.getSession)(model);
95
218
  var trackAdapter = model.trackAdapter; // prettier-ignore
96
219
 
@@ -130,8 +253,8 @@ var TrackAdapterSelector = (0, _mobxReact.observer)(function (_ref2) {
130
253
  })));
131
254
  });
132
255
 
133
- function UnknownAdapterPrompt(_ref3) {
134
- var model = _ref3.model;
256
+ function UnknownAdapterPrompt(_ref4) {
257
+ var model = _ref4.model;
135
258
  var classes = useStyles();
136
259
  return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_core.Typography, {
137
260
  className: classes.spacing
@@ -148,8 +271,8 @@ function UnknownAdapterPrompt(_ref3) {
148
271
  }));
149
272
  }
150
273
 
151
- var TrackTypeSelector = (0, _mobxReact.observer)(function (_ref4) {
152
- var model = _ref4.model;
274
+ var TrackTypeSelector = (0, _mobxReact.observer)(function (_ref5) {
275
+ var model = _ref5.model;
153
276
  var classes = useStyles();
154
277
  var session = (0, _util.getSession)(model);
155
278
  var trackType = model.trackType;
@@ -170,16 +293,16 @@ var TrackTypeSelector = (0, _mobxReact.observer)(function (_ref4) {
170
293
  'data-testid': 'trackTypeSelect'
171
294
  }
172
295
  }
173
- }, trackTypes.map(function (_ref5) {
174
- var name = _ref5.name;
296
+ }, trackTypes.map(function (_ref6) {
297
+ var name = _ref6.name;
175
298
  return /*#__PURE__*/_react.default.createElement(_core.MenuItem, {
176
299
  key: name,
177
300
  value: name
178
301
  }, name);
179
302
  }));
180
303
  });
181
- var TrackAssemblySelector = (0, _mobxReact.observer)(function (_ref6) {
182
- var model = _ref6.model;
304
+ var TrackAssemblySelector = (0, _mobxReact.observer)(function (_ref7) {
305
+ var model = _ref7.model;
183
306
  var session = (0, _util.getSession)(model);
184
307
  var assembly = model.assembly;
185
308
  return /*#__PURE__*/_react.default.createElement(_core.TextField, {
@@ -207,9 +330,15 @@ var TrackAssemblySelector = (0, _mobxReact.observer)(function (_ref6) {
207
330
  }));
208
331
  });
209
332
 
210
- function ConfirmTrack(_ref7) {
211
- var model = _ref7.model;
333
+ function ConfirmTrack(_ref8) {
334
+ var model = _ref8.model;
212
335
  var classes = useStyles();
336
+
337
+ var _useState9 = (0, _react.useState)(true),
338
+ _useState10 = (0, _slicedToArray2.default)(_useState9, 2),
339
+ check = _useState10[0],
340
+ setCheck = _useState10[1];
341
+
213
342
  var trackName = model.trackName,
214
343
  trackAdapter = model.trackAdapter,
215
344
  trackType = model.trackType,
@@ -244,6 +373,7 @@ function ConfirmTrack(_ref7) {
244
373
  return /*#__PURE__*/_react.default.createElement(_core.Typography, null, "Could not recognize this data type.");
245
374
  }
246
375
 
376
+ var supportedForIndexing = (0, _util.supportedIndexingAdapters)(trackAdapter === null || trackAdapter === void 0 ? void 0 : trackAdapter.type);
247
377
  return /*#__PURE__*/_react.default.createElement("div", null, trackAdapter ? /*#__PURE__*/_react.default.createElement(StatusMessage, {
248
378
  trackAdapter: trackAdapter,
249
379
  trackType: trackType
@@ -269,7 +399,18 @@ function ConfirmTrack(_ref7) {
269
399
  model: model
270
400
  }), /*#__PURE__*/_react.default.createElement(TrackAssemblySelector, {
271
401
  model: model
272
- }));
402
+ }), _util.isElectron && supportedForIndexing && /*#__PURE__*/_react.default.createElement(_core.FormControl, null, /*#__PURE__*/_react.default.createElement(_core.FormControlLabel, {
403
+ label: 'Index track for text searching?',
404
+ control: /*#__PURE__*/_react.default.createElement(_core.Checkbox, {
405
+ checked: check,
406
+ onChange: function onChange(e) {
407
+ setCheck(e.target.checked);
408
+ model.setTextIndexTrack(e.target.checked);
409
+ }
410
+ })
411
+ })), _util.isElectron && check && supportedForIndexing ? /*#__PURE__*/_react.default.createElement(TextIndexingConfig, {
412
+ model: model
413
+ }) : null);
273
414
  }
274
415
 
275
416
  var _default = (0, _mobxReact.observer)(ConfirmTrack);
@@ -1,6 +1,10 @@
1
1
  import { Instance } from 'mobx-state-tree';
2
2
  import PluginManager from '@jbrowse/core/PluginManager';
3
3
  import { FileLocation } from '@jbrowse/core/util/types';
4
+ interface IndexingAttr {
5
+ attributes: string[];
6
+ exclude: string[];
7
+ }
4
8
  export default function f(pluginManager: PluginManager): import("mobx-state-tree").IModelType<{
5
9
  id: import("mobx-state-tree").IOptionalIType<import("mobx-state-tree").ISimpleType<string>, [undefined]>;
6
10
  type: import("mobx-state-tree").ISimpleType<"AddTrackWidget">;
@@ -13,9 +17,13 @@ export default function f(pluginManager: PluginManager): import("mobx-state-tree
13
17
  altTrackName: string;
14
18
  altTrackType: string;
15
19
  adapterHint: string;
20
+ textIndexTrack: boolean;
21
+ textIndexingConf: IndexingAttr | undefined;
16
22
  } & {
17
23
  setAdapterHint(obj: string): void;
18
24
  setTrackSource(str: string): void;
25
+ setTextIndexingConf(conf: IndexingAttr): void;
26
+ setTextIndexTrack(flag: boolean): void;
19
27
  setTrackData(obj: FileLocation): void;
20
28
  setIndexTrackData(obj: FileLocation): void;
21
29
  setAssembly(str: string): void;
@@ -40,3 +48,4 @@ export default function f(pluginManager: PluginManager): import("mobx-state-tree
40
48
  }, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>;
41
49
  export declare type AddTrackStateModel = ReturnType<typeof f>;
42
50
  export declare type AddTrackModel = Instance<AddTrackStateModel>;
51
+ export {};
@@ -36,7 +36,9 @@ function f(pluginManager) {
36
36
  altAssemblyName: '',
37
37
  altTrackName: '',
38
38
  altTrackType: '',
39
- adapterHint: ''
39
+ adapterHint: '',
40
+ textIndexTrack: true,
41
+ textIndexingConf: undefined
40
42
  };
41
43
  }).actions(function (self) {
42
44
  return {
@@ -46,6 +48,12 @@ function f(pluginManager) {
46
48
  setTrackSource: function setTrackSource(str) {
47
49
  self.trackSource = str;
48
50
  },
51
+ setTextIndexingConf: function setTextIndexingConf(conf) {
52
+ self.textIndexingConf = conf;
53
+ },
54
+ setTextIndexTrack: function setTextIndexTrack(flag) {
55
+ self.textIndexTrack = flag;
56
+ },
49
57
  setTrackData: function setTrackData(obj) {
50
58
  self.trackData = obj;
51
59
  },
@@ -69,6 +77,8 @@ function f(pluginManager) {
69
77
  self.adapterHint = '';
70
78
  self.indexTrackData = undefined;
71
79
  self.trackData = undefined;
80
+ self.textIndexingConf = undefined;
81
+ self.textIndexTrack = false;
72
82
  }
73
83
  };
74
84
  }).views(function (self) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/plugin-data-management",
3
- "version": "1.7.4",
3
+ "version": "1.7.7",
4
4
  "description": "JBrowse 2 linear genome view",
5
5
  "keywords": [
6
6
  "jbrowse",
@@ -54,5 +54,5 @@
54
54
  "publishConfig": {
55
55
  "access": "public"
56
56
  },
57
- "gitHead": "0a3e0c58055bbab8e3ab0270c139291b96eff403"
57
+ "gitHead": "2c26e04ae942c380bf2f5b79ef7a49cc32b7bfed"
58
58
  }
@@ -8,9 +8,14 @@ import {
8
8
  Typography,
9
9
  makeStyles,
10
10
  } from '@material-ui/core'
11
- import { getSession } from '@jbrowse/core/util'
11
+ import {
12
+ getSession,
13
+ isElectron,
14
+ supportedIndexingAdapters,
15
+ } from '@jbrowse/core/util'
12
16
  import { getConf } from '@jbrowse/core/configuration'
13
17
  import { observer } from 'mobx-react'
18
+ import { getEnv } from 'mobx-state-tree'
14
19
  import { Alert } from '@material-ui/lab'
15
20
 
16
21
  // locals
@@ -46,7 +51,18 @@ function AddTrackWidget({ model }: { model: AddTrackModel }) {
46
51
  const [activeStep, setActiveStep] = useState(0)
47
52
  const classes = useStyles()
48
53
  const session = getSession(model)
49
- const { assembly, trackAdapter, trackData, trackName, trackType } = model
54
+ const { pluginManager } = getEnv(session)
55
+ const { rootModel } = pluginManager
56
+ const { jobsManager } = rootModel
57
+ const {
58
+ assembly,
59
+ trackAdapter,
60
+ trackData,
61
+ trackName,
62
+ trackType,
63
+ textIndexTrack,
64
+ textIndexingConf,
65
+ } = model
50
66
  const [trackErrorMessage, setTrackErrorMessage] = useState<string>()
51
67
 
52
68
  function getStepContent(step: number) {
@@ -86,8 +102,34 @@ function AddTrackWidget({ model }: { model: AddTrackModel }) {
86
102
  sequenceAdapter: getConf(assemblyInstance, ['sequence', 'adapter']),
87
103
  },
88
104
  })
105
+ const textSearchingDefault = {
106
+ attributes: ['Name', 'ID'],
107
+ exclude: ['CDS', 'exon'],
108
+ }
89
109
  if (model.view) {
90
110
  model.view.showTrack(trackId)
111
+ if (isElectron) {
112
+ if (textIndexTrack && supportedIndexingAdapters(trackAdapter.type)) {
113
+ const attr = textIndexingConf || textSearchingDefault
114
+ const indexName = trackName + '-index'
115
+ const indexingParams = {
116
+ ...attr,
117
+ assemblies: [assembly],
118
+ tracks: [trackId],
119
+ indexType: 'perTrack',
120
+ name: indexName,
121
+ timestamp: new Date().toISOString(),
122
+ }
123
+ const newEntry = {
124
+ indexingParams: indexingParams,
125
+ name: indexName,
126
+ cancelCallback: () => {
127
+ jobsManager.abortJob()
128
+ },
129
+ }
130
+ jobsManager.queueJob(newEntry)
131
+ }
132
+ }
91
133
  } else {
92
134
  session.notify(
93
135
  'Open a new view, or use the track selector in an existing view, to view this track',
@@ -1,14 +1,34 @@
1
- import React from 'react'
1
+ import React, { useEffect, useState } from 'react'
2
2
  import { readConfObject } from '@jbrowse/core/configuration'
3
- import { getSession } from '@jbrowse/core/util'
3
+ import {
4
+ supportedIndexingAdapters,
5
+ getSession,
6
+ isElectron,
7
+ } from '@jbrowse/core/util'
4
8
  import {
5
9
  Link,
6
10
  MenuItem,
7
11
  TextField,
8
12
  ListSubheader,
9
13
  Typography,
14
+ FormControl,
15
+ FormControlLabel,
16
+ Checkbox,
17
+ Paper,
18
+ Card,
19
+ List,
20
+ ListItem,
21
+ CardContent,
22
+ IconButton,
23
+ InputLabel,
24
+ InputAdornment,
10
25
  makeStyles,
11
26
  } from '@material-ui/core'
27
+
28
+ // icons
29
+ import DeleteIcon from '@material-ui/icons/Delete'
30
+ import AddIcon from '@material-ui/icons/Add'
31
+ // other
12
32
  import PluginManager from '@jbrowse/core/PluginManager'
13
33
  import { observer } from 'mobx-react'
14
34
  import { getEnv } from 'mobx-state-tree'
@@ -22,6 +42,17 @@ const useStyles = makeStyles(theme => ({
22
42
  spacing: {
23
43
  marginBottom: theme.spacing(3),
24
44
  },
45
+ paper: {
46
+ display: 'flex',
47
+ flexDirection: 'column',
48
+ padding: theme.spacing(1),
49
+ },
50
+ spacer: {
51
+ height: theme.spacing(8),
52
+ },
53
+ card: {
54
+ marginTop: theme.spacing(1),
55
+ },
25
56
  }))
26
57
 
27
58
  function StatusMessage({
@@ -98,6 +129,105 @@ function getTrackTypes(pluginManager: PluginManager) {
98
129
  return pluginManager.getElementTypesInGroup('track') as { name: string }[]
99
130
  }
100
131
 
132
+ const TextIndexingConfig = observer(({ model }: { model: AddTrackModel }) => {
133
+ const classes = useStyles()
134
+ const [value1, setValue1] = useState('')
135
+ const [value2, setValue2] = useState('')
136
+ const [attributes, setAttributes] = useState(['Name', 'ID'])
137
+ const [exclude, setExclude] = useState(['CDS', 'exon'])
138
+ const sections = [
139
+ {
140
+ label: 'Indexing attributes',
141
+ values: attributes,
142
+ },
143
+ {
144
+ label: 'Feature types to exclude',
145
+ values: exclude,
146
+ },
147
+ ]
148
+ useEffect(() => {
149
+ model.setTextIndexingConf({ attributes, exclude })
150
+ }, [model, attributes, exclude])
151
+
152
+ return (
153
+ <Paper className={classes.paper}>
154
+ <InputLabel>Indexing configuration</InputLabel>
155
+ {sections.map((section, index) => (
156
+ <Card raised key={section.label} className={classes.card}>
157
+ <CardContent>
158
+ <InputLabel>{section.label}</InputLabel>
159
+ <List disablePadding>
160
+ {section.values.map((val: string, idx: number) => (
161
+ <ListItem key={idx} disableGutters>
162
+ <TextField
163
+ value={val}
164
+ InputProps={{
165
+ endAdornment: (
166
+ <InputAdornment position="end">
167
+ <IconButton
168
+ color="secondary"
169
+ onClick={() => {
170
+ const newAttr = section.values.filter((a, i) => {
171
+ return i !== idx
172
+ })
173
+ index === 0
174
+ ? setAttributes(newAttr)
175
+ : setExclude(newAttr)
176
+ }}
177
+ >
178
+ <DeleteIcon />
179
+ </IconButton>
180
+ </InputAdornment>
181
+ ),
182
+ }}
183
+ />
184
+ </ListItem>
185
+ ))}
186
+ <ListItem disableGutters>
187
+ <TextField
188
+ value={index === 0 ? value1 : value2}
189
+ placeholder="add new"
190
+ onChange={event => {
191
+ index === 0
192
+ ? setValue1(event.target.value)
193
+ : setValue2(event.target.value)
194
+ }}
195
+ InputProps={{
196
+ endAdornment: (
197
+ <InputAdornment position="end">
198
+ <IconButton
199
+ onClick={() => {
200
+ if (index === 0) {
201
+ const newAttr: string[] = attributes
202
+ newAttr.push(value1)
203
+ setAttributes(newAttr)
204
+ setValue1('')
205
+ } else {
206
+ const newFeat: string[] = exclude
207
+ newFeat.push(value2)
208
+ setExclude(newFeat)
209
+ setValue2('')
210
+ }
211
+ }}
212
+ disabled={index === 0 ? value1 === '' : value2 === ''}
213
+ color="secondary"
214
+ data-testid={`stringArrayAdd-Feat`}
215
+ >
216
+ <AddIcon />
217
+ </IconButton>
218
+ </InputAdornment>
219
+ ),
220
+ }}
221
+ />
222
+ </ListItem>
223
+ </List>
224
+ </CardContent>
225
+ </Card>
226
+ ))}
227
+ </Paper>
228
+ )
229
+ })
230
+
101
231
  const TrackAdapterSelector = observer(({ model }: { model: AddTrackModel }) => {
102
232
  const classes = useStyles()
103
233
  const session = getSession(model)
@@ -233,6 +363,7 @@ const TrackAssemblySelector = observer(
233
363
 
234
364
  function ConfirmTrack({ model }: { model: AddTrackModel }) {
235
365
  const classes = useStyles()
366
+ const [check, setCheck] = useState(true)
236
367
  const { trackName, trackAdapter, trackType, warningMessage, adapterHint } =
237
368
  model
238
369
 
@@ -273,6 +404,7 @@ function ConfirmTrack({ model }: { model: AddTrackModel }) {
273
404
  return <Typography>Could not recognize this data type.</Typography>
274
405
  }
275
406
 
407
+ const supportedForIndexing = supportedIndexingAdapters(trackAdapter?.type)
276
408
  return (
277
409
  <div>
278
410
  {trackAdapter ? (
@@ -293,6 +425,25 @@ function ConfirmTrack({ model }: { model: AddTrackModel }) {
293
425
  <TrackAdapterSelector model={model} />
294
426
  <TrackTypeSelector model={model} />
295
427
  <TrackAssemblySelector model={model} />
428
+ {isElectron && supportedForIndexing && (
429
+ <FormControl>
430
+ <FormControlLabel
431
+ label={'Index track for text searching?'}
432
+ control={
433
+ <Checkbox
434
+ checked={check}
435
+ onChange={e => {
436
+ setCheck(e.target.checked)
437
+ model.setTextIndexTrack(e.target.checked)
438
+ }}
439
+ />
440
+ }
441
+ />
442
+ </FormControl>
443
+ )}
444
+ {isElectron && check && supportedForIndexing ? (
445
+ <TextIndexingConfig model={model} />
446
+ ) : null}
296
447
  </div>
297
448
  )
298
449
  }
@@ -17,7 +17,10 @@ function isAbsoluteUrl(url = '') {
17
17
  return url.startsWith('/')
18
18
  }
19
19
  }
20
-
20
+ interface IndexingAttr {
21
+ attributes: string[]
22
+ exclude: string[]
23
+ }
21
24
  export default function f(pluginManager: PluginManager) {
22
25
  return types
23
26
  .model('AddTrackModel', {
@@ -38,6 +41,8 @@ export default function f(pluginManager: PluginManager) {
38
41
  altTrackType: '',
39
42
 
40
43
  adapterHint: '',
44
+ textIndexTrack: true,
45
+ textIndexingConf: undefined as IndexingAttr | undefined,
41
46
  }))
42
47
  .actions(self => ({
43
48
  setAdapterHint(obj: string) {
@@ -46,6 +51,12 @@ export default function f(pluginManager: PluginManager) {
46
51
  setTrackSource(str: string) {
47
52
  self.trackSource = str
48
53
  },
54
+ setTextIndexingConf(conf: IndexingAttr) {
55
+ self.textIndexingConf = conf
56
+ },
57
+ setTextIndexTrack(flag: boolean) {
58
+ self.textIndexTrack = flag
59
+ },
49
60
  setTrackData(obj: FileLocation) {
50
61
  self.trackData = obj
51
62
  },
@@ -70,6 +81,8 @@ export default function f(pluginManager: PluginManager) {
70
81
  self.adapterHint = ''
71
82
  self.indexTrackData = undefined
72
83
  self.trackData = undefined
84
+ self.textIndexingConf = undefined
85
+ self.textIndexTrack = false
73
86
  },
74
87
  }))
75
88
  .views(self => ({