chem-generic-ui 0.1.34 → 0.1.37

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 (102) hide show
  1. package/.babelrc +17 -0
  2. package/.eslintrc +23 -0
  3. package/.tool-versions +3 -0
  4. package/package.json +55 -38
  5. package/public/ds_details.json +57 -0
  6. package/public/ds_klass.json +102 -0
  7. package/public/ds_props.json +54 -0
  8. package/public/favicon.ico +0 -0
  9. package/public/images/not_available.svg +1 -0
  10. package/public/index.html +47 -0
  11. package/public/logo192.png +0 -0
  12. package/public/logo512.png +0 -0
  13. package/public/manifest.json +25 -0
  14. package/public/robots.txt +3 -0
  15. package/public/sg_details.json +2036 -0
  16. package/public/sg_klass.json +850 -0
  17. package/public/test/ds_props.json +54 -0
  18. package/{dist/data/systemUnits.json → public/units_system.json} +0 -0
  19. package/src/app.js +50 -0
  20. package/{dist → src}/asserts/main.css +0 -7
  21. package/{dist → src}/asserts/main.scss +1 -7
  22. package/src/components/admin/ElementManager.js +28 -0
  23. package/src/components/details/GenDSDetails.js +164 -0
  24. package/src/components/details/GenSgDetails.js +396 -0
  25. package/{dist → src}/components/dnd/DragDropItemTypes.js +1 -8
  26. package/src/components/dnd/GenericElDropTarget.js +160 -0
  27. package/src/components/dnd/GridDnD.js +42 -0
  28. package/src/components/dnd/PanelDnD.js +85 -0
  29. package/src/components/fields/ButtonConfirm.js +45 -0
  30. package/src/components/fields/ButtonTooltip.js +46 -0
  31. package/src/components/fields/FieldLabel.js +18 -0
  32. package/src/components/fields/GenDSMisType.js +20 -0
  33. package/src/components/fields/GenFormGroupCb.js +17 -0
  34. package/src/components/fields/GenProperties.js +56 -0
  35. package/src/components/fields/GenPropertiesFields.js +318 -0
  36. package/src/components/layers/GenPropertiesLayer.js +176 -0
  37. package/src/components/layers/LayerModal.js +52 -0
  38. package/src/components/layers/LayersLayout.js +68 -0
  39. package/src/components/models/Attachment.js +37 -0
  40. package/src/components/models/GenericSubField.js +10 -0
  41. package/src/components/table/DropLinkRenderer.js +35 -0
  42. package/src/components/table/DropRenderer.js +31 -0
  43. package/src/components/table/DropTextRenderer.js +25 -0
  44. package/src/components/table/GenericElTableDropTarget.js +131 -0
  45. package/src/components/table/GridBtn.js +41 -0
  46. package/src/components/table/GridEntry.js +75 -0
  47. package/src/components/table/SamOption.js +53 -0
  48. package/src/components/table/SelectRenderer.js +34 -0
  49. package/src/components/table/TableRecord.js +254 -0
  50. package/src/components/table/UConverterRenderer.js +24 -0
  51. package/src/components/tools/collate.js +65 -0
  52. package/src/components/tools/orten.js +171 -0
  53. package/src/components/tools/utils.js +414 -0
  54. package/src/data/SystemUnits.js +434 -0
  55. package/src/data/systemUnits.json +430 -0
  56. package/{dist → src}/index.css +0 -0
  57. package/src/index.html +1 -0
  58. package/src/index.js +45 -0
  59. package/{dist → src}/logo.svg +0 -0
  60. package/src/simulations/SimuDS.js +52 -0
  61. package/src/simulations/SimuSG.js +54 -0
  62. package/webpack.config.js +52 -0
  63. package/dist/app.js +0 -105
  64. package/dist/components/admin/ElementManager.js +0 -54
  65. package/dist/components/details/GenDSDetails.js +0 -273
  66. package/dist/components/details/GenSgDetails.js +0 -566
  67. package/dist/components/dnd/GenericElDropTarget.js +0 -274
  68. package/dist/components/dnd/GridDnD.js +0 -77
  69. package/dist/components/dnd/PanelDnD.js +0 -171
  70. package/dist/components/fields/ButtonConfirm.js +0 -76
  71. package/dist/components/fields/ButtonTooltip.js +0 -88
  72. package/dist/components/fields/FieldLabel.js +0 -38
  73. package/dist/components/fields/GenDSMisType.js +0 -44
  74. package/dist/components/fields/GenFormGroupCb.js +0 -31
  75. package/dist/components/fields/GenProperties.js +0 -83
  76. package/dist/components/fields/GenPropertiesFields.js +0 -616
  77. package/dist/components/flow/FlowView.js +0 -88
  78. package/dist/components/flow/FlowViewerModal.js +0 -81
  79. package/dist/components/flow/LayerNode.js +0 -59
  80. package/dist/components/layers/GenPropertiesLayer.js +0 -280
  81. package/dist/components/layers/LayerModal.js +0 -81
  82. package/dist/components/layers/LayersLayout.js +0 -88
  83. package/dist/components/models/Attachment.js +0 -73
  84. package/dist/components/models/GenericSubField.js +0 -37
  85. package/dist/components/table/DropLinkRenderer.js +0 -55
  86. package/dist/components/table/DropRenderer.js +0 -45
  87. package/dist/components/table/DropTextRenderer.js +0 -45
  88. package/dist/components/table/GenericElTableDropTarget.js +0 -252
  89. package/dist/components/table/GridBtn.js +0 -102
  90. package/dist/components/table/GridEntry.js +0 -163
  91. package/dist/components/table/SamOption.js +0 -87
  92. package/dist/components/table/SelectRenderer.js +0 -52
  93. package/dist/components/table/TableRecord.js +0 -454
  94. package/dist/components/table/UConverterRenderer.js +0 -41
  95. package/dist/components/tools/collate.js +0 -103
  96. package/dist/components/tools/orten.js +0 -294
  97. package/dist/components/tools/utils.js +0 -593
  98. package/dist/data/SystemUnits.js +0 -588
  99. package/dist/index.js +0 -39
  100. package/dist/simulations/SimWF.js +0 -123
  101. package/dist/simulations/SimuDS.js +0 -118
  102. package/dist/simulations/SimuSG.js +0 -123
