chem-generic-ui 0.1.36 → 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 (63) hide show
  1. package/.babelrc +17 -0
  2. package/.eslintrc +23 -0
  3. package/.tool-versions +3 -0
  4. package/package.json +51 -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/public/units_system.json +430 -0
  19. package/src/app.js +50 -0
  20. package/src/asserts/main.css +458 -0
  21. package/src/asserts/main.scss +490 -0
  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/src/components/dnd/DragDropItemTypes.js +13 -0
  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/src/index.css +13 -0
  57. package/src/index.html +1 -0
  58. package/src/index.js +45 -0
  59. package/src/logo.svg +1 -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/bundle.min.js +0 -1
@@ -0,0 +1,75 @@
1
+ /* eslint-disable react/forbid-prop-types */
2
+ import React from 'react';
3
+ import { FormControl, InputGroup } from 'react-bootstrap';
4
+
5
+ const setCell = (columnDef, rowValue) => {
6
+ const {
7
+ type, field, onCellChange, cellRenderer, cellParams
8
+ } = columnDef;
9
+ switch (type) {
10
+ case 'text':
11
+ return (
12
+ <FormControl type="text" value={rowValue[field] || ''} onChange={e => onCellChange({ e, columnDef, rowValue })} />
13
+ );
14
+ case 'system-defined':
15
+ return (
16
+ <InputGroup>
17
+ <FormControl type="number" value={rowValue[field].value || ''} onChange={e => onCellChange({ e, columnDef, rowValue })} />
18
+ <InputGroup.Button>
19
+ {cellRenderer({ ...cellParams, node: { data: rowValue } })}
20
+ </InputGroup.Button>
21
+ </InputGroup>
22
+ );
23
+ case 'select':
24
+ case 'drag_molecule':
25
+ case 'drag_sample':
26
+ case 'dnd':
27
+ return (cellRenderer({ ...cellParams, node: { data: rowValue } }));
28
+ default:
29
+ return <span />;
30
+ }
31
+ };
32
+
33
+ const ColumnHeader = (columnDefs) => {
34
+ const ch = [];
35
+ const h = (col, idx) => {
36
+ const {
37
+ width, headerName, headerComponent, headerParams
38
+ } = col;
39
+ const colCss = {};
40
+ if (width) { Object.assign(colCss, { width, minWidth: width }); }
41
+ return (
42
+ <div key={`column_header_${col.colId || col.field}_${idx}`} className="generic_grid_header" style={colCss}>
43
+ {headerComponent ? headerComponent(headerParams) : null}
44
+ <div style={colCss}>{headerName}</div>
45
+ </div>
46
+ );
47
+ };
48
+ columnDefs.forEach((col, idx) => ch.push(h(col, idx)));
49
+ return (<div className="generic_grid" style={{ borderBottom: '1px solid #ccc' }}><div>{ch}</div></div>);
50
+ };
51
+
52
+ const ColumnRow = (columnDefs, rowValue) => {
53
+ const ch = [];
54
+ const h = (col, val, idx) => {
55
+ const {
56
+ field, width, cellParams, cellRenderer
57
+ } = col;
58
+ const colCss = {};
59
+ if (width) { Object.assign(colCss, { width, minWidth: width }); }
60
+ return (
61
+ <div key={`column_row_${val.id}_${col.colId || col.field}_${idx}`} className="generic_grid_row" style={colCss}>
62
+ {field ? (setCell(col, val) || '') : (cellRenderer({ ...cellParams, node: { data: val } }) || '')}
63
+ </div>
64
+ );
65
+ };
66
+ columnDefs.forEach((col, idx) => ch.push(h(col, rowValue, idx)));
67
+ return (<div key={`column_row_${rowValue.id}`} className="generic_grid"><div>{ch}</div></div>);
68
+ };
69
+
70
+ const NoRow = (values) => {
71
+ if (values && values.length > 0) return null;
72
+ return (<div className="generic_grid"><div><div className="generic_grid_row" style={{ width: '100%' }}>(No data)</div></div></div>);
73
+ };
74
+
75
+ export { ColumnHeader, ColumnRow, NoRow };
@@ -0,0 +1,53 @@
1
+ /* eslint-disable react/forbid-prop-types */
2
+ import React from 'react';
3
+ import PropTypes from 'prop-types';
4
+ import { v4 as uuid } from 'uuid';
5
+ import { OverlayTrigger, InputGroup, Tooltip } from 'react-bootstrap';
6
+
7
+ const SamOption = (props) => {
8
+ const { sField, node, onChange } = props;
9
+ const { data } = node;
10
+ const fValue = (data[sField.id] && data[sField.id].value) || {};
11
+ if (!fValue.is_new) return <div />;
12
+ const rUUID = uuid();
13
+ return (
14
+ <div className="generic_sam_options">
15
+ <OverlayTrigger delayShow={1000} placement="right" overlay={<Tooltip id={uuid()}>associate with this sample</Tooltip>}>
16
+ <InputGroup.Radio
17
+ name={`dropS_${rUUID}`}
18
+ disabled={fValue.isAssoc}
19
+ checked={fValue.cr_opt === 0}
20
+ onChange={() => onChange({ node, subField: sField, crOpt: 0 })}
21
+ >
22
+ Current
23
+ </InputGroup.Radio>
24
+ </OverlayTrigger>
25
+ <OverlayTrigger delayShow={1000} placement="right" overlay={<Tooltip id={uuid()}>split from the sample first and then associate with it</Tooltip>}>
26
+ <InputGroup.Radio
27
+ name={`dropS_${rUUID}`}
28
+ checked={fValue.cr_opt === 1}
29
+ onChange={() => onChange({ node, subField: sField, crOpt: 1 })}
30
+ >
31
+ Split
32
+ </InputGroup.Radio>
33
+ </OverlayTrigger>
34
+ <OverlayTrigger delayShow={1000} placement="right" overlay={<Tooltip id={uuid()}>duplicate the sample first and then associate with it</Tooltip>}>
35
+ <InputGroup.Radio
36
+ name={`dropS_${rUUID}`}
37
+ checked={fValue.cr_opt === 2}
38
+ onChange={() => onChange({ node, subField: sField, crOpt: 2 })}
39
+ >
40
+ Copy
41
+ </InputGroup.Radio>
42
+ </OverlayTrigger>
43
+ </div>
44
+ );
45
+ };
46
+
47
+ SamOption.propTypes = {
48
+ sField: PropTypes.object.isRequired,
49
+ node: PropTypes.object.isRequired,
50
+ onChange: PropTypes.func.isRequired
51
+ };
52
+
53
+ export default SamOption;
@@ -0,0 +1,34 @@
1
+ /* eslint-disable react/forbid-prop-types */
2
+ import React from 'react';
3
+ import PropTypes from 'prop-types';
4
+ import Select from 'react-select';
5
+
6
+ const SelectRenderer = (props) => {
7
+ const {
8
+ sField, onChange, sOptions, node
9
+ } = props;
10
+ if (sField.type !== 'select' || sOptions.length < 1) return null;
11
+ const { data } = node;
12
+ const val = sOptions.find(o => o.value === data[sField.id].value) || null;
13
+ return (
14
+ <Select
15
+ isClearable
16
+ menuContainerStyle={{ position: 'absolute' }}
17
+ multi={false}
18
+ options={sOptions}
19
+ value={val}
20
+ onChange={e => onChange(e, sField, node)}
21
+ className="status-select"
22
+ style={{ textAlign: 'left' }}
23
+ />
24
+ );
25
+ };
26
+
27
+ SelectRenderer.propTypes = {
28
+ sField: PropTypes.object.isRequired,
29
+ onChange: PropTypes.func.isRequired,
30
+ node: PropTypes.object.isRequired,
31
+ sOptions: PropTypes.arrayOf(PropTypes.object).isRequired
32
+ };
33
+
34
+ export default SelectRenderer;
@@ -0,0 +1,254 @@
1
+ /* eslint-disable no-restricted-globals */
2
+ /* eslint-disable no-empty */
3
+ /* eslint-disable react/forbid-prop-types */
4
+ import PropTypes from 'prop-types';
5
+ import React from 'react';
6
+ import Numeral from 'numeral';
7
+ import GenericSubField from '../models/GenericSubField';
8
+ import { AddRowBtn, DelRowBtn, DnDRowBtn, NullRowBtn } from './GridBtn';
9
+ import { ColumnHeader, ColumnRow, NoRow } from './GridEntry';
10
+ import UConverterRenderer from './UConverterRenderer';
11
+ import { genUnits, unitConversion, molOptions, samOptions } from '../tools/utils';
12
+ import DropRenderer from './DropRenderer';
13
+ import DropTextRenderer from './DropTextRenderer';
14
+ import DropLinkRenderer from './DropLinkRenderer';
15
+ import SampOption from './SamOption';
16
+ import DragDropItemTypes from '../dnd/DragDropItemTypes';
17
+ import SelectRenderer from './SelectRenderer';
18
+
19
+ export default class TableRecord extends React.Component {
20
+ constructor(props) {
21
+ super(props);
22
+ this.delRow = this.delRow.bind(this);
23
+ this.addRow = this.addRow.bind(this);
24
+ this.moveRow = this.moveRow.bind(this);
25
+ this.onCellChange = this.onCellChange.bind(this);
26
+ this.onSelectClick = this.onSelectClick.bind(this);
27
+ this.onUnitClick = this.onUnitClick.bind(this);
28
+ this.onDrop = this.onDrop.bind(this);
29
+ this.onChk = this.onChk.bind(this);
30
+ this.getColumns = this.getColumns.bind(this);
31
+ }
32
+
33
+ onCellChange(params) {
34
+ const { e, columnDef, rowValue } = params;
35
+ const newValue = e.target.value;
36
+ const oldValue = rowValue[columnDef.field].value;
37
+ if (oldValue === newValue) return;
38
+ if (columnDef.type === 'text') {
39
+ rowValue[columnDef.field] = newValue;
40
+ }
41
+ if (columnDef.type === 'system-defined') {
42
+ if (isNaN(newValue)) return;
43
+ rowValue[columnDef.field].value = Numeral(newValue).value();
44
+ }
45
+ const { opt } = this.props;
46
+ const subVals = opt.f_obj.sub_values || [];
47
+ const idx = subVals.findIndex(s => s.id === rowValue.id);
48
+ subVals.splice(idx, 1, rowValue);
49
+ opt.f_obj.sub_values = subVals;
50
+ opt.onSubChange(0, 0, opt.f_obj, true);
51
+ }
52
+
53
+ onSelectClick(e, subField, node) {
54
+ const { data } = node;
55
+ const { opt } = this.props;
56
+ const subVals = opt.f_obj.sub_values || [];
57
+ const subVal = subVals.find(s => s.id === data.id);
58
+ subVal[subField.id] = { value: e ? e.value : '' };
59
+ const idx = subVals.findIndex(s => s.id === data.id);
60
+ subVals.splice(idx, 1, subVal);
61
+ opt.f_obj.sub_values = subVals;
62
+ opt.onSubChange(subField, subField.id, opt.f_obj, true);
63
+ }
64
+
65
+ onUnitClick(subField, node) {
66
+ const { data } = node;
67
+ const { opt } = this.props;
68
+ const subVals = opt.f_obj.sub_values || [];
69
+ const subVal = subVals.find(s => s.id === data.id);
70
+ const units = genUnits(subField.option_layers);
71
+ let uIdx = units.findIndex(u => u.key === subVal[subField.id].value_system);
72
+ if (uIdx < units.length - 1) uIdx += 1; else uIdx = 0;
73
+ const vs = units.length > 0 ? units[uIdx].key : '';
74
+ const v = unitConversion(subField.option_layers, vs, subVal[subField.id].value);
75
+ subVal[subField.id] = { value: v, value_system: vs };
76
+ const idx = subVals.findIndex(s => s.id === data.id);
77
+ subVals.splice(idx, 1, subVal);
78
+ opt.f_obj.sub_values = subVals;
79
+ opt.onSubChange(subField, subField.id, opt.f_obj, true);
80
+ }
81
+
82
+ onDrop(targetProps, targetOpt) {
83
+ const { opt } = this.props;
84
+ const subField = targetOpt.sField;
85
+ const subVals = opt.f_obj.sub_values || [];
86
+ const subVal = subVals.find(s => s.id === targetOpt.data.id);
87
+ subVal[subField.id] = { value: targetProps };
88
+ const idx = subVals.findIndex(s => s.id === targetOpt.data.id);
89
+ subVals.splice(idx, 1, subVal);
90
+ opt.f_obj.sub_values = subVals;
91
+ opt.onSubChange(subField, subField.id, opt.f_obj, true);
92
+ }
93
+
94
+ onChk(params) {
95
+ const { node, subField, crOpt } = params;
96
+ const { opt } = this.props;
97
+ const subVals = opt.f_obj.sub_values || [];
98
+ const subVal = subVals.find(s => s.id === node.data.id);
99
+ node.data[subField.id].value.cr_opt = crOpt;
100
+ subVal[subField.id] = { value: node.data[subField.id].value };
101
+ const idx = subVals.findIndex(s => s.id === node.data.id);
102
+ subVals.splice(idx, 1, subVal);
103
+ opt.f_obj.sub_values = subVals;
104
+ opt.onSubChange(subField, subField.id, opt.f_obj, true);
105
+ }
106
+
107
+ getColumns() {
108
+ const { opt } = this.props;
109
+ const { selectOptions } = opt;
110
+ const sValues = (opt.f_obj.sub_values || []);
111
+ let columnDefs = [];
112
+ (opt.f_obj.sub_fields || []).forEach((sF) => {
113
+ let colDef = {
114
+ type: sF.type, headerName: sF.col_name, field: sF.id
115
+ };
116
+ const colDefExt = [];
117
+ if (sF.type === 'text') {
118
+ colDef = Object.assign({}, colDef, {
119
+ editable: true, onCellChange: this.onCellChange
120
+ });
121
+ }
122
+ if (sF.type === 'select') {
123
+ let sOptions =
124
+ (selectOptions[sF.option_layers] && selectOptions[sF.option_layers].options) || [];
125
+ sOptions = sOptions.map(op => ({ value: op.key, name: op.key, label: op.label }));
126
+ const cellParams = { sField: sF, onChange: this.onSelectClick, sOptions };
127
+ colDef = Object.assign({}, colDef, {
128
+ cellRenderer: SelectRenderer, cellParams, onCellChange: this.onCellChange
129
+ });
130
+ }
131
+ if (sF.type === 'system-defined') {
132
+ const cellParams = { sField: sF, onChange: this.onUnitClick };
133
+ colDef = Object.assign({}, colDef, {
134
+ cellRenderer: UConverterRenderer, cellParams, onCellChange: this.onCellChange
135
+ });
136
+ }
137
+ if (sF.type === 'drag_molecule') {
138
+ const cellParams = { sField: sF, opt, onChange: this.onDrop };
139
+ colDef = Object.assign({}, colDef, {
140
+ cellRenderer: DropRenderer, cellParams, onCellChange: this.onCellChange, width: '5vw'
141
+ });
142
+ const conf = ((sF.value || '').split(';') || []);
143
+ conf.forEach((c) => {
144
+ const attr = molOptions.find(m => m.value === c);
145
+ if (attr) {
146
+ const ext = {
147
+ colId: c, editable: false, type: 'text', headerName: attr.label, cellRenderer: DropTextRenderer, cellParams: { attr, sField: sF }
148
+ };
149
+ colDefExt.push(ext);
150
+ }
151
+ });
152
+ }
153
+ if (sF.type === 'drag_sample') {
154
+ const sOpt = sValues.filter(o => o[sF.id] && o[sF.id].value && o[sF.id].value.is_new);
155
+ const cellParams = { sField: sF, opt, onChange: this.onDrop };
156
+ colDef = Object.assign({}, colDef, {
157
+ cellRenderer: DropRenderer, cellParams, onCellChange: this.onCellChange, width: '5vw'
158
+ });
159
+ const addOption = {
160
+ colId: 'sam_option', editable: false, type: 'text', headerName: '', cellRenderer: SampOption, cellParams: { sField: sF, onChange: this.onChk }, width: '3vw'
161
+ };
162
+ if (sOpt.length > 0) colDefExt.push(addOption);
163
+ const addLink = {
164
+ colId: 'sam_link', editable: false, type: 'text', headerName: 'Short label', cellRenderer: DropLinkRenderer, cellParams: { sField: sF }, width: '5vw'
165
+ };
166
+ colDefExt.push(addLink);
167
+ const conf = ((sF.value || '').split(';') || []);
168
+ conf.forEach((c) => {
169
+ const attr = samOptions.find(m => m.value === c);
170
+ if (attr) {
171
+ const ext = {
172
+ colId: c, editable: false, type: 'text', headerName: attr.label, cellRenderer: DropTextRenderer, cellParams: { attr, sField: sF }
173
+ };
174
+ colDefExt.push(ext);
175
+ }
176
+ });
177
+ }
178
+ columnDefs.push(colDef);
179
+ if (colDefExt.length > 0) columnDefs = columnDefs.concat(colDefExt);
180
+ });
181
+ const act = {
182
+ type: 'button',
183
+ headerName: '',
184
+ colId: opt.f_obj.field,
185
+ headerComponent: AddRowBtn,
186
+ headerParams: { addRow: this.addRow },
187
+ cellRenderer: DelRowBtn,
188
+ cellParams: { delRow: this.delRow },
189
+ width: 'unset',
190
+ };
191
+ columnDefs.splice(0, 0, act);
192
+ const dtype = `${DragDropItemTypes.GENERIC_GRID}_${opt.layer.key}_${opt.f_obj.field}`;
193
+ const move = {
194
+ type: 'dnd',
195
+ field: opt.f_obj.field,
196
+ headerName: '',
197
+ colId: `${opt.f_obj.field}_dnd`,
198
+ headerComponent: NullRowBtn,
199
+ cellRenderer: DnDRowBtn,
200
+ cellParams: { moveRow: this.moveRow, field: opt.f_obj.field, type: dtype },
201
+ width: 'unset',
202
+ };
203
+ columnDefs.splice(0, 0, move);
204
+ return columnDefs;
205
+ }
206
+
207
+ moveRow(source, target) {
208
+ const { opt } = this.props;
209
+ const alles = opt.f_obj.sub_values;
210
+ const sid = alles.findIndex(e => e.id === source);
211
+ const tid = alles.findIndex(e => e.id === target);
212
+ const temp = alles[sid];
213
+ alles[sid] = alles[tid];
214
+ alles[tid] = temp;
215
+ opt.onSubChange(0, 0, opt.f_obj, true);
216
+ }
217
+
218
+ delRow(rowData) {
219
+ const { opt } = this.props;
220
+ opt.f_obj.sub_values = opt.f_obj.sub_values.filter(s => s.id !== rowData.id);
221
+ opt.onSubChange(0, 0, opt.f_obj, true);
222
+ }
223
+
224
+ addRow() {
225
+ const { opt } = this.props;
226
+ const subFields = opt.f_obj.sub_fields || [];
227
+ const newSub = new GenericSubField();
228
+ subFields.map((e) => {
229
+ if (e.type === 'text') return Object.assign(newSub, { [e.id]: '' });
230
+ return Object.assign(newSub, { [e.id]: { value: '', value_system: e.value_system } });
231
+ });
232
+ opt.f_obj.sub_values = opt.f_obj.sub_values || [];
233
+ opt.f_obj.sub_values.push(newSub);
234
+ opt.onSubChange(0, 0, opt.f_obj, true);
235
+ }
236
+
237
+ render() {
238
+ const { opt } = this.props;
239
+ if (opt.isSearchCriteria) return (<div>(This is a table)</div>);
240
+ if ((opt.f_obj.sub_fields || []).length < 1) return null;
241
+ const columnDefs = this.getColumns();
242
+ return (
243
+ <div>
244
+ {ColumnHeader(columnDefs)}
245
+ <div>{NoRow(opt.f_obj.sub_values)}</div>
246
+ <div>{(opt.f_obj.sub_values || []).map(s => ColumnRow(columnDefs, s))}</div>
247
+ </div>
248
+ );
249
+ }
250
+ }
251
+
252
+ TableRecord.propTypes = {
253
+ opt: PropTypes.object.isRequired,
254
+ };
@@ -0,0 +1,24 @@
1
+ /* eslint-disable react/forbid-prop-types */
2
+ import React from 'react';
3
+ import PropTypes from 'prop-types';
4
+ import { Button } from 'react-bootstrap';
5
+ import { genUnit, genUnitSup } from '../tools/utils';
6
+
7
+ const UConverterRenderer = (props) => {
8
+ const { sField, onChange, node } = props;
9
+ if (sField.type !== 'system-defined') return null;
10
+ const { data } = node;
11
+ return (
12
+ <Button key={`ucr_${data.id}`} active onClick={() => onChange(sField, node)} bsStyle="success">
13
+ {genUnitSup(genUnit(sField.option_layers, data[sField.id].value_system).label) || ''}
14
+ </Button>
15
+ );
16
+ };
17
+
18
+ UConverterRenderer.propTypes = {
19
+ sField: PropTypes.object.isRequired,
20
+ onChange: PropTypes.func.isRequired,
21
+ node: PropTypes.object.isRequired
22
+ };
23
+
24
+ export default UConverterRenderer;
@@ -0,0 +1,65 @@
1
+ import { cloneDeep } from 'lodash';
2
+ import { unitConversion } from './utils';
3
+ import GenericSubField from '../models/GenericSubField';
4
+
5
+ const collateValues = (currentFields, previousFields, previousValues) => {
6
+ const result = [];
7
+ let newSub = new GenericSubField();
8
+ currentFields.map(e => Object.assign(newSub, { [e.id]: '' }));
9
+ const currentValuKeys = Object.keys(newSub);
10
+ const previousValueKeys = Object.keys(previousValues[0]);
11
+ const notInCurrent = previousValueKeys.filter(e => !currentValuKeys.includes(e));
12
+ const currObj = {};
13
+ currentFields.map((c) => {
14
+ if (c.type === 'text') return Object.assign(currObj, { [c.id]: '' });
15
+ return Object.assign(currObj, { [c.id]: { value: '', value_system: c.value_system } });
16
+ });
17
+ previousValues.forEach((e) => {
18
+ newSub = new GenericSubField();
19
+ Object.assign(newSub, currObj, e);
20
+ notInCurrent.forEach(c => delete newSub[c]);
21
+ previousValueKeys.forEach((preKey) => {
22
+ if (newSub[preKey] === undefined || preKey === 'id') return;
23
+ const curr = currentFields.find(f => f.id === preKey);
24
+ const prev = previousFields.find(f => f.id === preKey);
25
+ if (curr.type === 'drag_molecule') {
26
+ if (['text', 'system-defined', 'drag_sample'].includes(prev.type)) {
27
+ newSub[preKey] = { value: undefined };
28
+ }
29
+ }
30
+ if (curr.type === 'text') {
31
+ if (prev.type === 'system-defined') {
32
+ newSub[preKey] = newSub[preKey].value;
33
+ }
34
+ if (['drag_molecule', 'drag_sample'].includes(prev.type)) {
35
+ newSub[preKey] = '';
36
+ }
37
+ }
38
+ if (curr.type === 'system-defined') {
39
+ if (prev.type === 'system-defined' && (curr.option_layers !== prev.option_layers)) {
40
+ newSub[preKey].value_system = curr.value_system;
41
+ }
42
+ if (['text', 'drag_molecule', 'drag_sample'].includes(prev.type)) {
43
+ newSub[preKey] = { value: '', value_system: curr.value_system };
44
+ }
45
+ newSub[preKey].value =
46
+ unitConversion(curr.option_layer, newSub[preKey].value_system, newSub[preKey].value);
47
+ }
48
+ });
49
+ result.push(newSub);
50
+ });
51
+ return result;
52
+ };
53
+
54
+ const organizeSubValues = (cur, pre) => {
55
+ const currentFields = cloneDeep(cur.sub_fields || []);
56
+ const previousFields = cloneDeep(pre.sub_fields || []);
57
+ const previousValues = cloneDeep(pre.sub_values || []);
58
+ if (currentFields.length < 1 ||
59
+ previousFields.length < 1 || previousValues.length < 1) {
60
+ return [];
61
+ }
62
+ return collateValues(currentFields, previousFields, previousValues);
63
+ };
64
+
65
+ export default organizeSubValues;
@@ -0,0 +1,171 @@
1
+ /* eslint-disable no-param-reassign */
2
+ /* eslint-disable import/prefer-default-export */
3
+ import { cloneDeep, sortBy } from 'lodash';
4
+ import { v4 as uuid } from 'uuid';
5
+
6
+ const getWFNode = (_flow, nodeId) => _flow.elements.filter(e => e.id === nodeId)[0];
7
+
8
+ // full-flow, node id
9
+ const getFlowLayer = (templateFlow, nodeId, sourceLayer, sIdx) => {
10
+ const flow = cloneDeep(templateFlow);
11
+ const nd = flow.elements.filter(e => e.id === nodeId); // fetch node
12
+ if (nd.length < 1) return null;
13
+ const { layer } = nd[0].data;
14
+ const ls = flow.elements.filter(e => e.animated); // lines
15
+ const ns = flow.elements.filter(e => e.type === 'default' && e.data); // nodes - Start - End
16
+ const ndNs = ls.filter(e => e.source === nodeId).map(e => e.target); // next nodes' id
17
+ const wfOpts = ns.filter(n => ndNs.includes(n.id)).map(e => ({ key: e.id, label: `${e.data.layer.label}(${e.data.layer.key})` })); // next nodes
18
+ if (wfOpts.length > 0) {
19
+ const position = (layer.fields || []).length + 1;
20
+ layer.fields.push({
21
+ type: 'wf-next', default: '', field: '_wf_next', label: 'Next', required: false, sub_fields: [], text_sub_fields: [], position, wf_options: wfOpts
22
+ });
23
+ }
24
+ layer.wf_info = { node_id: nodeId, source_layer: sourceLayer };
25
+ layer.wf_position = sIdx + 1;
26
+ return layer;
27
+ };
28
+
29
+ const orgLayerObject = (_layers = []) => {
30
+ const layers = _layers;
31
+ return layers.reduce((alles, name) => {
32
+ const all = alles;
33
+ const ok = Object.keys(all);
34
+ if (ok.includes(name.key)) {
35
+ const cnt = ok.filter(e => e === name.key || e.startsWith(`${name.key}.`)).length;
36
+ const nName = `${name.key}.${cnt}`;
37
+ name.key = nName;
38
+ all[nName] = name;
39
+ } else {
40
+ all[name.key] = name;
41
+ }
42
+ return all;
43
+ }, {});
44
+ };
45
+
46
+ const reformCondFields = (_layer, _oKey) => {
47
+ const layer = _layer;
48
+ layer.fields.map((_f) => {
49
+ const f = _f;
50
+ let conds = f.cond_fields;
51
+ // no cond_fields
52
+ if (!conds || conds.length < 1 || conds.filter(o => !o.field || o.field === '').length === conds.length) return f;
53
+ conds = conds.filter(o => o.layer === _oKey);
54
+ // no same layer, remove cond_fields
55
+ if (conds.length < 1) {
56
+ delete f.cond_fields;
57
+ return f;
58
+ }
59
+ // rename layer
60
+ conds = conds.map((o) => {
61
+ const n = o;
62
+ n.layer = layer.key;
63
+ return n;
64
+ });
65
+ f.cond_fields = conds;
66
+ return f;
67
+ });
68
+ return layer.fields;
69
+ };
70
+
71
+ const addToObject = (obj, key, addAfter) => {
72
+ const temp = {};
73
+ const ok = Object.keys(obj);
74
+ Object.keys(obj).forEach((e) => {
75
+ if (Object.prototype.hasOwnProperty.call(obj, e)) {
76
+ temp[e] = obj[e];
77
+ if (e === key) {
78
+ const srcPosition = temp[e].position;
79
+ const cnt = ok.filter(o => o === addAfter.key || o.startsWith(`${addAfter.key}.`)).length;
80
+ if (cnt === 0) {
81
+ temp[addAfter.key] = addAfter;
82
+ temp[addAfter.key].position = srcPosition;
83
+ } else {
84
+ const oKey = addAfter.key;
85
+ temp[`${addAfter.key}.${cnt}`] = addAfter;
86
+ temp[`${addAfter.key}.${cnt}`].position = srcPosition;
87
+ temp[`${addAfter.key}.${cnt}`].key = `${addAfter.key}.${cnt}`;
88
+ temp[addAfter.key].fields = reformCondFields(addAfter, oKey);
89
+ }
90
+ }
91
+ }
92
+ });
93
+ if (Object.keys(obj).length === 0) temp[addAfter.key] = addAfter;
94
+ return temp;
95
+ };
96
+
97
+ const traverseToRemove = (layers, rmKey) => {
98
+ let rms = [];
99
+ Object.keys(layers).forEach((e) => {
100
+ if (Object.prototype.hasOwnProperty.call(layers, e)) {
101
+ if (layers[e].key === rmKey) rms = rms.concat(rmKey);
102
+ else if (layers[e].wf_info && (layers[e].wf_info.source_layer === rmKey)) {
103
+ rms = rms.concat(traverseToRemove(layers, layers[e].key));
104
+ }
105
+ }
106
+ });
107
+ return rms;
108
+ };
109
+
110
+ const removeFromObject = (_propertiesLayers = {}, srcLayer = '', rmNode = {}) => {
111
+ const layers = _propertiesLayers;
112
+ const rmLayer = rmNode.data && rmNode.data.layer ? rmNode.data.layer.key : null;
113
+ if (!rmLayer) return [];
114
+ let rms = [];
115
+ Object.keys(layers).forEach((e) => {
116
+ if (Object.prototype.hasOwnProperty.call(layers, e)) {
117
+ const wf = layers[e].wf_info;
118
+ if (wf && (wf.source_layer === srcLayer) && (wf.node_id === rmNode.id)) {
119
+ rms = rms.concat(traverseToRemove(layers, layers[e].key));
120
+ }
121
+ }
122
+ });
123
+ rms.forEach(e => delete layers[e]);
124
+ return layers;
125
+ };
126
+
127
+ const buildInitWF = (template) => {
128
+ const orig = cloneDeep(template);
129
+ const { layers, flow } = orig;
130
+ const sortedLayers = sortBy(layers, l => l.position);
131
+ if (flow && flow.elements.filter(e => !['input', 'output'].includes(e.type).length > 0)) {
132
+ // id = 1 Start, id = 2 End
133
+ const nls = flow.elements; // nodes + lines
134
+ const ls = nls.filter(e => e.animated); // lines
135
+ const ns = nls.filter(e => e.type === 'default' && e.data); // nodes - Start - End
136
+ const nNs = ls.filter(e => e.source === '1').map(e => e.target); // get target ids from Start
137
+ const nextNodes = ns.filter(n => nNs.includes(n.id)); // target nodes
138
+ const result = [];
139
+ sortedLayers.forEach((sortedLayer) => {
140
+ const fLayer = sortedLayer;
141
+ if (fLayer.wf) {
142
+ const position = (fLayer.fields || []).length + 1;
143
+ const passen = nextNodes.filter(n => n.data.layer.key === fLayer.key);
144
+ passen.forEach((pas) => {
145
+ const nextOptions =
146
+ ls.filter(e => e.source === pas.id && e.source !== e.target).map(e => e.target);
147
+ const wfOpts = ns.filter(n => nextOptions.includes(n.id)).map(e => ({ key: e.id, label: `${e.data.layer.label}(${e.data.layer.key})` })); // next nodes
148
+ fLayer.fields.push({
149
+ type: 'wf-next', default: '', field: '_wf_next', label: 'Next', required: false, sub_fields: [], text_sub_fields: [], position, wf_options: wfOpts
150
+ });
151
+ fLayer.wf_info = { node_id: pas.id };
152
+ fLayer.wf_position = 1;
153
+ fLayer.wf_uuid = uuid();
154
+ result.push(fLayer);
155
+ });
156
+ } else {
157
+ result.push(fLayer);
158
+ }
159
+ });
160
+ const ll = orgLayerObject(result);
161
+ orig.layers = ll;
162
+ } else {
163
+ orig.layers = layers;
164
+ }
165
+ return orig;
166
+ };
167
+
168
+ export {
169
+ getWFNode, getFlowLayer, orgLayerObject,
170
+ addToObject, removeFromObject, reformCondFields, buildInitWF
171
+ };