chem-generic-ui 0.1.44 → 0.1.47
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.
- package/.babelrc +11 -0
- package/.eslintrc +23 -0
- package/.tool-versions +3 -0
- package/chem-generic-ui-v0.1.41.tgz +0 -0
- package/dist/bundle.js +1 -1
- package/dist/bundle.js.LICENSE.txt +70 -0
- package/dist/ds_details.json +57 -0
- package/dist/ds_klass.json +102 -0
- package/dist/ds_props.json +54 -0
- package/dist/index.html +14 -0
- package/dist/sg_details.json +2036 -0
- package/dist/sg_klass.json +850 -0
- package/dist/units_system.json +430 -0
- package/package.json +3 -13
- package/public/ds_details.json +57 -0
- package/public/ds_klass.json +102 -0
- package/public/ds_props.json +54 -0
- package/public/favicon.ico +0 -0
- package/public/images/not_available.svg +1 -0
- package/public/index.html +47 -0
- package/public/logo192.png +0 -0
- package/public/logo512.png +0 -0
- package/public/manifest.json +25 -0
- package/public/robots.txt +3 -0
- package/public/sg_details.json +2036 -0
- package/public/sg_klass.json +850 -0
- package/public/test/ds_props.json +54 -0
- package/public/units_system.json +430 -0
- package/src/app.js +2 -0
- package/src/asserts/bootstrap-theme.min.css +6 -0
- package/src/asserts/bootstrap.min.css +6 -0
- package/src/asserts/main.css +458 -0
- package/src/asserts/main.scss +490 -0
- package/src/components/admin/ElementManager.js +28 -0
- package/src/components/details/GenDSDetails.js +164 -0
- package/src/components/details/GenSgDetails.js +396 -0
- package/src/components/dnd/DragDropItemTypes.js +13 -0
- package/src/components/dnd/GenericElDropTarget.js +160 -0
- package/src/components/dnd/GridDnD.js +42 -0
- package/src/components/dnd/PanelDnD.js +85 -0
- package/src/components/fields/ButtonConfirm.js +45 -0
- package/src/components/fields/ButtonTooltip.js +46 -0
- package/src/components/fields/FieldLabel.js +18 -0
- package/src/components/fields/GenDSMisType.js +20 -0
- package/src/components/fields/GenFormGroupCb.js +17 -0
- package/src/components/fields/GenProperties.js +56 -0
- package/src/components/fields/GenPropertiesFields.js +440 -0
- package/src/components/layers/GenPropertiesLayer.js +178 -0
- package/src/components/layers/LayerModal.js +52 -0
- package/src/components/layers/LayersLayout.js +68 -0
- package/src/components/models/Attachment.js +37 -0
- package/src/components/models/GenericSubField.js +10 -0
- package/src/components/table/DropLinkRenderer.js +35 -0
- package/src/components/table/DropRenderer.js +31 -0
- package/src/components/table/DropTextRenderer.js +25 -0
- package/src/components/table/GenericElTableDropTarget.js +131 -0
- package/src/components/table/GridBtn.js +41 -0
- package/src/components/table/GridEntry.js +75 -0
- package/src/components/table/SamOption.js +53 -0
- package/src/components/table/SelectRenderer.js +34 -0
- package/src/components/table/TableRecord.js +254 -0
- package/src/components/table/UConverterRenderer.js +24 -0
- package/src/components/tools/collate.js +65 -0
- package/src/components/tools/orten.js +171 -0
- package/src/components/tools/utils.js +414 -0
- package/src/data/SystemUnits.js +434 -0
- package/src/data/systemUnits.json +430 -0
- package/src/index.css +13 -0
- package/src/index.html +1 -0
- package/src/index.js +45 -0
- package/src/logo.svg +1 -0
- package/src/simulations/SimuDS.js +52 -0
- package/src/simulations/SimuSG.js +54 -0
- package/webpack.config.js +46 -0
|
@@ -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 { Panel } 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
|
+
<Panel>
|
|
376
|
+
<Panel.Body style={{ position: 'relative', minHeight: 260, overflowY: 'unset' }}>
|
|
377
|
+
{this.elementalPropertiesItem(segment)}
|
|
378
|
+
</Panel.Body>
|
|
379
|
+
</Panel>
|
|
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;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
ELEMENT: 'element',
|
|
3
|
+
SAMPLE: 'sample',
|
|
4
|
+
MOLECULE: 'molecule',
|
|
5
|
+
LAYOUT: 'layout',
|
|
6
|
+
GENERAL: 'general',
|
|
7
|
+
DATA: 'data',
|
|
8
|
+
UNLINKED_DATA: 'unlinked_data',
|
|
9
|
+
DATASET: 'dataset',
|
|
10
|
+
CONTAINER: 'container',
|
|
11
|
+
ELEMENT_FIELD: 'element_field',
|
|
12
|
+
GENERIC_GRID: 'generic_grid'
|
|
13
|
+
};
|
|
@@ -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> <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} />
|
|
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);
|