@iobroker/json-config 6.17.12 → 6.17.14

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 (61) hide show
  1. package/package.json +27 -27
  2. package/src/JsonConfig.tsx +0 -710
  3. package/src/JsonConfigComponent/ChipInput.tsx +0 -752
  4. package/src/JsonConfigComponent/ConfigAccordion.tsx +0 -278
  5. package/src/JsonConfigComponent/ConfigAlive.tsx +0 -74
  6. package/src/JsonConfigComponent/ConfigAutocomplete.tsx +0 -108
  7. package/src/JsonConfigComponent/ConfigAutocompleteSendTo.tsx +0 -183
  8. package/src/JsonConfigComponent/ConfigCRON.jsx +0 -101
  9. package/src/JsonConfigComponent/ConfigCertCollection.tsx +0 -102
  10. package/src/JsonConfigComponent/ConfigCertificateSelect.tsx +0 -92
  11. package/src/JsonConfigComponent/ConfigCertificates.tsx +0 -202
  12. package/src/JsonConfigComponent/ConfigCheckLicense.jsx +0 -662
  13. package/src/JsonConfigComponent/ConfigCheckbox.tsx +0 -67
  14. package/src/JsonConfigComponent/ConfigChip.jsx +0 -81
  15. package/src/JsonConfigComponent/ConfigColor.tsx +0 -86
  16. package/src/JsonConfigComponent/ConfigCoordinates.tsx +0 -234
  17. package/src/JsonConfigComponent/ConfigCustom.tsx +0 -246
  18. package/src/JsonConfigComponent/ConfigDatePicker.tsx +0 -48
  19. package/src/JsonConfigComponent/ConfigDeviceManager.tsx +0 -33
  20. package/src/JsonConfigComponent/ConfigFile.jsx +0 -181
  21. package/src/JsonConfigComponent/ConfigFileSelector.jsx +0 -520
  22. package/src/JsonConfigComponent/ConfigFunc.jsx +0 -90
  23. package/src/JsonConfigComponent/ConfigGeneric.tsx +0 -1027
  24. package/src/JsonConfigComponent/ConfigIP.jsx +0 -96
  25. package/src/JsonConfigComponent/ConfigImageSendTo.jsx +0 -79
  26. package/src/JsonConfigComponent/ConfigImageUpload.jsx +0 -114
  27. package/src/JsonConfigComponent/ConfigInstanceSelect.jsx +0 -172
  28. package/src/JsonConfigComponent/ConfigInterface.jsx +0 -112
  29. package/src/JsonConfigComponent/ConfigJsonEditor.jsx +0 -103
  30. package/src/JsonConfigComponent/ConfigLanguage.tsx +0 -153
  31. package/src/JsonConfigComponent/ConfigLicense.jsx +0 -148
  32. package/src/JsonConfigComponent/ConfigNumber.tsx +0 -207
  33. package/src/JsonConfigComponent/ConfigObjectId.jsx +0 -113
  34. package/src/JsonConfigComponent/ConfigPanel.tsx +0 -360
  35. package/src/JsonConfigComponent/ConfigPassword.jsx +0 -160
  36. package/src/JsonConfigComponent/ConfigPattern.jsx +0 -50
  37. package/src/JsonConfigComponent/ConfigPort.tsx +0 -232
  38. package/src/JsonConfigComponent/ConfigRoom.jsx +0 -90
  39. package/src/JsonConfigComponent/ConfigSelect.jsx +0 -124
  40. package/src/JsonConfigComponent/ConfigSelectSendTo.tsx +0 -251
  41. package/src/JsonConfigComponent/ConfigSendto.tsx +0 -340
  42. package/src/JsonConfigComponent/ConfigSetState.jsx +0 -116
  43. package/src/JsonConfigComponent/ConfigSlider.jsx +0 -97
  44. package/src/JsonConfigComponent/ConfigStaticDivider.jsx +0 -51
  45. package/src/JsonConfigComponent/ConfigStaticHeader.jsx +0 -63
  46. package/src/JsonConfigComponent/ConfigStaticImage.jsx +0 -48
  47. package/src/JsonConfigComponent/ConfigStaticText.jsx +0 -72
  48. package/src/JsonConfigComponent/ConfigTable.tsx +0 -1040
  49. package/src/JsonConfigComponent/ConfigTabs.tsx +0 -150
  50. package/src/JsonConfigComponent/ConfigText.tsx +0 -188
  51. package/src/JsonConfigComponent/ConfigTextSendTo.tsx +0 -102
  52. package/src/JsonConfigComponent/ConfigTimePicker.tsx +0 -63
  53. package/src/JsonConfigComponent/ConfigTopic.jsx +0 -78
  54. package/src/JsonConfigComponent/ConfigUUID.tsx +0 -55
  55. package/src/JsonConfigComponent/ConfigUser.jsx +0 -104
  56. package/src/JsonConfigComponent/index.tsx +0 -435
  57. package/src/JsonConfigComponent/wrapper/Components/CustomModal.jsx +0 -145
  58. package/src/JsonConfigComponent/wrapper/Components/Editor.jsx +0 -65
  59. package/src/Utils.jsx +0 -1683
  60. package/src/index.tsx +0 -14
  61. package/src/types.d.ts +0 -372