@@ -0,0 +1,396 @@
1
+ /* eslint-disable no-restricted-globals */
2
+ /* eslint-disable camelcase */
3
+ /* eslint-disable react/forbid-prop-types */
4
+ import React, { Component } from 'react';
5
+ import PropTypes from 'prop-types';
6
+ import { findIndex, cloneDeep, sortBy } from 'lodash';
7
+ import { Card } from 'react-bootstrap';
8
+ // import { DragDropContext } from 'react-dnd';
9
+ // import HTML5Backend from 'react-dnd-html5-backend';
10
+ import LayersLayout from '../layers/LayersLayout';
11
+ import { genUnits, toBool, toNum, swapAryEls, unitConversion, uploadFiles } from '../tools/utils';
12
+ import { getWFNode, orgLayerObject, getFlowLayer, addToObject, removeFromObject, reformCondFields } from '../tools/orten';
13
+ import organizeSubValues from '../tools/collate';
14
+ import LayerModal from '../layers/LayerModal';
15
+
16
+ class SegmentDetails extends Component {
17
+ constructor(props) {
18
+ super(props);
19
+ this.state = { showViewLayer: false, selectedLayerKey: '' };
20
+ this.handleInputChange = this.handleInputChange.bind(this);
21
+ this.handleSubChange = this.handleSubChange.bind(this);
22
+ this.handleUnitClick = this.handleUnitClick.bind(this);
23
+ this.handleReload = this.handleReload.bind(this);
24
+ this.handleAddLayer = this.handleAddLayer.bind(this);
25
+ this.setViewLayer = this.setViewLayer.bind(this);
26
+ this.dropLayer = this.dropLayer.bind(this);
27
+ this.removeLayer = this.removeLayer.bind(this);
28
+ this.handleWFNext = this.handleWFNext.bind(this);
29
+ }
30
+
31
+ setViewLayer() {
32
+ this.setState({ showViewLayer: !this.state.showViewLayer });
33
+ }
34
+
35
+ handleSubChange(layer, obj, valueOnly = false) {
36
+ const { segment } = this.props;
37
+ const { properties } = segment;
38
+ if (!valueOnly) {
39
+ const subFields = properties.layers[`${layer}`].fields
40
+ .find(m => m.field === obj.f.field).sub_fields || [];
41
+ const idxSub = subFields.findIndex(m => m.id === obj.sub.id);
42
+ subFields.splice(idxSub, 1, obj.sub);
43
+ properties.layers[`${layer}`].fields
44
+ .find(e => e.field === obj.f.field).sub_fields = subFields;
45
+ }
46
+ properties.layers[`${layer}`].fields
47
+ .find(e => e.field === obj.f.field).sub_values = obj.f.sub_values || [];
48
+ segment.properties = properties;
49
+ segment.changed = true;
50
+ this.props.onChange(segment);
51
+ }
52
+
53
+ handleInputChange(event, field, layer, type = 'text') {
54
+ const { segment } = this.props;
55
+ const { properties } = segment;
56
+ let value = '';
57
+ let propsChange = true;
58
+ switch (type) {
59
+ case 'drop-layer':
60
+ this.dropLayer(field, layer);
61
+ propsChange = false;
62
+ break;
63
+ case 'layer-remove':
64
+ event.stopPropagation();
65
+ this.removeLayer(field, layer);
66
+ propsChange = false;
67
+ break;
68
+ case 'layer-modal':
69
+ event.stopPropagation();
70
+ propsChange = false;
71
+ this.setState({ selectedLayerKey: layer.key, showViewLayer: true });
72
+ break;
73
+ case 'wf-next':
74
+ propsChange = false;
75
+ this.handleWFNext(event, layer);
76
+ break;
77
+ case 'checkbox':
78
+ value = event.target.checked;
79
+ break;
80
+ case 'formula-field':
81
+ if (event.target) {
82
+ ({ value } = event.target);
83
+ } else {
84
+ value = event;
85
+ }
86
+ break;
87
+ case 'upload': {
88
+ const vals = uploadFiles(properties, event, field, layer);
89
+ value = vals[0];
90
+ if (vals[1].length > 0) segment.files = (segment.files || []).concat(vals[1]);
91
+ if (vals.length > 2) {
92
+ const fileIdx = findIndex((segment.files || []), o => o.uid === event.uid);
93
+ if (fileIdx >= 0 && segment.files && segment.files.length > 0) {
94
+ segment.files.splice(fileIdx, 1);
95
+ }
96
+ }
97
+ break;
98
+ }
99
+ case 'select':
100
+ value = event ? event.value : null;
101
+ break;
102
+ case 'drag_molecule':
103
+ value = event;
104
+ break;
105
+ case 'integer':
106
+ ({ value } = event.target);
107
+ value = Math.trunc(value);
108
+ break;
109
+ default:
110
+ ({ value } = event.target);
111
+ }
112
+ if (propsChange) {
113
+ properties.layers[`${layer}`].fields.find(e => e.field === field).value = value;
114
+ if (type === 'system-defined' && (!properties.layers[`${layer}`].fields.find(e => e.field === field).value_system || properties.layers[`${layer}`].fields.find(e => e.field === field).value_system === '')) {
115
+ const opt = properties.layers[`${layer}`].fields
116
+ .find(e => e.field === field).option_layers;
117
+ properties.layers[`${layer}`].fields
118
+ .find(e => e.field === field).value_system = genUnits(opt)[0].key;
119
+ }
120
+ segment.properties = properties;
121
+ segment.changed = true;
122
+ this.props.onChange(segment);
123
+ }
124
+ }
125
+
126
+ handleUnitClick(layer, obj) {
127
+ const { segment } = this.props;
128
+ const { properties } = segment;
129
+ const newVal = unitConversion(obj.option_layers, obj.value_system, obj.value);
130
+ properties.layers[`${layer}`].fields
131
+ .find(e => e.field === obj.field).value_system = obj.value_system;
132
+ properties.layers[`${layer}`].fields.find(e => e.field === obj.field).value = newVal;
133
+ segment.properties = properties;
134
+ segment.changed = true;
135
+ this.props.onChange(segment);
136
+ }
137
+
138
+ handleReload() {
139
+ const { klass, segment } = this.props;
140
+ const newProps = cloneDeep(klass.properties_release);
141
+ newProps.klass_uuid = klass.uuid;
142
+ Object.keys(newProps.layers).forEach((key) => {
143
+ const newLayer = newProps.layers[key] || {};
144
+ const curFields = (segment.properties.layers[key] && segment.properties.layers[key].fields)
145
+ || [];
146
+ (newLayer.fields || []).forEach((f, idx) => {
147
+ const curIdx = findIndex(curFields, o => o.field === f.field);
148
+ if (curIdx >= 0) {
149
+ const curVal = segment.properties.layers[key].fields[curIdx].value;
150
+ const curType = typeof curVal;
151
+ if (['select', 'text', 'textarea', 'formula-field'].includes(newProps.layers[key].fields[idx].type)) {
152
+ newProps.layers[key].fields[idx].value = curType !== 'undefined' ? curVal.toString() : '';
153
+ }
154
+ if (newProps.layers[key].fields[idx].type === 'integer') {
155
+ newProps.layers[key].fields[idx].value = (curType === 'undefined' || curType === 'boolean' || isNaN(curVal)) ? 0 : parseInt(curVal, 10);
156
+ }
157
+ if (newProps.layers[key].fields[idx].type === 'checkbox') {
158
+ newProps.layers[key].fields[idx].value = curType !== 'undefined' ? toBool(curVal) : false;
159
+ }
160
+ if (newProps.layers[key].fields[idx].type === 'system-defined') {
161
+ const units = genUnits(newProps.layers[key].fields[idx].option_layers);
162
+ const vs = units.find(u =>
163
+ u.key === segment.properties.layers[key].fields[curIdx].value_system);
164
+ newProps.layers[key].fields[idx].value_system = (vs && vs.key) || units[0].key;
165
+ newProps.layers[key].fields[idx].value = toNum(curVal);
166
+ }
167
+ if (newProps.layers[key].fields[idx].type === 'input-group') {
168
+ if (segment.properties.layers[key].fields[curIdx].type !==
169
+ newProps.layers[key].fields[idx].type) {
170
+ newProps.layers[key].fields[idx].value = undefined;
171
+ } else {
172
+ const nSubs = newProps.layers[key].fields[idx].sub_fields || [];
173
+ const cSubs = segment.properties.layers[key].fields[curIdx].sub_fields || [];
174
+ const exSubs = [];
175
+ if (nSubs.length < 1) {
176
+ newProps.layers[key].fields[idx].value = undefined;
177
+ } else {
178
+ nSubs.forEach((nSub) => {
179
+ const hitSub = cSubs.find(c => c.id === nSub.id) || {};
180
+ if (nSub.type === 'label') { exSubs.push(nSub); }
181
+ if (nSub.type === 'text') {
182
+ if (hitSub.type === 'label') {
183
+ exSubs.push(nSub);
184
+ } else { exSubs.push({ ...nSub, value: (hitSub.value || '').toString() }); }
185
+ }
186
+
187
+ if (['number', 'system-defined'].includes(nSub.type)) {
188
+ const nvl = (typeof hitSub.value === 'undefined' || hitSub.value == null || hitSub.value.length === 0) ? '' : toNum(hitSub.value);
189
+ if (nSub.option_layers === hitSub.option_layers) {
190
+ exSubs.push({ ...nSub, value: nvl, value_system: hitSub.value_system });
191
+ } else {
192
+ exSubs.push({ ...nSub, value: nvl });
193
+ }
194
+ }
195
+ });
196
+ }
197
+ newProps.layers[key].fields[idx].sub_fields = exSubs;
198
+ }
199
+ }
200
+ if (newProps.layers[key].fields[idx].type === 'upload') {
201
+ if (segment.properties.layers[key].fields[curIdx].type ===
202
+ newProps.layers[key].fields[idx].type) {
203
+ newProps.layers[key].fields[idx].value =
204
+ segment.properties.layers[key].fields[curIdx].value;
205
+ } else {
206
+ newProps.layers[key].fields[idx].value = {};
207
+ }
208
+ }
209
+ if (newProps.layers[key].fields[idx].type === 'table') {
210
+ if (segment.properties.layers[key].fields[curIdx].type !==
211
+ newProps.layers[key].fields[idx].type) {
212
+ newProps.layers[key].fields[idx].sub_values = [];
213
+ } else {
214
+ newProps.layers[key].fields[idx].sub_values =
215
+ organizeSubValues(
216
+ newProps.layers[key].fields[idx],
217
+ segment.properties.layers[key].fields[curIdx]
218
+ );
219
+ }
220
+ }
221
+ }
222
+ });
223
+ });
224
+ segment.properties = newProps;
225
+ segment.changed = true;
226
+ this.props.onChange(segment);
227
+ }
228
+
229
+ handleAddLayer(event, _layer) {
230
+ const { segment } = this.props;
231
+ const { selectedLayerKey } = this.state;
232
+ const layer = _layer;
233
+ const { layers } = segment.properties;
234
+ const sortedLayers = sortBy(layers, ['position', 'wf_position']);
235
+ const idx = sortedLayers.findIndex(e => e.key === selectedLayerKey);
236
+ // re-set added layer attributes
237
+ const selectedLayer = sortedLayers[idx];
238
+ layer.position = selectedLayer.position;
239
+ layer.wf_position = selectedLayer.wf_position + 1;
240
+ layer.wf = false;
241
+ layer.wf_uuid = null;
242
+ // layer is standard layer (from released)
243
+ const cnt = sortedLayers
244
+ .filter(e => e.key === layer.key || e.key.startsWith(`${layer.key}.`)).length;
245
+ if (cnt > 0) {
246
+ const origKey = layer.key;
247
+ layer.key = `${layer.key}.${cnt}`;
248
+ layer.fields = reformCondFields(layer, origKey);
249
+ }
250
+ // insert new layer
251
+ sortedLayers.splice(idx + 1, 0, layer);
252
+ // re-count wf_position
253
+ sortedLayers.filter(e => e.position === selectedLayer.position).map((e, ix) => {
254
+ const el = e;
255
+ el.wf_position = ix;
256
+ return el;
257
+ });
258
+ const ll = orgLayerObject(sortedLayers);
259
+ segment.properties.layers = ll;
260
+ this.setState(
261
+ { selectedLayerKey: layer.key, showViewLayer: false },
262
+ this.props.onChange(segment)
263
+ );
264
+ }
265
+
266
+ dropLayer(_source, _target) {
267
+ const { segment } = this.props;
268
+ const { layers } = segment.properties;
269
+ let sortedLayers = sortBy(layers, ['position', 'wf_position']);
270
+ // swap or move
271
+ const srcIdx = sortedLayers.findIndex(e => e.key === _source);
272
+ const tmpSrc = sortedLayers[srcIdx];
273
+ let tarIdx = sortedLayers.findIndex(e => e.key === _target);
274
+ if (Math.abs(srcIdx - tarIdx) === 1) {
275
+ sortedLayers = swapAryEls(sortedLayers, srcIdx, tarIdx);
276
+ } else {
277
+ // delete src
278
+ sortedLayers.splice(srcIdx, 1);
279
+ // keep tar
280
+ tarIdx = sortedLayers.findIndex(e => e.key === _target);
281
+ const tmpTar = sortedLayers[tarIdx];
282
+ // prepare new layer
283
+ tmpSrc.position = tmpTar.position;
284
+ tmpSrc.wf_position = (tmpTar.wf_position || 0) + 1;
285
+ // insert new layer
286
+ sortedLayers.splice(tarIdx + 1, 0, tmpSrc);
287
+ }
288
+ // re-count wf_position
289
+ sortedLayers.filter(e => e.position === tmpSrc.position).map((e, idx) => {
290
+ const el = e;
291
+ el.wf_position = idx;
292
+ return el;
293
+ });
294
+ const ll = orgLayerObject(sortedLayers);
295
+ segment.properties.layers = ll;
296
+ segment.changed = true;
297
+ this.props.onChange(segment);
298
+ }
299
+
300
+ removeLayer(elId, layer) {
301
+ const { segment } = this.props;
302
+ const { layers } = segment.properties;
303
+ const sortedLayers = sortBy(layers, ['position', 'wf_position']);
304
+ const selectedIdx = sortedLayers.findIndex(e => e.key === layer.key);
305
+ const selected = sortedLayers[selectedIdx];
306
+ sortedLayers.splice(selectedIdx, 1);
307
+ sortedLayers.filter(e => e.position === selected.position).map((e, idx) => {
308
+ const el = e;
309
+ el.wf_position = idx;
310
+ return el;
311
+ });
312
+ segment.properties.layers = orgLayerObject(sortedLayers);
313
+ segment.changed = true;
314
+ this.props.onChange(segment);
315
+ }
316
+
317
+ handleWFNext(event, layer) {
318
+ const value = event ? event.value : null;
319
+ if (value) {
320
+ const { segment } = this.props;
321
+ const { properties, properties_release } = segment;
322
+ // next step value if exists
323
+ let rmNeeded = false;
324
+ const preValue = properties.layers[`${layer}`].fields.find(e => e.field === '_wf_next').value;
325
+ if (value !== preValue) {
326
+ if (preValue && preValue !== '' && preValue !== value) {
327
+ rmNeeded = true;
328
+ }
329
+ const { flow } = properties_release;
330
+ const preLayer = properties.layers[`${layer}`];
331
+ // value is the next node's id
332
+ const nxLayer = getFlowLayer(flow, value, layer, preLayer.wf_position);
333
+ if (nxLayer) {
334
+ properties.layers = addToObject(properties.layers, layer, nxLayer);
335
+ }
336
+ if (rmNeeded) {
337
+ properties.layers = removeFromObject(properties.layers, layer, getWFNode(flow, preValue));
338
+ }
339
+ // update next step value
340
+ properties.layers[`${layer}`].fields.find(e => e.field === '_wf_next').value = value;
341
+ segment.properties = properties;
342
+ segment.changed = true;
343
+ // this.props.onChange(segment, () => renderFlowModal(segment, false));
344
+ this.props.onChange(segment); // cb move to e.g. SampleDetails.js
345
+ }
346
+ }
347
+ }
348
+
349
+ elementalPropertiesItem(segment) {
350
+ const layersLayout = LayersLayout(
351
+ segment.properties.layers,
352
+ segment.properties_release.select_options || {},
353
+ this.handleInputChange,
354
+ this.handleSubChange,
355
+ this.handleUnitClick,
356
+ [], 0, false, true
357
+ );
358
+ return (<div style={{ margin: '5px' }}>{layersLayout}</div>);
359
+ }
360
+
361
+ render() {
362
+ const { uiCtrl, segment } = this.props;
363
+ if (!uiCtrl || Object.keys(segment).length === 0) return null;
364
+ const { showViewLayer } = this.state;
365
+ const addLayerModal = (
366
+ <LayerModal
367
+ show={showViewLayer}
368
+ layers={cloneDeep(segment.properties_release.layers) || {}}
369
+ fnClose={this.setViewLayer}
370
+ fnAdd={this.handleAddLayer}
371
+ />
372
+ );
373
+ return (
374
+ <div>
375
+ <Card>
376
+ <Card.Body style={{ position: 'relative', minHeight: 260, overflowY: 'unset' }}>
377
+ {this.elementalPropertiesItem(segment)}
378
+ </Card.Body>
379
+ </Card>
380
+ {addLayerModal}
381
+ </div>
382
+ );
383
+ }
384
+ }
385
+
386
+ SegmentDetails.propTypes = {
387
+ uiCtrl: PropTypes.bool.isRequired,
388
+ segment: PropTypes.object,
389
+ klass: PropTypes.object,
390
+ onChange: PropTypes.func.isRequired,
391
+ };
392
+
393
+ SegmentDetails.defaultProps = { segment: {}, klass: {} };
394
+
395
+ // export default DragDropContext(HTML5Backend)(SegmentDetails);
396
+ export default SegmentDetails;
@@ -1,10 +1,4 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
- var _default = {
1
+ export default {
8
2
  ELEMENT: 'element',
9
3
  SAMPLE: 'sample',
10
4
  MOLECULE: 'molecule',
@@ -17,4 +11,3 @@ var _default = {
17
11
  ELEMENT_FIELD: 'element_field',
18
12
  GENERIC_GRID: 'generic_grid'
19
13
  };
20
- exports.default = _default;
@@ -0,0 +1,160 @@
1
+ /* eslint-disable no-unused-vars */
2
+ /* eslint-disable jsx-a11y/anchor-is-valid */
3
+ /* eslint-disable jsx-a11y/click-events-have-key-events */
4
+ /* eslint-disable jsx-a11y/interactive-supports-focus */
5
+ /* eslint-disable react/prop-types */
6
+ /* eslint-disable no-restricted-globals */
7
+ import React, { Component } from 'react';
8
+ import PropTypes from 'prop-types';
9
+ import { v4 as uuid } from 'uuid';
10
+ import { DropTarget } from 'react-dnd';
11
+ // import Aviator from 'aviator';
12
+ import { Tooltip, OverlayTrigger, Popover } from 'react-bootstrap';
13
+ // import UIStore from '../stores/UIStore';
14
+
15
+ // const handleSampleClick = (type, id) => {
16
+ // const { currentCollection, isSync } = UIStore.getState();
17
+ // if (!isNaN(id)) type += `/${id}`;
18
+ // const collectionUrl = `${currentCollection.id}/${type}`;
19
+ // Aviator.navigate(isSync ? `/scollection/${collectionUrl}` : `/collection/${collectionUrl}`);
20
+ // };
21
+
22
+ // const handleElementClick = (type, id) => {
23
+ // const { currentCollection, isSync } = UIStore.getState();
24
+ // if (!isNaN(id)) type += `/${id}`;
25
+ // const collectionUrl = `${currentCollection.id}/${type}`;
26
+ // Aviator.navigate(isSync ? `/scollection/${collectionUrl}` : `/collection/${collectionUrl}`);
27
+ // };
28
+
29
+ const show = (opt, iconClass, onLink) => {
30
+ if (opt.value && opt.value.el_id) {
31
+ const tips = opt.value.el_tip && opt.value.el_tip.split('@@');
32
+ const tip1 = (tips && tips.length >= 1 && tips[0]) || '';
33
+ const tip2 = (tips && tips.length >= 2 && tips[1]) || '';
34
+ const tit = (<div>{tip1}<br />{tip2}</div>);
35
+ const pop = (
36
+ <Popover id="popover-svg" title={tit} style={{ maxWidth: 'none', maxHeight: 'none' }}>
37
+ <img src={opt.value.el_svg} style={{ height: '26vh', width: '26vh' }} alt="" />
38
+ </Popover>
39
+ );
40
+ let label = opt.value.el_label;
41
+ const simg = (path, tip, txt) => ((path && path !== '') ? (
42
+ <div className="s-img">
43
+ <OverlayTrigger trigger={['hover']} placement="left" rootClose onHide={null} overlay={pop}>
44
+ <img src={path} alt="" />
45
+ </OverlayTrigger>&nbsp;<span className="data">{txt}</span>
46
+ </div>
47
+ ) : (<OverlayTrigger placement="top" overlay={<Tooltip id={uuid()}>{tip1}<br />{tip2}</Tooltip>}><div className="data">{txt}</div></OverlayTrigger>));
48
+ if (opt.value.el_type === 'sample') {
49
+ if (opt.value.is_new !== true) {
50
+ label = (
51
+ // <a role="link"
52
+ // onClick={() => handleSampleClick(opt.value.el_type, opt.value.el_id)}
53
+ // style={{ cursor: 'pointer' }}>
54
+ <a role="link" onClick={() => onLink(opt.value.el_type, opt.value.el_id)} style={{ cursor: 'pointer' }}>
55
+ <span className="reaction-material-link">{label}</span>
56
+ </a>
57
+ );
58
+ }
59
+ }
60
+ if (opt.value.el_type === 'element') {
61
+ label = (
62
+ // <a role="link"
63
+ // onClick={() => handleElementClick(opt.value.el_klass, opt.value.el_id)}
64
+ // style={{ cursor: 'pointer' }}>
65
+ <a role="link" onClick={() => onLink(opt.value.el_klass, opt.value.el_id)} style={{ cursor: 'pointer' }}>
66
+ <i className={opt.value.icon_name} />&nbsp;
67
+ <span className="reaction-material-link">{label}</span>
68
+ </a>
69
+ );
70
+ }
71
+ return simg(opt.value.el_svg, opt.value.el_tip, label);
72
+ }
73
+ if (iconClass === 'element') {
74
+ return (<span className="fa fa-link icon_generic_nav indicator" />);
75
+ }
76
+ return (<span className={`icon-${iconClass} indicator`} />);
77
+ };
78
+
79
+ const source = (type, props, id) => {
80
+ let isAssoc = false;
81
+ const taggable = (props && props.tag && props.tag.taggable_data) || {};
82
+ if (taggable.element && taggable.element.id === id) {
83
+ isAssoc = false;
84
+ } else {
85
+ isAssoc = !!(taggable.reaction_id || taggable.wellplate_id || taggable.element);
86
+ }
87
+
88
+ switch (type) {
89
+ case 'molecule':
90
+ return {
91
+ el_id: props.molecule.id,
92
+ el_type: 'molecule',
93
+ el_label: props.molecule_name_label,
94
+ el_tip: `${props.molecule.inchikey}@@${props.molecule.cano_smiles}`,
95
+ };
96
+ case 'sample':
97
+ return {
98
+ el_id: props.id,
99
+ is_new: true,
100
+ cr_opt: isAssoc === true ? 1 : 0,
101
+ isAssoc,
102
+ el_type: 'sample',
103
+ el_label: props.short_label,
104
+ el_tip: props.short_label
105
+ };
106
+ case 'element':
107
+ return {
108
+ el_id: props.id,
109
+ el_type: 'element',
110
+ icon_name: (props.element_klass && props.element_klass.icon_name) || '',
111
+ el_klass: props.type,
112
+ el_label: props.short_label,
113
+ el_tip: `${props.label}@@${props.name}`
114
+ };
115
+ default:
116
+ return {
117
+ el_id: props.id,
118
+ el_type: props.type,
119
+ el_label: props.short_label,
120
+ el_tip: props.short_label,
121
+ };
122
+ }
123
+ };
124
+
125
+ const dropTarget = {
126
+ drop(targetProps, monitor) {
127
+ const sourceProps = monitor.getItem().element;
128
+ const sourceTag = source(targetProps.opt.type.split('_')[1], sourceProps, targetProps.opt.id);
129
+ targetProps.onDrop(sourceTag);
130
+ },
131
+ canDrop(_targetProps, _monitor) {
132
+ return true;
133
+ },
134
+ };
135
+
136
+ const dropCollect = (connect, monitor) => ({
137
+ connectDropTarget: connect.dropTarget(),
138
+ isOver: monitor.isOver(),
139
+ canDrop: monitor.canDrop()
140
+ });
141
+
142
+ class GenericElDropTarget extends Component {
143
+ render() {
144
+ const {
145
+ connectDropTarget, isOver, canDrop, opt, onLink
146
+ } = this.props;
147
+ const iconClass = (opt.dndItems && opt.dndItems[0] === 'molecule' ? 'sample' : opt.dndItems[0]);
148
+ const className = `target${isOver ? ' is-over' : ''}${canDrop ? ' can-drop' : ''}`;
149
+ return connectDropTarget(<div className={className}>{show(opt, iconClass, onLink)}</div>);
150
+ }
151
+ }
152
+
153
+ export default
154
+ DropTarget(props => props.opt.dndItems, dropTarget, dropCollect)(GenericElDropTarget);
155
+
156
+ GenericElDropTarget.propTypes = {
157
+ connectDropTarget: PropTypes.func.isRequired,
158
+ isOver: PropTypes.bool.isRequired,
159
+ canDrop: PropTypes.bool.isRequired,
160
+ };
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import { DragSource, DropTarget } from 'react-dnd';
3
+ import { compose } from 'redux';
4
+
5
+ const orderSource = {
6
+ beginDrag(props) {
7
+ const { field, rowValue } = props;
8
+ return { fid: field, rId: rowValue.id };
9
+ },
10
+ };
11
+
12
+ const orderTarget = {
13
+ drop(props, monitor) {
14
+ const { field, rowValue, handleMove } = props;
15
+ const tar = { fid: field, rId: rowValue.id };
16
+ const src = monitor.getItem();
17
+ if (tar.fid === src.fid && tar.rId !== src.rId) handleMove(src.rId, tar.rId);
18
+ },
19
+ };
20
+
21
+ const orderDragCollect = (connect, monitor) => ({
22
+ connectDragSource: connect.dragSource(),
23
+ isDragging: monitor.isDragging(),
24
+ });
25
+
26
+ const orderDropCollect = (connect, monitor) => ({
27
+ connectDropTarget: connect.dropTarget(),
28
+ isOver: monitor.isOver(),
29
+ canDrop: monitor.canDrop(),
30
+ });
31
+
32
+ const GridDnD = ({
33
+ connectDragSource, connectDropTarget, isDragging, isOver, canDrop,
34
+ }) => {
35
+ const className = `generic_grid_dnd${isOver ? ' is-over' : ''}${canDrop ? ' can-drop' : ''}${isDragging ? ' is-dragging' : ''}`;
36
+ return compose(connectDragSource, connectDropTarget)(<div className={className}><div className="dnd-btn"><span className="text-info fa fa-arrows" /></div></div>);
37
+ };
38
+
39
+ export default compose(
40
+ DragSource(s => s.type, orderSource, orderDragCollect),
41
+ DropTarget(s => s.type, orderTarget, orderDropCollect)
42
+ )(GridDnD);