chem-generic-ui 0.1.45 → 0.1.46
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 -6
- 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/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,440 @@
|
|
|
1
|
+
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
|
2
|
+
/* eslint-disable jsx-a11y/anchor-is-valid */
|
|
3
|
+
/* eslint-disable jsx-a11y/click-events-have-key-events */
|
|
4
|
+
/* eslint-disable no-eval */
|
|
5
|
+
/* eslint-disable no-restricted-globals */
|
|
6
|
+
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import { Button, Checkbox, FormGroup, FormControl,
|
|
9
|
+
InputGroup, ListGroup, ListGroupItem, OverlayTrigger, Radio, Tooltip } from 'react-bootstrap';
|
|
10
|
+
import Select from 'react-select';
|
|
11
|
+
import Dropzone from 'react-dropzone';
|
|
12
|
+
import { v4 as uuid } from 'uuid';
|
|
13
|
+
import { filter } from 'lodash';
|
|
14
|
+
import FieldLabel from './FieldLabel';
|
|
15
|
+
import { downloadFile, genUnit, genUnitSup, unitConvToBase } from '../tools/utils';
|
|
16
|
+
import GenericElDropTarget from '../dnd/GenericElDropTarget';
|
|
17
|
+
import TableRecord from '../table/TableRecord';
|
|
18
|
+
|
|
19
|
+
const GenPropertiesCalculate = (opt) => {
|
|
20
|
+
const fields = (opt.layer && opt.layer.fields) || [];
|
|
21
|
+
let showVal = 0;
|
|
22
|
+
let showTxt = null;
|
|
23
|
+
let newFormula = opt.formula;
|
|
24
|
+
|
|
25
|
+
const calFields = filter(fields, o => (o.type === 'integer' || o.type === 'system-defined'));
|
|
26
|
+
const regF = /[a-zA-Z0-9]+/gm;
|
|
27
|
+
// eslint-disable-next-line max-len
|
|
28
|
+
const varFields = (opt.formula && opt.formula.match(regF)) ? opt.formula.match(regF).sort((a, b) => b.length - a.length) : [];
|
|
29
|
+
|
|
30
|
+
varFields.forEach((fi) => {
|
|
31
|
+
if (!isNaN(fi)) return;
|
|
32
|
+
|
|
33
|
+
const tmpField = calFields.find(e => e.field === fi);
|
|
34
|
+
if (typeof tmpField === 'undefined' || tmpField == null) {
|
|
35
|
+
newFormula = newFormula.replace(fi, 0);
|
|
36
|
+
} else {
|
|
37
|
+
newFormula = (tmpField.type === 'system-defined') ? newFormula.replace(fi, parseFloat(unitConvToBase(tmpField) || 0)) : newFormula.replace(fi, parseFloat(tmpField.value || 0));
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
if (opt.type === 'formula-field') {
|
|
42
|
+
try {
|
|
43
|
+
showVal = eval(newFormula);
|
|
44
|
+
showTxt = !isNaN(showVal) ? parseFloat(showVal.toFixed(5)) : 0;
|
|
45
|
+
} catch (e) {
|
|
46
|
+
if (e instanceof SyntaxError) {
|
|
47
|
+
showTxt = e.message;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const fieldHeader = opt.label === '' ? null : (<FieldLabel label={opt.label} desc={opt.description} />);
|
|
53
|
+
return (
|
|
54
|
+
<FormGroup>
|
|
55
|
+
{fieldHeader}
|
|
56
|
+
<InputGroup>
|
|
57
|
+
<FormControl
|
|
58
|
+
type="text"
|
|
59
|
+
value={showTxt}
|
|
60
|
+
onChange={opt.onChange}
|
|
61
|
+
className="readonly"
|
|
62
|
+
readOnly="readonly"
|
|
63
|
+
required={false}
|
|
64
|
+
placeholder={opt.placeholder}
|
|
65
|
+
min={0}
|
|
66
|
+
/>
|
|
67
|
+
<InputGroup.Button>
|
|
68
|
+
<OverlayTrigger
|
|
69
|
+
placement="bottom"
|
|
70
|
+
overlay={<Tooltip id="update_calculation_field">adjust</Tooltip>}
|
|
71
|
+
>
|
|
72
|
+
<Button active className="clipboardBtn" onClick={() => opt.onChange(showTxt)}>
|
|
73
|
+
<i className="fa fa-arrow-right" aria-hidden="true" />
|
|
74
|
+
</Button>
|
|
75
|
+
</OverlayTrigger>
|
|
76
|
+
</InputGroup.Button>
|
|
77
|
+
<FormControl
|
|
78
|
+
type="text"
|
|
79
|
+
value={opt.value}
|
|
80
|
+
onChange={opt.onChange}
|
|
81
|
+
required={false}
|
|
82
|
+
placeholder={opt.placeholder}
|
|
83
|
+
min={0}
|
|
84
|
+
/>
|
|
85
|
+
</InputGroup>
|
|
86
|
+
</FormGroup>
|
|
87
|
+
);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const GenPropertiesCheckbox = opt => (
|
|
91
|
+
<FormGroup>
|
|
92
|
+
<Checkbox
|
|
93
|
+
name={opt.field}
|
|
94
|
+
checked={opt.value}
|
|
95
|
+
onChange={opt.onChange}
|
|
96
|
+
disabled={opt.readOnly}
|
|
97
|
+
>
|
|
98
|
+
<FormControl.Static>{opt.label}</FormControl.Static>
|
|
99
|
+
</Checkbox>
|
|
100
|
+
</FormGroup>
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
const GenPropertiesDrop = (opt) => {
|
|
104
|
+
const className = opt.isRequired ? 'drop_generic_properties field_required' : 'drop_generic_properties';
|
|
105
|
+
|
|
106
|
+
let createOpt = null;
|
|
107
|
+
if (opt.value.is_new === true) {
|
|
108
|
+
createOpt = (
|
|
109
|
+
<div className="sample_radios">
|
|
110
|
+
<OverlayTrigger placement="top" overlay={<Tooltip id={uuid()}>associate with this sample</Tooltip>}>
|
|
111
|
+
<Radio name={`dropS_${opt.value.el_id}`} disabled={opt.value.isAssoc === true} checked={opt.value.cr_opt === 0} onChange={() => opt.onChange({ ...opt.value, cr_opt: 0 })} inline>Current</Radio>
|
|
112
|
+
</OverlayTrigger>
|
|
113
|
+
<OverlayTrigger placement="top" overlay={<Tooltip id={uuid()}>split from the sample first and then associate with it</Tooltip>}>
|
|
114
|
+
<Radio name={`dropS_${opt.value.el_id}`} checked={opt.value.cr_opt === 1} onChange={() => opt.onChange({ ...opt.value, cr_opt: 1 })} inline>Split</Radio>
|
|
115
|
+
</OverlayTrigger>
|
|
116
|
+
<OverlayTrigger placement="top" overlay={<Tooltip id={uuid()}>duplicate the sample first and then associate with it</Tooltip>}>
|
|
117
|
+
<Radio name={`dropS_${opt.value.el_id}`} checked={opt.value.cr_opt === 2} onChange={() => opt.onChange({ ...opt.value, cr_opt: 2 })} inline>Copy</Radio>
|
|
118
|
+
</OverlayTrigger>
|
|
119
|
+
</div>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
const fieldHeader = opt.label === '' ? null : <FieldLabel label={opt.label} desc={opt.description} />;
|
|
123
|
+
const defaultIcon = opt.type === 'drag_element' ? <span className="fa fa-link icon_generic_nav indicator" /> : <span className="icon-sample indicator" />;
|
|
124
|
+
const dragTarget = opt.isPreview === true ? <div className="target">{defaultIcon}</div> : <GenericElDropTarget opt={opt} onDrop={opt.onChange} />;
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<FormGroup>
|
|
128
|
+
{fieldHeader}
|
|
129
|
+
<FormControl.Static style={{ paddingBottom: '0px' }}>
|
|
130
|
+
<div className={className}>
|
|
131
|
+
{dragTarget}
|
|
132
|
+
{createOpt}
|
|
133
|
+
<div>
|
|
134
|
+
<OverlayTrigger placement="top" overlay={<Tooltip id={uuid()}>remove</Tooltip>}>
|
|
135
|
+
<Button className="btn_del" bsStyle="danger" bsSize="xsmall" onClick={() => opt.onChange({})} ><i className="fa fa-trash-o" aria-hidden="true" /></Button>
|
|
136
|
+
</OverlayTrigger>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
</FormControl.Static>
|
|
140
|
+
</FormGroup>
|
|
141
|
+
);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const GenDummy = () => (
|
|
145
|
+
<FormGroup className="text_generic_properties">
|
|
146
|
+
<FormControl type="text" className="dummy" readOnly />
|
|
147
|
+
</FormGroup>
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
const GenPropertiesInputGroup = (opt) => {
|
|
151
|
+
const fieldHeader = opt.label === '' ? null : <FieldLabel label={opt.label} desc={opt.description} />;
|
|
152
|
+
const fLab = e => <div key={uuid()} className="form-control g_input_group_label">{e.value}</div>;
|
|
153
|
+
const fTxt = e => <FormControl className="g_input_group" key={e.id} type={e.type} name={e.id} value={e.value} onChange={o => opt.onSubChange(o, e.id, opt.f_obj)} />;
|
|
154
|
+
const fUnit = e => (
|
|
155
|
+
<span key={`${e.id}_GenPropertiesInputGroup`} className="input-group" style={{ width: '100%' }}>
|
|
156
|
+
<FormControl key={e.id} type="number" name={e.id} value={e.value} onChange={o => opt.onSubChange(o, e.id, opt.f_obj)} min={1} />
|
|
157
|
+
<InputGroup.Button>
|
|
158
|
+
<Button active onClick={() => opt.onSubChange(e, e.id, opt.f_obj)} bsStyle="success">
|
|
159
|
+
{genUnitSup(genUnit(e.option_layers, e.value_system).label) || ''}
|
|
160
|
+
</Button>
|
|
161
|
+
</InputGroup.Button>
|
|
162
|
+
</span>
|
|
163
|
+
);
|
|
164
|
+
const subs = opt.f_obj && opt.f_obj.sub_fields && opt.f_obj.sub_fields.map((e) => {
|
|
165
|
+
if (e.type === 'label') { return fLab(e); } if (e.type === 'system-defined') { return fUnit(e); } return fTxt(e);
|
|
166
|
+
});
|
|
167
|
+
return (
|
|
168
|
+
<FormGroup>
|
|
169
|
+
{fieldHeader}
|
|
170
|
+
<InputGroup style={{ display: 'flex' }}>
|
|
171
|
+
{subs}
|
|
172
|
+
</InputGroup>
|
|
173
|
+
</FormGroup>
|
|
174
|
+
);
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const GenPropertiesNumber = (opt) => {
|
|
178
|
+
let className = opt.isEditable ? 'editable' : 'readonly';
|
|
179
|
+
className = opt.isRequired && opt.isEditable ? 'required' : className;
|
|
180
|
+
const fieldHeader = opt.label === '' ? null : <FieldLabel label={opt.label} desc={opt.description} />;
|
|
181
|
+
return (
|
|
182
|
+
<FormGroup>
|
|
183
|
+
{fieldHeader}
|
|
184
|
+
<FormControl
|
|
185
|
+
type="number"
|
|
186
|
+
value={opt.value}
|
|
187
|
+
onChange={opt.onChange}
|
|
188
|
+
className={className}
|
|
189
|
+
readOnly={opt.readOnly}
|
|
190
|
+
required={opt.isRequired}
|
|
191
|
+
placeholder={opt.placeholder}
|
|
192
|
+
min={1}
|
|
193
|
+
/>
|
|
194
|
+
</FormGroup>
|
|
195
|
+
);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const GenPropertiesSelect = (opt) => {
|
|
199
|
+
const options = opt.options.map(op => ({ value: op.key, name: op.key, label: op.label }));
|
|
200
|
+
let className = opt.isEditable ? 'select_generic_properties_editable' : 'select_generic_properties_readonly';
|
|
201
|
+
className = opt.isRequired && opt.isEditable ? 'select_generic_properties_required' : className;
|
|
202
|
+
className = `${className} status-select`;
|
|
203
|
+
const fieldHeader = opt.label === '' ? null : <FieldLabel label={opt.label} desc={opt.description} />;
|
|
204
|
+
const val = options.find(o => o.value === opt.value) || null;
|
|
205
|
+
return (
|
|
206
|
+
<FormGroup>
|
|
207
|
+
{fieldHeader}
|
|
208
|
+
<Select
|
|
209
|
+
isClearable
|
|
210
|
+
menuContainerStyle={{ position: 'absolute' }}
|
|
211
|
+
name={opt.field}
|
|
212
|
+
multi={false}
|
|
213
|
+
options={options}
|
|
214
|
+
value={val}
|
|
215
|
+
onChange={opt.onChange}
|
|
216
|
+
className={className}
|
|
217
|
+
disabled={opt.readOnly}
|
|
218
|
+
/>
|
|
219
|
+
</FormGroup>
|
|
220
|
+
);
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
const GenPropertiesSystemDefined = (opt) => {
|
|
224
|
+
let className = opt.isEditable ? 'editable' : 'readonly';
|
|
225
|
+
className = opt.isRequired && opt.isEditable ? 'required' : className;
|
|
226
|
+
const fieldHeader = opt.label === '' ? null : <FieldLabel label={opt.label} desc={opt.description} />;
|
|
227
|
+
return (
|
|
228
|
+
<FormGroup>
|
|
229
|
+
{fieldHeader}
|
|
230
|
+
<InputGroup>
|
|
231
|
+
<FormControl
|
|
232
|
+
type="number"
|
|
233
|
+
value={opt.value}
|
|
234
|
+
onChange={opt.onChange}
|
|
235
|
+
className={className}
|
|
236
|
+
readOnly={opt.readOnly}
|
|
237
|
+
required={opt.isRequired}
|
|
238
|
+
placeholder={opt.placeholder}
|
|
239
|
+
min={1}
|
|
240
|
+
/>
|
|
241
|
+
<InputGroup.Button>
|
|
242
|
+
<Button disabled={opt.readOnly} active onClick={opt.onClick} bsStyle="success">
|
|
243
|
+
{genUnitSup(genUnit(opt.option_layers, opt.value_system).label) || ''}
|
|
244
|
+
</Button>
|
|
245
|
+
</InputGroup.Button>
|
|
246
|
+
</InputGroup>
|
|
247
|
+
</FormGroup>
|
|
248
|
+
);
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const GenPropertiesTable = (opt) => {
|
|
252
|
+
const fieldHeader = opt.label === '' ? null : <FieldLabel label={opt.label} desc={opt.description} />;
|
|
253
|
+
return (
|
|
254
|
+
<FormGroup>
|
|
255
|
+
{fieldHeader}
|
|
256
|
+
<TableRecord key={`grid_${opt.f_obj.field}`} opt={opt} />
|
|
257
|
+
</FormGroup>
|
|
258
|
+
);
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const GenPropertiesText = (opt) => {
|
|
262
|
+
let className = opt.isEditable ? 'editable' : 'readonly';
|
|
263
|
+
className = opt.isRequired && opt.isEditable ? 'required' : className;
|
|
264
|
+
const fieldHeader = opt.label === '' ? null : <FieldLabel label={opt.label} desc={opt.description} />;
|
|
265
|
+
return (
|
|
266
|
+
<FormGroup className="text_generic_properties">
|
|
267
|
+
{fieldHeader}
|
|
268
|
+
<FormControl
|
|
269
|
+
type="text"
|
|
270
|
+
value={opt.value}
|
|
271
|
+
onChange={opt.onChange}
|
|
272
|
+
className={className}
|
|
273
|
+
readOnly={opt.readOnly}
|
|
274
|
+
required={opt.isRequired}
|
|
275
|
+
placeholder={opt.placeholder}
|
|
276
|
+
/>
|
|
277
|
+
</FormGroup>
|
|
278
|
+
);
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
const GenPropertiesTextArea = (opt) => {
|
|
282
|
+
let className = opt.isEditable ? 'editable' : 'readonly';
|
|
283
|
+
className = opt.isRequired && opt.isEditable ? 'required' : className;
|
|
284
|
+
const fieldHeader = opt.label === '' ? null : <FieldLabel label={opt.label} desc={opt.description} />;
|
|
285
|
+
return (
|
|
286
|
+
<FormGroup className="text_generic_properties">
|
|
287
|
+
{fieldHeader}
|
|
288
|
+
<FormControl
|
|
289
|
+
componentClass="textarea"
|
|
290
|
+
value={opt.value}
|
|
291
|
+
onChange={opt.onChange}
|
|
292
|
+
className={className}
|
|
293
|
+
readOnly={opt.readOnly}
|
|
294
|
+
required={opt.isRequired}
|
|
295
|
+
placeholder={opt.placeholder}
|
|
296
|
+
/>
|
|
297
|
+
</FormGroup>
|
|
298
|
+
);
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const GenTextFormula = (opt) => {
|
|
302
|
+
const { layers } = opt;
|
|
303
|
+
const fieldHeader = opt.label === '' ? null : <FieldLabel label={opt.label} desc={opt.description} />;
|
|
304
|
+
const subs = [];
|
|
305
|
+
(opt.f_obj && opt.f_obj.text_sub_fields).map((e) => {
|
|
306
|
+
const { layer, field, separator } = e;
|
|
307
|
+
if (field && field !== '') {
|
|
308
|
+
if (field.includes('[@@]')) {
|
|
309
|
+
const fds = field.split('[@@]');
|
|
310
|
+
if (fds && fds.length === 2) {
|
|
311
|
+
const fdt = ((layers[layer] || {}).fields || []).find(f => f.field === fds[0] && f.type === 'table');
|
|
312
|
+
((fdt && fdt.sub_values) || []).forEach((svv) => {
|
|
313
|
+
if (svv && svv[fds[1]] && svv[fds[1]] !== '') { subs.push(svv[fds[1]]); subs.push(separator); }
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
} else {
|
|
317
|
+
const fd = ((layers[layer] || {}).fields || []).find(f => f.field === field);
|
|
318
|
+
if (fd && fd.value && fd.value !== '') { subs.push(fd.value); subs.push(separator); }
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return true;
|
|
322
|
+
});
|
|
323
|
+
return (
|
|
324
|
+
<FormGroup className="text_generic_properties">
|
|
325
|
+
{fieldHeader}
|
|
326
|
+
<FormControl
|
|
327
|
+
type="text"
|
|
328
|
+
value={subs.join('')}
|
|
329
|
+
className="readonly"
|
|
330
|
+
readOnly
|
|
331
|
+
required={false}
|
|
332
|
+
/>
|
|
333
|
+
</FormGroup>
|
|
334
|
+
);
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
const renderListGroupItem = (opt, attachment) => {
|
|
338
|
+
const delBtn = (
|
|
339
|
+
<Button bsSize="xsmall" id={attachment.uid} className="button-right" onClick={() => opt.onChange({ ...opt.value, action: 'd', uid: attachment.uid })}>
|
|
340
|
+
<i className="fa fa-times" aria-hidden="true" />
|
|
341
|
+
</Button>
|
|
342
|
+
);
|
|
343
|
+
const filename = attachment.aid ?
|
|
344
|
+
(<a onClick={() => downloadFile({ contents: `/api/v1/attachments/${attachment.aid}`, name: attachment.filename })} style={{ cursor: 'pointer' }}>{attachment.filename}</a>) : attachment.filename;
|
|
345
|
+
return (
|
|
346
|
+
<div className="generic_grid">
|
|
347
|
+
<div>
|
|
348
|
+
<div>{delBtn}</div>
|
|
349
|
+
<div className="generic_grid_row">{filename}</div>
|
|
350
|
+
<div className="generic_grid_row">
|
|
351
|
+
<FormGroup bsSize="small">
|
|
352
|
+
<FormControl
|
|
353
|
+
type="text"
|
|
354
|
+
value={attachment.label || ''}
|
|
355
|
+
onChange={e => opt.onChange({
|
|
356
|
+
...opt.value, action: 'l', uid: attachment.uid, val: e
|
|
357
|
+
})}
|
|
358
|
+
/>
|
|
359
|
+
</FormGroup>
|
|
360
|
+
</div>
|
|
361
|
+
</div>
|
|
362
|
+
</div>
|
|
363
|
+
);
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
const GenPropertiesUpload = (opt) => {
|
|
367
|
+
const fieldHeader = opt.label === '' ? null : <FieldLabel label={opt.label} desc={opt.description} />;
|
|
368
|
+
const attachments = (opt.value && opt.value.files) || [];
|
|
369
|
+
if (opt.isSearchCriteria) return (<div>(This is an upload)</div>);
|
|
370
|
+
|
|
371
|
+
return (
|
|
372
|
+
<FormGroup className="text_generic_properties">
|
|
373
|
+
{fieldHeader}
|
|
374
|
+
<FormControl.Static style={{ paddingBottom: '0px' }}>
|
|
375
|
+
<Dropzone
|
|
376
|
+
id="dropzone"
|
|
377
|
+
onDrop={e => opt.onChange({
|
|
378
|
+
...opt.value, action: 'f', val: e
|
|
379
|
+
})}
|
|
380
|
+
style={{ height: 30, width: '100%', border: '3px dashed lightgray' }}
|
|
381
|
+
>
|
|
382
|
+
<div style={{ textAlign: 'center', paddingTop: 6, color: 'gray' }}>
|
|
383
|
+
Drop File, or Click to Select.
|
|
384
|
+
</div>
|
|
385
|
+
</Dropzone>
|
|
386
|
+
</FormControl.Static>
|
|
387
|
+
<ListGroup>
|
|
388
|
+
{attachments.map(attachment => (
|
|
389
|
+
<ListGroupItem key={attachment.id} className="generic_files">
|
|
390
|
+
{renderListGroupItem(opt, attachment)}
|
|
391
|
+
</ListGroupItem>
|
|
392
|
+
))}
|
|
393
|
+
</ListGroup>
|
|
394
|
+
</FormGroup>
|
|
395
|
+
);
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
const GenWFNext = (opt) => {
|
|
399
|
+
const options = (opt.f_obj.wf_options || []).map((op) => {
|
|
400
|
+
const label = op.label.match(/(.*)\(.*\)/);
|
|
401
|
+
return ({ value: op.key, name: op.key, label: label[1] === '' ? label[0] : label[1] });
|
|
402
|
+
});
|
|
403
|
+
let className = opt.isEditable ? 'select_generic_properties_editable' : 'select_generic_properties_readonly';
|
|
404
|
+
className = opt.isRequired && opt.isEditable ? 'select_generic_properties_required' : className;
|
|
405
|
+
className = `${className} status-select`;
|
|
406
|
+
const fieldHeader = opt.label === '' ? null : <FieldLabel label={opt.label} desc={opt.description} />;
|
|
407
|
+
const val = options.find(o => o.value === opt.value) || null;
|
|
408
|
+
return (
|
|
409
|
+
<FormGroup>
|
|
410
|
+
{fieldHeader}
|
|
411
|
+
<Select
|
|
412
|
+
menuContainerStyle={{ position: 'absolute' }}
|
|
413
|
+
name={opt.field}
|
|
414
|
+
multi={false}
|
|
415
|
+
options={options}
|
|
416
|
+
value={val}
|
|
417
|
+
onChange={opt.onChange}
|
|
418
|
+
className={className}
|
|
419
|
+
disabled={opt.readOnly}
|
|
420
|
+
/>
|
|
421
|
+
</FormGroup>
|
|
422
|
+
);
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
export {
|
|
426
|
+
GenPropertiesCalculate,
|
|
427
|
+
GenPropertiesCheckbox,
|
|
428
|
+
GenPropertiesDrop,
|
|
429
|
+
GenDummy,
|
|
430
|
+
GenTextFormula,
|
|
431
|
+
GenPropertiesInputGroup,
|
|
432
|
+
GenPropertiesNumber,
|
|
433
|
+
GenPropertiesSelect,
|
|
434
|
+
GenPropertiesSystemDefined,
|
|
435
|
+
GenPropertiesTable,
|
|
436
|
+
GenPropertiesText,
|
|
437
|
+
GenPropertiesTextArea,
|
|
438
|
+
GenPropertiesUpload,
|
|
439
|
+
GenWFNext
|
|
440
|
+
};
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/* eslint-disable max-len */
|
|
2
|
+
/* eslint-disable react/require-default-props */
|
|
3
|
+
/* eslint-disable react/forbid-prop-types */
|
|
4
|
+
import React, { Component } from 'react';
|
|
5
|
+
import PropTypes from 'prop-types';
|
|
6
|
+
import { Panel, Col, PanelGroup, Row } from 'react-bootstrap';
|
|
7
|
+
import GenProperties from '../fields/GenProperties';
|
|
8
|
+
import { genUnits, showProperties, unitConversion } from '../tools/utils';
|
|
9
|
+
import PanelDnD from '../dnd/PanelDnD';
|
|
10
|
+
|
|
11
|
+
export default class GenPropertiesLayer extends Component {
|
|
12
|
+
constructor(props) {
|
|
13
|
+
super(props);
|
|
14
|
+
this.handleChange = this.handleChange.bind(this);
|
|
15
|
+
this.handleSubChange = this.handleSubChange.bind(this);
|
|
16
|
+
this.moveLayer = this.moveLayer.bind(this);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
handleChange(e, f, k, t) {
|
|
20
|
+
this.props.onChange(e, f, k, t);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
handleSubChange(e, id, f, valueOnly = false) {
|
|
24
|
+
const sub = f.sub_fields.find(m => m.id === id);
|
|
25
|
+
if (!valueOnly) {
|
|
26
|
+
if (e.type === 'system-defined') {
|
|
27
|
+
const units = genUnits(e.option_layers);
|
|
28
|
+
let uIdx = units.findIndex(u => u.key === e.value_system);
|
|
29
|
+
if (uIdx < units.length - 1) uIdx += 1; else uIdx = 0;
|
|
30
|
+
sub.value_system = units.length > 0 ? units[uIdx].key : '';
|
|
31
|
+
sub.value = unitConversion(e.option_layers, sub.value_system, e.value);
|
|
32
|
+
} else {
|
|
33
|
+
sub.value = e.target.value;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const { layer } = this.props;
|
|
37
|
+
const obj = { f, sub };
|
|
38
|
+
this.props.onSubChange(layer.key, obj, valueOnly);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
handleClick(keyLayer, obj, val) {
|
|
42
|
+
const units = genUnits(obj.option_layers);
|
|
43
|
+
let uIdx = units.findIndex(e => e.key === val);
|
|
44
|
+
if (uIdx < units.length - 1) uIdx += 1; else uIdx = 0;
|
|
45
|
+
const update = obj;
|
|
46
|
+
update.value_system = units.length > 0 ? units[uIdx].key : '';
|
|
47
|
+
this.props.onClick(keyLayer, update);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
views() {
|
|
51
|
+
const {
|
|
52
|
+
layer, selectOptions, id, layers, isPreview
|
|
53
|
+
} = this.props;
|
|
54
|
+
const { cols, fields, key } = layer;
|
|
55
|
+
const perRow = cols || 1;
|
|
56
|
+
const col = Math.floor(12 / perRow);
|
|
57
|
+
const klaz = (12 % perRow) > 0 ? 'g_col_w' : '';
|
|
58
|
+
const vs = [];
|
|
59
|
+
let op = [];
|
|
60
|
+
let newRow = 0;
|
|
61
|
+
let rowId = 1;
|
|
62
|
+
(fields || []).forEach((f, i) => {
|
|
63
|
+
if (showProperties(f, layers)) {
|
|
64
|
+
const unit = genUnits(f.option_layers)[0] || {};
|
|
65
|
+
const tabCol = (f.cols || 1) * 1;
|
|
66
|
+
const rCol = (f.type === 'table') ? (12 / (tabCol || 1)) : col;
|
|
67
|
+
newRow = (f.type === 'table') ? newRow += (perRow / (tabCol || 1)) : newRow += 1;
|
|
68
|
+
|
|
69
|
+
if (newRow > perRow) {
|
|
70
|
+
vs.push(<Row key={rowId}>{op}</Row>);
|
|
71
|
+
rowId += 1;
|
|
72
|
+
op = [];
|
|
73
|
+
newRow = (f.type === 'table') ? newRow = (perRow / (tabCol || 1)) : newRow = 1;
|
|
74
|
+
}
|
|
75
|
+
const eachCol = (
|
|
76
|
+
<Col key={`prop_${key}_${f.priority}_${f.field}`} md={rCol} lg={rCol} className={f.type === 'table' ? '' : klaz}>
|
|
77
|
+
<GenProperties
|
|
78
|
+
key={`${id}_${layer}_${f.field}_GenPropertiesLayer`}
|
|
79
|
+
layers={layers}
|
|
80
|
+
id={id}
|
|
81
|
+
layer={layer}
|
|
82
|
+
f_obj={f}
|
|
83
|
+
label={f.label}
|
|
84
|
+
value={f.value || ''}
|
|
85
|
+
description={f.description || ''}
|
|
86
|
+
type={f.type || 'text'}
|
|
87
|
+
field={f.field || 'field'}
|
|
88
|
+
formula={f.formula || ''}
|
|
89
|
+
options={(selectOptions && selectOptions[f.option_layers] && selectOptions[f.option_layers].options) || []}
|
|
90
|
+
onChange={event => this.handleChange(event, f.field, key, f.type)}
|
|
91
|
+
onSubChange={this.handleSubChange}
|
|
92
|
+
isEditable
|
|
93
|
+
isPreview={isPreview}
|
|
94
|
+
readOnly={false}
|
|
95
|
+
isRequired={f.required || false}
|
|
96
|
+
placeholder={f.placeholder || ''}
|
|
97
|
+
option_layers={f.option_layers}
|
|
98
|
+
value_system={f.value_system || unit.key}
|
|
99
|
+
onClick={() => this.handleClick(key, f, (f.value_system || unit.key))}
|
|
100
|
+
selectOptions={selectOptions || {}}
|
|
101
|
+
/>
|
|
102
|
+
</Col>
|
|
103
|
+
);
|
|
104
|
+
op.push(eachCol);
|
|
105
|
+
if (newRow % perRow === 0) newRow = 0;
|
|
106
|
+
if ((newRow === 0) || (fields.length === (i + 1))) {
|
|
107
|
+
vs.push(<Row key={rowId}>{op}</Row>);
|
|
108
|
+
rowId += 1;
|
|
109
|
+
op = [];
|
|
110
|
+
}
|
|
111
|
+
} else if (fields.length === (i + 1)) {
|
|
112
|
+
vs.push(<Row key={rowId}>{op}</Row>);
|
|
113
|
+
rowId += 1;
|
|
114
|
+
op = [];
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
return vs;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
moveLayer(src, tar) {
|
|
121
|
+
this.handleChange(null, src, tar, 'drop-layer');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
render() {
|
|
125
|
+
const { id, layer, activeWF } = this.props;
|
|
126
|
+
const { color, style, label } = layer;
|
|
127
|
+
let bs = color || 'default';
|
|
128
|
+
const cl = (style || 'panel_generic_heading').replace('panel_generic_heading', 'panel_generic_heading_slim');
|
|
129
|
+
// panel header color is based on input bs value
|
|
130
|
+
const panelDnD = (<PanelDnD
|
|
131
|
+
type="gen_panel"
|
|
132
|
+
layer={layer}
|
|
133
|
+
field="layer"
|
|
134
|
+
rowValue={{ id: layer.key }}
|
|
135
|
+
handleMove={this.moveLayer}
|
|
136
|
+
id={id}
|
|
137
|
+
handleChange={this.handleChange}
|
|
138
|
+
bs={bs}
|
|
139
|
+
/>);
|
|
140
|
+
const panelHeader = label === '' ? (<span />) : (
|
|
141
|
+
<Panel.Heading className={cl}>
|
|
142
|
+
<Panel.Title toggle>{label}</Panel.Title>
|
|
143
|
+
</Panel.Heading>
|
|
144
|
+
);
|
|
145
|
+
const noneKlass = bs === 'none' ? 'generic_panel_none' : '';
|
|
146
|
+
if (bs === 'none') bs = 'default';
|
|
147
|
+
return (
|
|
148
|
+
<PanelGroup accordion id="accordion_generic_layer" defaultActiveKey="1" style={{ marginBottom: '0px' }}>
|
|
149
|
+
<Panel bsStyle={bs} className={`panel_generic_properties ${noneKlass}`} eventKey="1">
|
|
150
|
+
{activeWF ? panelDnD : panelHeader}
|
|
151
|
+
<Panel.Collapse>
|
|
152
|
+
<Panel.Body className="panel_generic_properties_body">{this.views()}</Panel.Body>
|
|
153
|
+
</Panel.Collapse>
|
|
154
|
+
</Panel>
|
|
155
|
+
</PanelGroup>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
GenPropertiesLayer.propTypes = {
|
|
161
|
+
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), // element id or new id
|
|
162
|
+
layer: PropTypes.object,
|
|
163
|
+
selectOptions: PropTypes.object,
|
|
164
|
+
onChange: PropTypes.func.isRequired,
|
|
165
|
+
onSubChange: PropTypes.func.isRequired,
|
|
166
|
+
onClick: PropTypes.func,
|
|
167
|
+
layers: PropTypes.object.isRequired,
|
|
168
|
+
isPreview: PropTypes.bool,
|
|
169
|
+
activeWF: PropTypes.bool
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
GenPropertiesLayer.defaultProps = {
|
|
173
|
+
id: 0,
|
|
174
|
+
selectOptions: {},
|
|
175
|
+
onClick: () => {},
|
|
176
|
+
isPreview: false,
|
|
177
|
+
activeWF: false
|
|
178
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/* eslint-disable react/forbid-prop-types */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
import { Button, Tooltip, Modal, OverlayTrigger } from 'react-bootstrap';
|
|
5
|
+
import { sortBy } from 'lodash';
|
|
6
|
+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
7
|
+
|
|
8
|
+
const block = (layer, fnAdd) => (
|
|
9
|
+
<div className="generic_layer_column">
|
|
10
|
+
<div>
|
|
11
|
+
<div><b>{layer.label}</b><br />({layer.key})</div>
|
|
12
|
+
<OverlayTrigger delayShow={1000} placement="top" overlay={<Tooltip id="_tooltip_layers">click to add layer</Tooltip>}>
|
|
13
|
+
<Button bsStyle="primary" onClick={event => fnAdd(event, layer)}><FontAwesomeIcon icon="fas fa-plus" /></Button>
|
|
14
|
+
</OverlayTrigger>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
const drawLayout = (layers, fnAdd) => {
|
|
20
|
+
const layout = [];
|
|
21
|
+
layers.forEach((layer) => { layout.push(<div key={layer.key}>{block(layer, fnAdd)}</div>); });
|
|
22
|
+
return layout;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const LayerModal = (props) => {
|
|
26
|
+
const {
|
|
27
|
+
show, layers, fnClose, fnAdd
|
|
28
|
+
} = props;
|
|
29
|
+
if (!show) return null;
|
|
30
|
+
const sortedLayers = sortBy(layers, ['position', 'wf_position']) || [];
|
|
31
|
+
if (sortedLayers.length < 1) return null;
|
|
32
|
+
const layout = drawLayout(sortedLayers, fnAdd);
|
|
33
|
+
return (
|
|
34
|
+
<Modal show={show} onHide={fnClose}>
|
|
35
|
+
<Modal.Header closeButton><Modal.Title>Choose Layer</Modal.Title></Modal.Header>
|
|
36
|
+
<Modal.Body>
|
|
37
|
+
<div style={{ maxHeight: '80vh', overflow: 'auto' }}>
|
|
38
|
+
<div className="generic_grid">{layout}</div>
|
|
39
|
+
</div>
|
|
40
|
+
</Modal.Body>
|
|
41
|
+
</Modal>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
LayerModal.propTypes = {
|
|
46
|
+
show: PropTypes.bool.isRequired,
|
|
47
|
+
layers: PropTypes.object.isRequired,
|
|
48
|
+
fnClose: PropTypes.func.isRequired,
|
|
49
|
+
fnAdd: PropTypes.func.isRequired
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default LayerModal;
|