@@ -1,520 +0,0 @@
1
- import React from 'react';
2
- import PropTypes from 'prop-types';
3
- import { withStyles } from '@mui/styles';
4
- import Dropzone from 'react-dropzone';
5
-
6
- import {
7
- InputLabel,
8
- MenuItem,
9
- FormHelperText,
10
- FormControl,
11
- Select,
12
- IconButton,
13
- ListItemText,
14
- ListItemIcon,
15
- } from '@mui/material';
16
-
17
- import {
18
- Refresh as IconRefresh,
19
- UploadFile as IconUpload,
20
- Delete as IconDelete,
21
- PlayArrow as IconPlay,
22
- MusicNote as IconAudio,
23
- Videocam as IconVideo,
24
- Article as IconText,
25
- Code as IconCode,
26
- } from '@mui/icons-material';
27
- import { FaFileUpload as UploadIcon } from 'react-icons/fa';
28
-
29
- import { Confirm as ConfirmDialog, Utils, I18n } from '@iobroker/adapter-react-v5';
30
-
31
- import ConfigGeneric from './ConfigGeneric';
32
-
33
- const styles = () => ({
34
- fullWidth: {
35
- width: '100%',
36
- },
37
- fullWidthOneButton: {
38
- width: 'calc(100% - 42px)',
39
- },
40
- fullWidthTwoButtons: {
41
- width: 'calc(100% - 84px)',
42
- },
43
- fullWidthThreeButtons: {
44
- width: 'calc(100% - 126x)',
45
- },
46
- dropZone: {
47
- width: '100%',
48
- height: '100%',
49
- position: 'absolute',
50
- },
51
- dropZoneEmpty: {
52
-
53
- },
54
- image: {
55
- objectFit: 'contain',
56
- margin: 'auto',
57
- display: 'flex',
58
- width: '100%',
59
- height: '100%',
60
- },
61
- uploadDiv: {
62
- position: 'relative',
63
- width: '100%',
64
- },
65
- uploadDivDragging: {
66
- opacity: 1,
67
- background: 'rgba(128,255,128,0.1)',
68
- },
69
- uploadCenterDiv: {
70
- margin: 5,
71
- border: '3px dashed grey',
72
- borderRadius: 5,
73
- width: '100%',
74
- height: '100%',
75
- position: 'absolute',
76
- display: 'flex',
77
- },
78
- uploadCenterIcon: {
79
- paddingTop: 10,
80
- width: 48,
81
- height: 48,
82
- },
83
- uploadCenterText: {
84
- fontSize: 16,
85
- },
86
- uploadCenterTextAndIcon: {
87
- textAlign: 'center',
88
- position: 'absolute',
89
- top: 0,
90
- bottom: 0,
91
- left: 0,
92
- right: 0,
93
- display: 'flex',
94
- flexDirection: 'column',
95
- alignItems: 'center',
96
- justifyContent: 'center',
97
- },
98
- disabledOpacity: {
99
- opacity: 0.3,
100
- cursor: 'default',
101
- },
102
- error: {
103
- border: '2px solid red',
104
- },
105
- deleteButton: {
106
-
107
- },
108
- selectedImage: {
109
- height: 40,
110
- width: 40,
111
- display: 'inline-block',
112
- marginRight: 8,
113
- },
114
- });
115
-
116
- const IMAGE_EXT = ['jpg', 'jpeg', 'svg', 'png', 'webp', 'gif', 'apng', 'avif', 'webp'];
117
- const AUDIO_EXT = ['mp3', 'ogg', 'wav', 'aac'];
118
- const VIDEO_EXT = ['avi', 'mp4', 'mov'];
119
- const DOC_EXT = ['txt', 'log', 'html', 'htm'];
120
- const JS_EXT = ['json', 'js', 'ts'];
121
-
122
- class ConfigFileSelector extends ConfigGeneric {
123
- constructor(props) {
124
- super(props);
125
- this.dropzoneRef = React.createRef();
126
- this.imagePrefix = this.props.imagePrefix === undefined ? './files' : this.props.imagePrefix;
127
- }
128
-
129
- componentDidMount() {
130
- super.componentDidMount();
131
-
132
- this.objectID = (this.props.schema.objectID || '0_userdata.0').replace('%INSTANCE%', this.props.instance);
133
- this.path = this.props.schema.upload;
134
- if (this.path) {
135
- if (this.path === '/') {
136
- this.path = '';
137
- } else if (!this.path.endsWith('/')) {
138
- this.path = `${this.path}/`;
139
- }
140
- }
141
-
142
- // read files
143
- this.updateFiles()
144
- .then(() => {
145
- const value = ConfigGeneric.getValue(this.props.data, this.props.attr);
146
- this.setState({ value });
147
- });
148
- }
149
-
150
- updateFiles() {
151
- return this.readFiles(this.props.schema.pattern)
152
- .then(files => this.setState({ files }));
153
- }
154
-
155
- async readFolder(folderName, files, filter) {
156
- try {
157
- const dirFiles = await this.props.socket.readDir(this.objectID, folderName.replace(/^\//, '') || null);
158
- for (let f = 0; f < dirFiles.length; f++) {
159
- const file = dirFiles[f];
160
- if (file.isDir) {
161
- // read it
162
- await this.readFolder(`${folderName + file.file}/`, files, filter);
163
- } else {
164
- let ok = false;
165
- if (filter === '*.*' && file.file.includes('.')) {
166
- ok = true;
167
- } else if (!filter || filter === '*') {
168
- ok = true;
169
- } else if (filter === '.*' && file.file.startsWith('.')) {
170
- ok = true;
171
- } else {
172
- const regExp = new RegExp(`^${filter.replace(/\./g, '\\.').replace(/\*/g, '.*')}$`);
173
- ok = regExp.test(file.file);
174
- }
175
-
176
- ok && files.push({ name: folderName + file.file, size: file.stats ? Utils.formatBytes(file.stats.size) : '--' });
177
- }
178
- }
179
- } catch (e) {
180
- console.error(`Cannot read "${folderName}": ${e}`);
181
- }
182
-
183
- return files;
184
- }
185
-
186
- async readFiles(pattern) {
187
- const files = [];
188
- pattern = pattern || this.props.schema.pattern;
189
- if (!pattern) {
190
- pattern = '**/*.*';
191
- }
192
- let filter;
193
- const pos = pattern.lastIndexOf('/');
194
- if (pos === -1) {
195
- filter = pattern;
196
- } else {
197
- filter = pattern.substring(pos + 1);
198
- }
199
-
200
- if (pattern.startsWith('**')) {
201
- // read all folders
202
- await this.readFolder('/', files, filter);
203
- } else {
204
- const pos_ = pattern.lastIndexOf('/');
205
- if (pos_ === -1) {
206
- await this.readFolder('/', files, filter);
207
- } else {
208
- const folder = pattern.substring(0, pos_ + 1);
209
- await this.readFolder(folder, files, filter);
210
- }
211
- }
212
-
213
- return files;
214
- }
215
-
216
- onDrop(acceptedFiles) {
217
- const file = acceptedFiles[0];
218
- const reader = new FileReader();
219
- const maxSize = this.props.schema.maxSize || (2 * 1024 * 1024);
220
-
221
- reader.onabort = () => console.log('file reading was aborted');
222
- reader.onerror = () => console.log('file reading has failed');
223
- reader.onload = () => {
224
- let ext = `image/${file.name.split('.').pop().toLowerCase()}`;
225
- if (ext === 'image/jpg') {
226
- ext = 'image/jpeg';
227
- } else if (ext.includes('svg')) {
228
- ext = 'image/svg+xml';
229
- }
230
- if (file.size > maxSize) {
231
- window.alert(I18n.t('File is too big. Max %sk allowed. Try use SVG.', Math.round(maxSize / 1024)));
232
- return;
233
- }
234
- const base64 = `data:${ext};base64,${btoa(
235
- new Uint8Array(reader.result)
236
- .reduce((data, byte) => data + String.fromCharCode(byte), ''),
237
- )}`;
238
-
239
- this.props.socket.writeFile64(this.objectID, this.path + file.name, base64)
240
- .then(() => this.updateFiles())
241
- .catch(e => window.alert(`Cannot upload file: ${e}`));
242
- };
243
- reader.readAsArrayBuffer(file);
244
- }
245
-
246
- renderDeleteDialog() {
247
- if (!this.state.deleteFile) {
248
- return null;
249
- }
250
- return <ConfirmDialog
251
- title={I18n.t('ra_Are you sure?')}
252
- text={I18n.t('ra_File will be deleted')}
253
- ok={I18n.t('ra_Delete')}
254
- cancel={I18n.t('ra_Cancel')}
255
- onClose={isOk => {
256
- const deleteFile = this.state.deleteFile;
257
- this.setState({ deleteFile: false }, () => {
258
- if (isOk) {
259
- this.props.socket.deleteFile(this.objectID, deleteFile)
260
- .then(() => this.updateFiles())
261
- .catch(e => window.alert(`Cannot delete file: ${e}`));
262
- }
263
- });
264
- }}
265
- />;
266
- }
267
-
268
- static base64ToArrayBuffer(base64) {
269
- const binaryString = window.atob(base64);
270
- const len = binaryString.length;
271
- const bytes = new Uint8Array(len);
272
- for (let i = 0; i < len; i++) {
273
- bytes[i] = binaryString.charCodeAt(i);
274
- }
275
- return bytes.buffer;
276
- }
277
-
278
- loadFile() {
279
- return this.props.socket.readFile(this.objectID, this.state.value, true);
280
- }
281
-
282
- play() {
283
- this.loadFile()
284
- .then(data => {
285
- if (typeof AudioContext !== 'undefined') {
286
- const context = new AudioContext();
287
- const buf = ConfigFileSelector.base64ToArrayBuffer(data.file);
288
- context.decodeAudioData(buf, buffer => {
289
- const source = context.createBufferSource(); // creates a sound source
290
- source.buffer = buffer; // tell the source which sound to play
291
- source.connect(context.destination); // connect the source to the context's destination (the speakers)
292
- source.start(0);
293
- }, err => window.alert(`Cannot play: ${err}`));
294
- }
295
- });
296
- }
297
-
298
- getIcon(item) {
299
- if (!item || !item.extension) {
300
- return null;
301
- }
302
- if (IMAGE_EXT.includes(item.extension)) {
303
- return <div
304
- className={this.props.classes.selectedImage}
305
- style={{
306
- backgroundImage: `url(${this.imagePrefix}/${this.objectID}/${item.value})`,
307
- backgroundSize: 'contain',
308
- backgroundRepeat: 'no-repeat',
309
- }}
310
- />;
311
- } if (AUDIO_EXT.includes(item.extension)) {
312
- return <IconAudio />;
313
- } if (DOC_EXT.includes(item.extension)) {
314
- return <IconText />;
315
- } if (VIDEO_EXT.includes(item.extension)) {
316
- return <IconVideo />;
317
- } if (JS_EXT.includes(item.extension)) {
318
- return <IconCode />;
319
- }
320
- return null;
321
- }
322
-
323
- renderItem(error, disabled) {
324
- if (!this.state.files) {
325
- return null;
326
- }
327
- const folders = [];
328
- if (!this.props.schema.withFolder) {
329
- this.state.files.forEach(file => {
330
- const pos = file.name.lastIndexOf('/');
331
- if (pos === -1) {
332
- if (!folders.includes('/')) {
333
- folders.push('/');
334
- }
335
- } else {
336
- const folder = file.name.substring(0, pos + 1);
337
- if (!folders.includes(folder)) {
338
- folders.push(folder);
339
- }
340
- }
341
- });
342
- }
343
-
344
- /** @typedef {{ value: string, label: string, extension?: string }} Item */
345
- /** @type {Item[]} */
346
- const selectOptions = this.state.files
347
- .map(file => ({
348
- value: file.name,
349
- label: !this.props.schema.withFolder && folders.length === 1 ? `${file.name.substring(folders[0].length)}` : `${file.name}${this.props.schema.noSize ? '' : `(${file.size})`}`,
350
- extension: file.name.toLowerCase().split('.').pop(),
351
- }));
352
-
353
- if (!this.props.schema.noNone) {
354
- selectOptions.unshift({ label: I18n.t('ra_none'), value: '' });
355
- }
356
-
357
- /** @type {Item | undefined } */
358
- const item = selectOptions.find(_item => _item.value === this.state.value);
359
-
360
- let buttons = 0;
361
-
362
- if (this.props.schema.upload) {
363
- buttons++;
364
- }
365
- if (this.props.schema.refresh) {
366
- buttons++;
367
- }
368
- const play = this.state.value && (this.state.value.endsWith('.mp3') || this.state.value.endsWith('.ogg') || this.state.value.endsWith('.wav'));
369
- // show play button
370
- if (play) {
371
- buttons++;
372
- }
373
-
374
- const element = <div className={this.props.classes.fullWidth}>
375
- <FormControl variant="standard" style={{ width: `calc(100% - ${buttons * 42}px)` }}>
376
- {this.props.schema.label ? <InputLabel>{this.getText(this.props.schema.label)}</InputLabel> : null}
377
- <Select
378
- variant="standard"
379
- error={!!error}
380
- disabled={!!disabled}
381
- value={this.state.value || '_'}
382
- renderValue={() => <>
383
- {this.getIcon(item)}
384
- <span>{item?.label || ''}</span>
385
- </>}
386
- onChange={e => {
387
- this.setState({ value: e.target.value === '_' ? '' : e.target.value }, () =>
388
- this.onChange(this.props.attr, this.state.value));
389
- }}
390
- >
391
- {selectOptions.map(it => <MenuItem key={it.value} value={it.value}>
392
- <ListItemIcon>{this.getIcon(it)}</ListItemIcon>
393
- <ListItemText>{it.label}</ListItemText>
394
- {this.props.schema.delete && item.value ?
395
- <IconButton
396
- className={this.props.classes.deleteButton}
397
- size="small"
398
- onClick={() => this.setState({ deleteFile: item.value })}
399
- >
400
- <IconDelete />
401
- </IconButton> : null}
402
- </MenuItem>)}
403
- </Select>
404
- {this.props.schema.help ? <FormHelperText>{this.renderHelp(this.props.schema.help, this.props.schema.helpLink, this.props.schema.noTranslation)}</FormHelperText> : null}
405
- </FormControl>
406
- { this.props.schema.refresh && <IconButton onClick={() => this.updateFiles()}><IconRefresh /></IconButton> }
407
- { this.props.schema.upload && <IconButton onClick={() => this.dropzoneRef.current?.open()}><IconUpload /></IconButton> }
408
- { play && <IconButton style={{ color: '#00FF00' }} onClick={() => this.play()}><IconPlay /></IconButton> }
409
- </div>;
410
-
411
- if (!this.props.schema.upload) {
412
- return <>
413
- {element}
414
- {this.renderDeleteDialog()}
415
- </>;
416
- }
417
- let accept = { '*/*': [] };
418
- if (this.props.schema.fileTypes === 'image') {
419
- accept = {
420
- 'image/*': ['.png', '.jpg', '.svg', '.gif', '.apng', '.avif', '.webp'],
421
- };
422
- } else if (this.props.schema.fileTypes === 'audio') {
423
- accept = {
424
- 'audio/*': ['.mp3', '.ogg', '.wav', '.mp4'],
425
- };
426
- } else if (this.props.schema.fileTypes === 'text') {
427
- accept = {
428
- 'text/plain': ['.txt'],
429
- };
430
- }
431
- if (this.props.schema.pattern) {
432
- const last = this.props.schema.pattern.split('/').pop().toLowerCase().replace(/.*\./, '');
433
- if (last === 'png' || last === 'jpg' || last === 'svg' || last === 'gif' || last === 'apng' || last === 'avif' || last === 'webp') {
434
- accept = {
435
- 'image/*': ['.png', '.jpg', '.svg', '.gif', '.apng', '.avif', '.webp'],
436
- };
437
- } else if (last === 'mp3' || last === 'ogg' || last === 'wav') {
438
- accept = {
439
- 'audio/*': ['.mp3', '.ogg', '.wav', '.mp4'],
440
- };
441
- } else if (last === 'ics') {
442
- accept = {
443
- 'text/calendar': ['.ics'],
444
- };
445
- } else if (last === 'txt') {
446
- accept = {
447
- 'text/plain': ['.txt'],
448
- };
449
- } else if (last === 'pem') {
450
- accept = {
451
- 'text/plain': ['.pem'],
452
- };
453
- } else {
454
- accept = {
455
- '*/*': [`.${last}`],
456
- };
457
- }
458
- }
459
-
460
- return <Dropzone
461
- ref={this.dropzoneRef}
462
- multiple={false}
463
- accept={accept}
464
- noKeyboard
465
- noClick
466
- maxSize={this.props.schema.maxSize || 2 * 1024 * 1024}
467
- onDragEnter={() => {
468
- this.setState({ uploadFile: 'dragging' });
469
- }}
470
- onDragLeave={() => this.setState({ uploadFile: true })}
471
- onDrop={(acceptedFiles, errors) => {
472
- this.setState({ uploadFile: false });
473
- if (!acceptedFiles.length) {
474
- window.alert((errors && errors[0] && errors[0].errors && errors[0].errors[0] && errors[0].errors[0].message) || I18n.t('Cannot upload'));
475
- } else {
476
- this.onDrop(acceptedFiles);
477
- }
478
- }}
479
- >
480
- {({ getRootProps, getInputProps }) => <div
481
- className={Utils.clsx(
482
- this.props.classes.uploadDiv,
483
- this.state.uploadFile === 'dragging' && this.props.classes.uploadDivDragging,
484
- disabled && this.props.classes.disabledOpacity,
485
- )}
486
- {...getRootProps()}
487
- >
488
- <input {...getInputProps()} />
489
- {this.state.uploadFile === 'dragging' ? <div className={Utils.clsx(this.props.classes.uploadCenterDiv, this.state.uploadError && this.props.classes.error)}>
490
- <div className={this.props.classes.uploadCenterTextAndIcon}>
491
- <UploadIcon className={this.props.classes.uploadCenterIcon} />
492
- <div className={this.props.classes.uploadCenterText}>
493
- {
494
- this.state.uploadFile === 'dragging' ? I18n.t('ra_Drop file here') :
495
- I18n.t('ra_Place your files here or click here to open the browse dialog')
496
- }
497
- </div>
498
- </div>
499
- </div> : null}
500
- {element}
501
- {this.renderDeleteDialog()}
502
- </div>}
503
- </Dropzone>;
504
- }
505
- }
506
-
507
- ConfigFileSelector.propTypes = {
508
- socket: PropTypes.object.isRequired,
509
- themeType: PropTypes.string,
510
- themeName: PropTypes.string,
511
- style: PropTypes.object,
512
- className: PropTypes.string,
513
- data: PropTypes.object.isRequired,
514
- schema: PropTypes.object,
515
- onError: PropTypes.func,
516
- onChange: PropTypes.func,
517
- imagePrefix: PropTypes.func,
518
- };
519
-
520
- export default withStyles(styles)(ConfigFileSelector);
@@ -1,90 +0,0 @@
1
- import React from 'react';
2
- import PropTypes from 'prop-types';
3
- import { withStyles } from '@mui/styles';
4
-
5
- import {
6
- InputLabel,
7
- MenuItem,
8
- FormHelperText,
9
- FormControl,
10
- Select,
11
- } from '@mui/material';
12
-
13
- import { TextWithIcon, I18n } from '@iobroker/adapter-react-v5';
14
-
15
- import ConfigGeneric from './ConfigGeneric';
16
-
17
- const styles = () => ({
18
- fullWidth: {
19
- width: '100%',
20
- },
21
- });
22
-
23
- class ConfigFunc extends ConfigGeneric {
24
- componentDidMount() {
25
- super.componentDidMount();
26
- const value = ConfigGeneric.getValue(this.props.data, this.props.attr);
27
-
28
- this.props.socket.getEnums('functions')
29
- .then(enums => {
30
- const selectOptions = Object.keys(enums)
31
- .map(id => ({
32
- value: this.props.schema.short ? id.replace('enum.functions.', '') : id,
33
- label: this.getText(enums[id].common.name),
34
- obj: enums[id],
35
- }));
36
-
37
- if (this.props.schema.allowDeactivate !== false) {
38
- selectOptions.unshift({ label: I18n.t(ConfigGeneric.NONE_LABEL), value: ConfigGeneric.NONE_VALUE });
39
- }
40
-
41
- this.setState({ value, selectOptions });
42
- });
43
- }
44
-
45
- renderItem(error, disabled /* , defaultValue */) {
46
- if (!this.state.selectOptions) {
47
- return null;
48
- }
49
-
50
- const item = this.state.selectOptions.find(it => it.value === this.state.value);
51
-
52
- return <FormControl
53
- variant="standard"
54
- className={this.props.classes.fullWidth}
55
- >
56
- {this.props.schema.label ? <InputLabel>{this.getText(this.props.schema.label)}</InputLabel> : null}
57
- <Select
58
- variant="standard"
59
- error={!!error}
60
- disabled={!!disabled}
61
- value={this.state.value || '_'}
62
- renderValue={() => (item ? (item.obj ? <TextWithIcon value={item.obj} themeType={this.props.themeType} lang={I18n.getLanguage()} /> : item.label) : '')}
63
- onChange={e => {
64
- this.setState({ value: e.target.value === '_' ? '' : e.target.value }, () =>
65
- this.onChange(this.props.attr, this.state.value));
66
- }}
67
- >
68
- {this.state.selectOptions.map(it =>
69
- <MenuItem key={it.value} value={it.value} style={it.value === ConfigGeneric.DIFFERENT_VALUE ? { opacity: 0.5 } : {}}>
70
- {it.obj ? <TextWithIcon value={it.obj} themeType={this.props.themeType} lang={I18n.getLanguage()} /> : it.label}
71
- </MenuItem>)}
72
- </Select>
73
- {this.props.schema.help ? <FormHelperText>{this.renderHelp(this.props.schema.help, this.props.schema.helpLink, this.props.schema.noTranslation)}</FormHelperText> : null}
74
- </FormControl>;
75
- }
76
- }
77
-
78
- ConfigFunc.propTypes = {
79
- socket: PropTypes.object.isRequired,
80
- themeType: PropTypes.string,
81
- themeName: PropTypes.string,
82
- style: PropTypes.object,
83
- className: PropTypes.string,
84
- data: PropTypes.object.isRequired,
85
- schema: PropTypes.object,
86
- onError: PropTypes.func,
87
- onChange: PropTypes.func,
88
- };
89
-
90
- export default withStyles(styles)(ConfigFunc);