@iobroker/json-config 6.17.13 → 6.17.15

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 (87) hide show
  1. package/build/JsonConfig.d.ts +3 -4
  2. package/build/JsonConfig.js +2 -2
  3. package/build/JsonConfig.js.map +1 -1
  4. package/build/JsonConfigComponent/ChipInput.js +1 -0
  5. package/build/JsonConfigComponent/ChipInput.js.map +1 -1
  6. package/build/JsonConfigComponent/ConfigAccordion.d.ts +1 -1
  7. package/build/JsonConfigComponent/ConfigAccordion.js.map +1 -1
  8. package/build/JsonConfigComponent/ConfigCertificateSelect.js +1 -0
  9. package/build/JsonConfigComponent/ConfigCertificateSelect.js.map +1 -1
  10. package/build/JsonConfigComponent/ConfigCertificates.js +1 -0
  11. package/build/JsonConfigComponent/ConfigCertificates.js.map +1 -1
  12. package/build/JsonConfigComponent/ConfigCheckLicense.d.ts +12 -1
  13. package/build/JsonConfigComponent/ConfigCheckLicense.js +13 -50
  14. package/build/JsonConfigComponent/ConfigCheckLicense.js.map +1 -1
  15. package/build/JsonConfigComponent/ConfigDeviceManager.js +11 -2
  16. package/build/JsonConfigComponent/ConfigDeviceManager.js.map +1 -1
  17. package/build/JsonConfigComponent/ConfigPanel.js.map +1 -1
  18. package/build/JsonConfigComponent/ConfigTable.js.map +1 -1
  19. package/build/JsonConfigComponent/wrapper/Components/CustomModal.d.ts +1 -1
  20. package/build/JsonConfigComponent/wrapper/Components/CustomModal.js +5 -1
  21. package/build/JsonConfigComponent/wrapper/Components/CustomModal.js.map +1 -1
  22. package/build/JsonConfigComponent/wrapper/Components/Editor.d.ts +7 -13
  23. package/build/JsonConfigComponent/wrapper/Components/Editor.js +9 -23
  24. package/build/JsonConfigComponent/wrapper/Components/Editor.js.map +1 -1
  25. package/build/index.d.ts +1 -0
  26. package/build/index.js.map +1 -1
  27. package/package.json +2 -4
  28. package/src/JsonConfig.tsx +0 -710
  29. package/src/JsonConfigComponent/ChipInput.tsx +0 -752
  30. package/src/JsonConfigComponent/ConfigAccordion.tsx +0 -278
  31. package/src/JsonConfigComponent/ConfigAlive.tsx +0 -74
  32. package/src/JsonConfigComponent/ConfigAutocomplete.tsx +0 -108
  33. package/src/JsonConfigComponent/ConfigAutocompleteSendTo.tsx +0 -183
  34. package/src/JsonConfigComponent/ConfigCRON.jsx +0 -101
  35. package/src/JsonConfigComponent/ConfigCertCollection.tsx +0 -102
  36. package/src/JsonConfigComponent/ConfigCertificateSelect.tsx +0 -92
  37. package/src/JsonConfigComponent/ConfigCertificates.tsx +0 -202
  38. package/src/JsonConfigComponent/ConfigCheckLicense.jsx +0 -662
  39. package/src/JsonConfigComponent/ConfigCheckbox.tsx +0 -67
  40. package/src/JsonConfigComponent/ConfigChip.jsx +0 -81
  41. package/src/JsonConfigComponent/ConfigColor.tsx +0 -86
  42. package/src/JsonConfigComponent/ConfigCoordinates.tsx +0 -234
  43. package/src/JsonConfigComponent/ConfigCustom.tsx +0 -246
  44. package/src/JsonConfigComponent/ConfigDatePicker.tsx +0 -48
  45. package/src/JsonConfigComponent/ConfigDeviceManager.tsx +0 -33
  46. package/src/JsonConfigComponent/ConfigFile.jsx +0 -181
  47. package/src/JsonConfigComponent/ConfigFileSelector.jsx +0 -520
  48. package/src/JsonConfigComponent/ConfigFunc.jsx +0 -90
  49. package/src/JsonConfigComponent/ConfigGeneric.tsx +0 -1027
  50. package/src/JsonConfigComponent/ConfigIP.jsx +0 -96
  51. package/src/JsonConfigComponent/ConfigImageSendTo.jsx +0 -79
  52. package/src/JsonConfigComponent/ConfigImageUpload.jsx +0 -114
  53. package/src/JsonConfigComponent/ConfigInstanceSelect.jsx +0 -172
  54. package/src/JsonConfigComponent/ConfigInterface.jsx +0 -112
  55. package/src/JsonConfigComponent/ConfigJsonEditor.jsx +0 -103
  56. package/src/JsonConfigComponent/ConfigLanguage.tsx +0 -153
  57. package/src/JsonConfigComponent/ConfigLicense.jsx +0 -148
  58. package/src/JsonConfigComponent/ConfigNumber.tsx +0 -207
  59. package/src/JsonConfigComponent/ConfigObjectId.jsx +0 -113
  60. package/src/JsonConfigComponent/ConfigPanel.tsx +0 -360
  61. package/src/JsonConfigComponent/ConfigPassword.jsx +0 -160
  62. package/src/JsonConfigComponent/ConfigPattern.jsx +0 -50
  63. package/src/JsonConfigComponent/ConfigPort.tsx +0 -232
  64. package/src/JsonConfigComponent/ConfigRoom.jsx +0 -90
  65. package/src/JsonConfigComponent/ConfigSelect.jsx +0 -124
  66. package/src/JsonConfigComponent/ConfigSelectSendTo.tsx +0 -251
  67. package/src/JsonConfigComponent/ConfigSendto.tsx +0 -340
  68. package/src/JsonConfigComponent/ConfigSetState.jsx +0 -116
  69. package/src/JsonConfigComponent/ConfigSlider.jsx +0 -97
  70. package/src/JsonConfigComponent/ConfigStaticDivider.jsx +0 -51
  71. package/src/JsonConfigComponent/ConfigStaticHeader.jsx +0 -63
  72. package/src/JsonConfigComponent/ConfigStaticImage.jsx +0 -48
  73. package/src/JsonConfigComponent/ConfigStaticText.jsx +0 -72
  74. package/src/JsonConfigComponent/ConfigTable.tsx +0 -1040
  75. package/src/JsonConfigComponent/ConfigTabs.tsx +0 -150
  76. package/src/JsonConfigComponent/ConfigText.tsx +0 -188
  77. package/src/JsonConfigComponent/ConfigTextSendTo.tsx +0 -102
  78. package/src/JsonConfigComponent/ConfigTimePicker.tsx +0 -63
  79. package/src/JsonConfigComponent/ConfigTopic.jsx +0 -78
  80. package/src/JsonConfigComponent/ConfigUUID.tsx +0 -55
  81. package/src/JsonConfigComponent/ConfigUser.jsx +0 -104
  82. package/src/JsonConfigComponent/index.tsx +0 -435
  83. package/src/JsonConfigComponent/wrapper/Components/CustomModal.jsx +0 -145
  84. package/src/JsonConfigComponent/wrapper/Components/Editor.jsx +0 -65
  85. package/src/Utils.jsx +0 -1683
  86. package/src/index.tsx +0 -14
  87. package/src/types.d.ts +0 -372
@@ -1,1027 +0,0 @@
1
- import React, { Component } from 'react';
2
-
3
- import { Grid, Button } from '@mui/material';
4
-
5
- import {
6
- Info as IconInfo,
7
- Warning as IconWarning,
8
- Error as IconError,
9
- Key as IconAuth,
10
- Send as IconSend,
11
- Public as IconWeb,
12
- Search as IconSearch,
13
- MenuBook as IconMenuBook,
14
- Help as IconHelp,
15
- UploadFile as IconUploadFile,
16
- } from '@mui/icons-material';
17
-
18
- import {
19
- Confirm as ConfirmDialog, Icon,
20
- Utils, type AdminConnection, I18n,
21
- } from '@iobroker/adapter-react-v5';
22
- import type { ThemeType, ThemeName } from '@iobroker/adapter-react-v5/types';
23
- import type { ConfigItemAny, ConfigItemConfirmData } from '#JC/types';
24
-
25
- // because this class is used in adapter-react-v5, do not include here any foreign files like from '../../helpers/utils.ts'
26
- export function isObject(it: any): it is Record<string, any> {
27
- // This is necessary because:
28
- // typeof null === 'object'
29
- // typeof [] === 'object'
30
- // [] instanceof Object === true
31
- return Object.prototype.toString.call(it) === '[object Object]'; // this code is 25% faster than below one
32
- // return it && typeof it === 'object' && !(it instanceof Array);
33
- }
34
-
35
- export interface ConfigGenericProps {
36
- adapterName: string;
37
- alive: boolean;
38
- arrayIndex?: number;
39
- attr?: string;
40
- changeLanguage?: () => void;
41
- changed: boolean;
42
- className?: string;
43
- classes: Record<string, any>;
44
- commandRunning?: boolean;
45
- common: Record<string, any>;
46
- custom?: boolean;
47
- customObj?: Record<string, any>;
48
- customs?: Record<string, React.Component>;
49
- data: Record<string, any>;
50
- dateFormat: string;
51
- disabled?: boolean;
52
- forceUpdate: (attrs: string[], data: Record<string, any>) => void;
53
- // filled only by table and represents the obj.native or obj.common.custom['adapter.X'] object
54
- globalData?: Record<string, any>;
55
- imagePrefix?: string;
56
- // filled only by table
57
- index?: number;
58
- instance: number;
59
- instanceObj?: ioBroker.InstanceObject;
60
- isFloatComma: boolean;
61
- isParentTab?: boolean;
62
- /** If true, this field edits multiple data points at once and thus contains an array, should not be saved if not changed */
63
- multiEdit?: boolean;
64
- onChange: (attrOrData: string | Record<string, any>, val?: any, cb?: () => void, saveConfig?: boolean) => void;
65
- onCommandRunning: (running: boolean) => void;
66
- onError: (attr: string, error?: string) => void;
67
- originalData: Record<string, any>;
68
- registerOnForceUpdate?: (attr: string, onUpdate?: (data: Record<string, any>) => void) => void;
69
- /** Provided props by the specific component */
70
- schema: ConfigItemAny;
71
- socket: AdminConnection;
72
- systemConfig?: ioBroker.SystemConfigCommon;
73
- /** This item is in the table. Maybe some layouts must be changed */
74
- table?: boolean;
75
- themeName: ThemeName;
76
- themeType: ThemeType;
77
- }
78
-
79
- export interface ConfigGenericState {
80
- confirmDialog: boolean;
81
- confirmNewValue: any;
82
- confirmAttr: any;
83
- confirmData: ConfigItemConfirmData | null;
84
- value?: any;
85
- confirmDepAttr?: any;
86
- confirmDepNewValue?: any;
87
- }
88
-
89
- export default class ConfigGeneric<Props extends ConfigGenericProps = ConfigGenericProps, State extends ConfigGenericState = ConfigGenericState> extends Component<Props, State> {
90
- static DIFFERENT_VALUE = '__different__';
91
-
92
- static DIFFERENT_LABEL = 'ra___different__';
93
-
94
- static NONE_VALUE = '';
95
-
96
- static NONE_LABEL = 'ra_none';
97
-
98
- private readonly defaultValue: any;
99
-
100
- private isError: any;
101
-
102
- private readonly lang: ioBroker.Languages;
103
-
104
- private defaultSendToDone?: boolean;
105
-
106
- private sendToTimeout?: any;
107
-
108
- private noPlaceRequired: any;
109
-
110
- constructor(props: Props) {
111
- super(props);
112
-
113
- // @ts-expect-error of course, as we just
114
- this.state = {
115
- confirmDialog: false,
116
- confirmNewValue: null,
117
- confirmAttr: null,
118
- confirmData: null,
119
- } satisfies ConfigGenericState;
120
-
121
- this.isError = {};
122
-
123
- if (props.schema) {
124
- if (props.custom) {
125
- this.defaultValue = props.schema.defaultFunc
126
- ? this.executeCustom(
127
- props.schema.defaultFunc,
128
- props.data,
129
- props.customObj,
130
- props.instanceObj,
131
- props.arrayIndex,
132
- props.globalData,
133
- )
134
- : props.schema.default;
135
- } else {
136
- this.defaultValue = props.schema.defaultFunc
137
- ? this.execute(
138
- props.schema.defaultFunc,
139
- props.schema.default,
140
- props.data,
141
- props.arrayIndex,
142
- props.globalData,
143
- )
144
- : props.schema.default;
145
- }
146
- }
147
-
148
- this.lang = I18n.getLanguage();
149
- }
150
-
151
- componentDidMount() {
152
- this.props.registerOnForceUpdate && this.props.registerOnForceUpdate(this.props.attr, this.onUpdate);
153
- const LIKE_SELECT = ['select', 'autocomplete', 'autocompleteSendTo'];
154
- // init default value
155
- if (this.defaultValue !== undefined) {
156
- const value = ConfigGeneric.getValue(this.props.data, this.props.attr);
157
- if (
158
- value === undefined ||
159
- (LIKE_SELECT.includes(this.props.schema.type) && (value === '' || value === null))
160
- ) {
161
- setTimeout(() => {
162
- if (this.props.custom) {
163
- this.props.onChange(this.props.attr, this.defaultValue, () =>
164
- setTimeout(() => this.props.forceUpdate([this.props.attr], this.props.data), 100));
165
- } else {
166
- ConfigGeneric.setValue(this.props.data, this.props.attr, this.defaultValue);
167
- this.props.onChange(this.props.data, undefined, () =>
168
- this.props.forceUpdate([this.props.attr], this.props.data));
169
- }
170
- }, 100);
171
- }
172
- } else if (this.props.schema.defaultSendTo) {
173
- this.sendTo();
174
- }
175
- }
176
-
177
- sendTo() {
178
- if (this.props.alive) {
179
- this.defaultSendToDone = true;
180
- let data: any = this.props.schema.data;
181
- if (data === undefined && this.props.schema.jsonData) {
182
- const dataStr = this.getPattern(this.props.schema.jsonData);
183
- try {
184
- data = JSON.parse(dataStr);
185
- } catch (e) {
186
- console.error(`Cannot parse json data: ${dataStr}`);
187
- }
188
- } else {
189
- data = {
190
- attr: this.props.attr,
191
- value: ConfigGeneric.getValue(this.props.data, this.props.attr),
192
- };
193
- }
194
-
195
- if (data === undefined) {
196
- data = null;
197
- }
198
-
199
- this.props.socket
200
- .sendTo(`${this.props.adapterName}.${this.props.instance}`, this.props.schema.defaultSendTo, data)
201
- .then((value: any) => {
202
- if (value !== null && value !== undefined) {
203
- if (this.props.custom) {
204
- this.props.onChange(this.props.attr, value, () =>
205
- this.props.forceUpdate([this.props.attr], this.props.data));
206
- } else {
207
- ConfigGeneric.setValue(this.props.data, this.props.attr, value);
208
- this.props.onChange(this.props.data, undefined, () =>
209
- this.props.forceUpdate([this.props.attr], this.props.data));
210
- }
211
- }
212
- });
213
- } else {
214
- this.defaultSendToDone = false;
215
- // show error, that instance did not start
216
- this.onError(this.props.attr, I18n.t('ra_Instance %s is not alive', this.props.instance.toString()));
217
- }
218
- }
219
-
220
- componentWillUnmount() {
221
- this.props.registerOnForceUpdate && this.props.registerOnForceUpdate(this.props.attr);
222
- if (this.sendToTimeout) {
223
- clearTimeout(this.sendToTimeout);
224
- this.sendToTimeout = null;
225
- }
226
- }
227
-
228
- onUpdate = (data: Record<string, any>) => {
229
- const value = ConfigGeneric.getValue(data || this.props.data, this.props.attr) || '';
230
- if (this.state.value !== value) {
231
- this.setState({ value });
232
- } else {
233
- this.forceUpdate();
234
- }
235
- };
236
-
237
- /**
238
- * Extract attribute out of data
239
- *
240
- * @param data
241
- * @param attr
242
- */
243
- static getValue(data: Record<string, any>, attr: string | string[]): any {
244
- if (typeof attr === 'string') {
245
- return ConfigGeneric.getValue(data, attr.split('.'));
246
- }
247
- if (attr.length === 1) {
248
- return data[attr[0]];
249
- }
250
- const part = attr.shift();
251
-
252
- if (typeof part === 'string' && typeof data[part] === 'object') {
253
- return ConfigGeneric.getValue(data[part], attr);
254
- }
255
- return null;
256
- }
257
-
258
- static setValue(data: Record<string, any>, attr: string | string[], value: any) {
259
- if (typeof attr === 'string') {
260
- ConfigGeneric.setValue(data, attr.split('.'), value);
261
- return;
262
- }
263
- if (attr.length === 1) {
264
- if (value === null) {
265
- delete data[attr[0]];
266
- } else {
267
- data[attr[0]] = value;
268
- }
269
- } else {
270
- const part = attr.shift();
271
-
272
- if (typeof part !== 'string') {
273
- return;
274
- }
275
-
276
- if (!data[part] || typeof data[part] === 'object') {
277
- data[part] = data[part] || {};
278
- }
279
- ConfigGeneric.setValue(data[part], attr, value);
280
- }
281
- }
282
-
283
- getText(text: ioBroker.StringOrTranslated, noTranslation?: boolean): string {
284
- if (!text) {
285
- return '';
286
- }
287
-
288
- if (typeof text === 'string') {
289
- const strText = noTranslation ? text : I18n.t(text);
290
- if (strText.includes('${')) {
291
- return this.getPattern(strText);
292
- }
293
- return strText;
294
- }
295
-
296
- if (isObject(text)) {
297
- // todo
298
- if ((text as any).func) {
299
- // calculate pattern
300
- if (typeof (text as any).func === 'object') {
301
- return this.getPattern((text as any).func[this.lang] || (text as any).func.en || '');
302
- }
303
- return this.getPattern((text as any).func);
304
- }
305
-
306
- return text[this.lang] || text.en || '';
307
- }
308
-
309
- return (text as any).toString();
310
- }
311
-
312
- renderConfirmDialog() {
313
- if (!this.state.confirmDialog) {
314
- return null;
315
- }
316
- const confirm = this.state.confirmData || this.props.schema.confirm;
317
- let icon: null | React.JSX.Element = null;
318
- if (confirm.type === 'warning') {
319
- icon = <IconWarning />;
320
- } else if (confirm.type === 'error') {
321
- icon = <IconError />;
322
- } else if (confirm.type === 'info') {
323
- icon = <IconInfo />;
324
- }
325
-
326
- return <ConfirmDialog
327
- title={this.getText(confirm.title) || I18n.t('ra_Please confirm')}
328
- text={this.getText(confirm.text)}
329
- ok={this.getText(confirm.ok) || I18n.t('ra_Ok')}
330
- cancel={this.getText(confirm.cancel) || I18n.t('ra_Cancel')}
331
- icon={icon || undefined}
332
- onClose={isOk =>
333
- this.setState({ confirmDialog: false }, () => {
334
- if (isOk) {
335
- const data = JSON.parse(JSON.stringify(this.props.data));
336
- if (this.state.confirmDepAttr) {
337
- ConfigGeneric.setValue(data, this.state.confirmDepAttr, this.state.confirmDepNewValue);
338
- }
339
-
340
- ConfigGeneric.setValue(data, this.state.confirmAttr, this.state.confirmNewValue);
341
- this.setState(
342
- {
343
- confirmDialog: false,
344
- confirmDepAttr: null,
345
- confirmDepNewValue: null,
346
- confirmNewValue: null,
347
- confirmAttr: null,
348
- confirmData: null,
349
- },
350
- () => this.props.onChange(data),
351
- );
352
- } else {
353
- this.setState({
354
- confirmDialog: false,
355
- confirmDepAttr: null,
356
- confirmDepNewValue: null,
357
- confirmNewValue: null,
358
- confirmAttr: null,
359
- confirmData: null,
360
- });
361
- }
362
- })}
363
- />;
364
- }
365
-
366
- // eslint-disable-next-line react/no-unused-class-component-methods
367
- getIcon(iconSettings?: string | null): React.JSX.Element | null {
368
- iconSettings = iconSettings || this.props.schema.icon;
369
- let icon = null;
370
- if (iconSettings === 'auth') {
371
- icon = <IconAuth />;
372
- } else if (iconSettings === 'send') {
373
- icon = <IconSend />;
374
- } else if (iconSettings === 'web') {
375
- icon = <IconWeb />;
376
- } else if (iconSettings === 'warning') {
377
- icon = <IconWarning />;
378
- } else if (iconSettings === 'error') {
379
- icon = <IconError />;
380
- } else if (iconSettings === 'info') {
381
- icon = <IconInfo />;
382
- } else if (iconSettings === 'search') {
383
- icon = <IconSearch />;
384
- } else if (iconSettings === 'book') {
385
- icon = <IconMenuBook />;
386
- } else if (iconSettings === 'help') {
387
- icon = <IconHelp />;
388
- } else if (iconSettings === 'upload') {
389
- icon = <IconUploadFile />;
390
- } else if (iconSettings) {
391
- if (iconSettings.endsWith('.png') || iconSettings.endsWith('.svg') || iconSettings.endsWith('.jpg')) {
392
- // this path is relative to ./adapter/NAME
393
- if (!iconSettings.startsWith('http://') && !iconSettings.startsWith('https://')) {
394
- iconSettings = `./adapter/${this.props.adapterName}/${iconSettings}`;
395
- }
396
- }
397
-
398
- icon = <Icon src={iconSettings} style={{ width: 22, height: 22 }} />;
399
- }
400
-
401
- return icon;
402
- }
403
-
404
- /**
405
- * Trigger onChange, to activate save button on change
406
- *
407
- * @param attr the changed attribute
408
- * @param newValue new value of the attribute
409
- */
410
- onChangeAsync(attr: string, newValue: unknown): Promise<void> {
411
- return new Promise(resolve => {
412
- this.onChange(attr, newValue, resolve);
413
- });
414
- }
415
-
416
- /**
417
- * Trigger onChange, to activate save button on change
418
- *
419
- * @param attr the changed attribute
420
- * @param newValue new value of the attribute
421
- * @param cb optional callback function, else returns a Promise
422
- */
423
- // eslint-disable-next-line react/no-unused-class-component-methods
424
- onChange(attr: string, newValue: unknown, cb?: () => void): Promise<void> {
425
- // Do not use here deep copy, as it is not JsonConfig
426
- const data = JSON.parse(JSON.stringify(this.props.data));
427
- ConfigGeneric.setValue(data, attr, newValue);
428
-
429
- if (
430
- this.props.schema.confirm &&
431
- this.execute(this.props.schema.confirm.condition, false, data, this.props.arrayIndex, this.props.globalData)
432
- ) {
433
- return new Promise<void>(resolve => {
434
- this.setState(
435
- {
436
- confirmDialog: true,
437
- confirmNewValue: newValue,
438
- confirmAttr: attr,
439
- confirmData: null,
440
- },
441
- () => {
442
- if (typeof cb === 'function') {
443
- cb();
444
- } else {
445
- resolve();
446
- }
447
- },
448
- );
449
- });
450
- }
451
- // find any inputs with confirmation
452
- if (this.props.schema.confirmDependsOn) {
453
- for (let z = 0; z < this.props.schema.confirmDependsOn.length; z++) {
454
- const dep = this.props.schema.confirmDependsOn[z];
455
- if (dep.confirm) {
456
- const val = ConfigGeneric.getValue(data, dep.attr);
457
-
458
- if (
459
- this.execute(
460
- dep.confirm.condition,
461
- false,
462
- data,
463
- this.props.arrayIndex,
464
- this.props.globalData,
465
- )
466
- ) {
467
- return new Promise<void>(resolve => {
468
- this.setState(
469
- {
470
- confirmDialog: true,
471
- confirmNewValue: newValue,
472
- confirmAttr: attr,
473
- confirmDepNewValue: val,
474
- confirmDepAttr: dep.attr,
475
- confirmData: dep.confirm,
476
- },
477
- () => {
478
- if (typeof cb === 'function') {
479
- cb();
480
- } else {
481
- resolve();
482
- }
483
- },
484
- );
485
- });
486
- }
487
- }
488
- }
489
- }
490
-
491
- const changed: string[] = [];
492
- if (this.props.schema.onChangeDependsOn) {
493
- for (let z = 0; z < this.props.schema.onChangeDependsOn.length; z++) {
494
- const dep = this.props.schema.onChangeDependsOn[z];
495
- if (dep.onChange) {
496
- const val = ConfigGeneric.getValue(data, dep.attr);
497
-
498
- let _newValue;
499
- if (this.props.custom) {
500
- _newValue = this.executeCustom(
501
- dep.onChange.calculateFunc,
502
- data,
503
- this.props.customObj,
504
- this.props.instanceObj,
505
- this.props.arrayIndex,
506
- this.props.globalData,
507
- );
508
- } else {
509
- _newValue = this.execute(
510
- dep.onChange.calculateFunc,
511
- val,
512
- data,
513
- this.props.arrayIndex,
514
- this.props.globalData,
515
- );
516
- }
517
-
518
- if (_newValue !== val) {
519
- ConfigGeneric.setValue(data, dep.attr, _newValue);
520
- changed.push(dep.attr);
521
- }
522
- }
523
- }
524
- }
525
-
526
- if (this.props.schema.hiddenDependsOn) {
527
- for (let z = 0; z < this.props.schema.hiddenDependsOn.length; z++) {
528
- const dep = this.props.schema.hiddenDependsOn[z];
529
- dep.hidden && changed.push(dep.attr);
530
- }
531
- }
532
-
533
- if (this.props.schema.labelDependsOn) {
534
- for (let z = 0; z < this.props.schema.labelDependsOn.length; z++) {
535
- const dep = this.props.schema.labelDependsOn[z];
536
- dep.hidden && changed.push(dep.attr);
537
- }
538
- }
539
-
540
- if (this.props.schema.helpDependsOn) {
541
- for (let z = 0; z < this.props.schema.helpDependsOn.length; z++) {
542
- const dep = this.props.schema.helpDependsOn[z];
543
- dep.hidden && changed.push(dep.attr);
544
- }
545
- }
546
-
547
- if (this.props.schema.onChange && !this.props.schema.onChange.ignoreOwnChanges) {
548
- const val = ConfigGeneric.getValue(data, this.props.attr);
549
-
550
- const newValue_ = this.props.custom
551
- ? this.executeCustom(
552
- this.props.schema.onChange.calculateFunc,
553
- data,
554
- this.props.customObj,
555
- this.props.instanceObj,
556
- this.props.arrayIndex,
557
- this.props.globalData,
558
- )
559
- : this.execute(
560
- this.props.schema.onChange.calculateFunc,
561
- val,
562
- data,
563
- this.props.arrayIndex,
564
- this.props.globalData,
565
- );
566
- if (newValue_ !== val) {
567
- ConfigGeneric.setValue(data, this.props.attr, newValue_);
568
- }
569
- }
570
-
571
- if (this.props.custom) {
572
- this.props.onChange(attr, newValue, () => cb && cb());
573
-
574
- changed &&
575
- changed.length &&
576
- changed.forEach((_attr, i) =>
577
- setTimeout(() => this.props.onChange(_attr, ConfigGeneric.getValue(data, _attr)), i * 50));
578
- } else {
579
- this.props.onChange(data, undefined, () => {
580
- changed.length && this.props.forceUpdate(changed, data);
581
- cb && cb();
582
- });
583
- }
584
-
585
- return Promise.resolve();
586
- }
587
-
588
- execute(
589
- func: string | boolean | Record<string, string>,
590
- defaultValue: string | number | boolean,
591
- data: Record<string, any>,
592
- arrayIndex: number,
593
- globalData: Record<string, any>,
594
- ): string | number | boolean {
595
- let fun: string;
596
-
597
- if (isObject(func)) {
598
- fun = func.func;
599
- } else if (typeof func === 'string') {
600
- fun = func;
601
- } else {
602
- return func as boolean;
603
- }
604
-
605
- if (!fun) {
606
- return defaultValue;
607
- }
608
- try {
609
- // eslint-disable-next-line no-new-func
610
- const f = new Function(
611
- 'data',
612
- 'originalData',
613
- '_system',
614
- '_alive',
615
- '_common',
616
- '_socket',
617
- '_instance',
618
- 'arrayIndex',
619
- 'globalData',
620
- '_changed',
621
- fun.includes('return') ? fun : `return ${fun}`,
622
- );
623
- return f(
624
- data || this.props.data,
625
- this.props.originalData,
626
- this.props.systemConfig,
627
- this.props.alive,
628
- this.props.common,
629
- this.props.socket,
630
- this.props.instance,
631
- arrayIndex,
632
- globalData,
633
- this.props.changed,
634
- );
635
- } catch (e) {
636
- console.error(`Cannot execute ${func}: ${e}`);
637
- return defaultValue;
638
- }
639
- }
640
-
641
- executeCustom(
642
- func: string | boolean | Record<string, string>,
643
- data: Record<string, any>,
644
- customObj: Record<string, any>,
645
- instanceObj: ioBroker.InstanceObject,
646
- arrayIndex: number,
647
- globalData: Record<string, any>,
648
- ): string | boolean | number | null {
649
- let fun: string;
650
-
651
- if (isObject(func)) {
652
- fun = func.func;
653
- } else if (typeof func === 'string') {
654
- fun = func;
655
- } else {
656
- return func as boolean;
657
- }
658
-
659
- if (!fun) {
660
- return null;
661
- }
662
- try {
663
- // eslint-disable-next-line no-new-func
664
- const f = new Function(
665
- 'data',
666
- 'originalData',
667
- '_system',
668
- 'instanceObj',
669
- 'customObj',
670
- '_socket',
671
- 'arrayIndex',
672
- 'globalData',
673
- '_changed',
674
- fun.includes('return') ? fun : `return ${fun}`,
675
- );
676
- return f(
677
- data || this.props.data,
678
- this.props.originalData,
679
- this.props.systemConfig,
680
- instanceObj,
681
- customObj,
682
- this.props.socket,
683
- arrayIndex,
684
- globalData,
685
- this.props.changed,
686
- );
687
- } catch (e) {
688
- console.error(`Cannot execute ${fun}: ${e}`);
689
- return null;
690
- }
691
- }
692
-
693
- calculate(schema: Record<string, any>): {
694
- error: boolean;
695
- disabled: boolean;
696
- hidden: boolean;
697
- defaultValue: null | string | number | boolean;
698
- } {
699
- let error: boolean;
700
- let disabled: boolean;
701
- let hidden: boolean;
702
- let defaultValue: null | string | number | boolean;
703
-
704
- if (this.props.custom) {
705
- error = schema.validator
706
- ? !this.executeCustom(
707
- schema.validator,
708
- this.props.data,
709
- this.props.customObj,
710
- this.props.instanceObj,
711
- this.props.arrayIndex,
712
- this.props.globalData,
713
- ) as boolean
714
- : false;
715
- disabled = schema.disabled
716
- ? this.executeCustom(
717
- schema.disabled,
718
- this.props.data,
719
- this.props.customObj,
720
- this.props.instanceObj,
721
- this.props.arrayIndex,
722
- this.props.globalData,
723
- ) as boolean
724
- : false;
725
- hidden = schema.hidden
726
- ? this.executeCustom(
727
- schema.hidden,
728
- this.props.data,
729
- this.props.customObj,
730
- this.props.instanceObj,
731
- this.props.arrayIndex,
732
- this.props.globalData,
733
- ) as boolean
734
- : false;
735
- defaultValue = schema.defaultFunc
736
- ? this.executeCustom(
737
- schema.defaultFunc,
738
- this.props.data,
739
- this.props.customObj,
740
- this.props.instanceObj,
741
- this.props.arrayIndex,
742
- this.props.globalData,
743
- )
744
- : schema.default;
745
- } else {
746
- error = schema.validator
747
- ? !this.execute(schema.validator, false, this.props.data, this.props.arrayIndex, this.props.globalData) as boolean
748
- : false;
749
- disabled = schema.disabled
750
- ? this.execute(schema.disabled, false, this.props.data, this.props.arrayIndex, this.props.globalData) as boolean
751
- : false;
752
- hidden = schema.hidden
753
- ? this.execute(schema.hidden, false, this.props.data, this.props.arrayIndex, this.props.globalData) as boolean
754
- : false;
755
- defaultValue = schema.defaultFunc
756
- ? this.execute(
757
- schema.defaultFunc,
758
- schema.default,
759
- this.props.data,
760
- this.props.arrayIndex,
761
- this.props.globalData,
762
- )
763
- : schema.default;
764
- }
765
-
766
- return {
767
- error, disabled, hidden, defaultValue,
768
- };
769
- }
770
-
771
- onError(attr: string, error?: string) {
772
- if (!error) {
773
- delete this.isError[attr];
774
- } else {
775
- this.isError[attr] = error;
776
- }
777
-
778
- this.props.onError && this.props.onError(attr, error);
779
- }
780
-
781
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
782
- renderItem(_error: unknown, _disabled: boolean, _defaultValue?: unknown): React.JSX.Element | string | null {
783
- return this.getText(this.props.schema.label) || this.getText(this.props.schema.text);
784
- }
785
-
786
- // eslint-disable-next-line react/no-unused-class-component-methods
787
- renderHelp(text: ioBroker.StringOrTranslated, link: string, noTranslation: boolean) {
788
- if (!link) {
789
- text = this.getText(text, noTranslation) || '';
790
- if (
791
- text &&
792
- (text.includes('<a ') || text.includes('<br') || text.includes('<b>') || text.includes('<i>'))
793
- ) {
794
- return Utils.renderTextWithA(text);
795
- }
796
- return text;
797
- }
798
- return <a
799
- href={link}
800
- target="_blank"
801
- rel="noreferrer"
802
- style={{
803
- color: this.props.themeType === 'dark' ? '#a147ff' : '#5b238f',
804
- textDecoration: 'underline',
805
- }}
806
- >
807
- {this.getText(text, noTranslation)}
808
- </a>;
809
- }
810
-
811
- getPattern(pattern: string | { func: string }, data?: Record<string, any>) {
812
- data = data || this.props.data;
813
- if (!pattern) {
814
- return '';
815
- }
816
- let patternStr: string;
817
- if (typeof pattern === 'object') {
818
- if (pattern.func) {
819
- patternStr = (pattern as { func: string }).func;
820
- } else {
821
- console.log(`Object must be stringified: ${JSON.stringify(pattern)}`);
822
- patternStr = JSON.stringify(pattern);
823
- }
824
- } else {
825
- patternStr = pattern as string;
826
- }
827
-
828
- try {
829
- if (this.props.custom) {
830
- // eslint-disable-next-line no-new-func
831
- const f = new Function(
832
- 'data',
833
- 'originalData',
834
- 'arrayIndex',
835
- 'globalData',
836
- '_system',
837
- 'instanceObj',
838
- 'customObj',
839
- '_socket',
840
- '_changed',
841
- `return \`${patternStr.replace(/`/g, '\\`')}\``,
842
- );
843
- return f(
844
- data,
845
- this.props.originalData,
846
- this.props.arrayIndex,
847
- this.props.globalData,
848
- this.props.systemConfig,
849
- this.props.instanceObj,
850
- this.props.customObj,
851
- this.props.socket,
852
- this.props.changed,
853
- );
854
- }
855
- // eslint-disable-next-line no-new-func
856
- const f = new Function(
857
- 'data',
858
- 'originalData',
859
- 'arrayIndex',
860
- 'globalData',
861
- '_system',
862
- '_alive',
863
- '_common',
864
- '_socket',
865
- '_changed',
866
- `return \`${patternStr.replace(/`/g, '\\`')}\``,
867
- );
868
- return f(
869
- data,
870
- this.props.originalData,
871
- this.props.arrayIndex,
872
- this.props.globalData,
873
- this.props.systemConfig,
874
- this.props.alive,
875
- this.props.common,
876
- this.props.socket,
877
- this.props.changed,
878
- );
879
- } catch (e) {
880
- console.error(`Cannot execute ${patternStr}: ${e}`);
881
- return patternStr;
882
- }
883
- }
884
-
885
- render(): string | React.JSX.Element | null {
886
- const schema = this.props.schema;
887
-
888
- if (!schema) {
889
- return null;
890
- }
891
-
892
- if (this.props.alive && this.defaultSendToDone === false) {
893
- this.sendToTimeout = setTimeout(() => {
894
- this.sendToTimeout = null;
895
- this.sendTo();
896
- }, 200);
897
- }
898
-
899
- const {
900
- error, disabled, hidden, defaultValue,
901
- } = this.calculate(schema);
902
-
903
- if (hidden) {
904
- // Remove all errors if element is hidden
905
- if (Object.keys(this.isError).length) {
906
- setTimeout(
907
- isError => Object.keys(isError).forEach(attr => this.props.onError(attr)),
908
- 100,
909
- JSON.parse(JSON.stringify(this.isError)),
910
- );
911
- this.isError = {};
912
- }
913
-
914
- if (schema.hideOnlyControl) {
915
- const item = <Grid
916
- item
917
- xs={schema.xs || undefined}
918
- lg={schema.lg || undefined}
919
- md={schema.md || undefined}
920
- sm={schema.sm || undefined}
921
- style={({
922
- marginBottom: 0, /* marginRight: 8, */
923
- textAlign: 'left',
924
- ...schema.style,
925
- ...(this.props.themeType === 'dark' ? schema.darkStyle : {}),
926
- })}
927
- />;
928
-
929
- if (schema.newLine) {
930
- return <>
931
- <div style={{ flexBasis: '100%', height: 0 }} />
932
- {item}
933
- </>;
934
- }
935
- return item;
936
- }
937
- return null;
938
- }
939
- // Add error
940
- if (schema.validatorNoSaveOnError) {
941
- if (error && !Object.keys(this.isError).length) {
942
- this.isError = {
943
- [this.props.attr]: schema.validatorErrorText ? I18n.t(schema.validatorErrorText) : true,
944
- };
945
- setTimeout(
946
- isError => Object.keys(isError).forEach(attr => this.props.onError(attr, isError[attr])),
947
- 100,
948
- JSON.parse(JSON.stringify(this.isError)),
949
- );
950
- } else if (!error && Object.keys(this.isError).length) {
951
- setTimeout(
952
- isError => Object.keys(isError).forEach(attr => this.props.onError(attr)),
953
- 100,
954
- JSON.parse(JSON.stringify(this.isError)),
955
- );
956
- this.isError = {};
957
- }
958
- }
959
-
960
- const renderedItem = this.renderItem(
961
- error,
962
- disabled || this.props.commandRunning || this.props.disabled,
963
- defaultValue,
964
- );
965
-
966
- if (this.noPlaceRequired) {
967
- return renderedItem;
968
- }
969
-
970
- const item = <Grid
971
- item
972
- title={this.getText(schema.tooltip)}
973
- xs={schema.xs || undefined}
974
- lg={schema.lg || undefined}
975
- md={schema.md || undefined}
976
- sm={schema.sm || undefined}
977
- style={({
978
- marginBottom: 0,
979
- // marginRight: 8,
980
- textAlign: 'left',
981
- width: schema.type === 'divider' || schema.type === 'header'
982
- ? schema.width || '100%'
983
- : undefined,
984
- ...schema.style,
985
- ...(this.props.themeType === 'dark' ? schema.darkStyle : {}),
986
- })}
987
- >
988
- {this.props.schema.defaultSendTo && this.props.schema.button ?
989
- <Grid container style={{ width: '100%' }}>
990
- <Grid item flex={1}>
991
- {renderedItem}
992
- </Grid>
993
- <Grid item>
994
- <Button
995
- variant="outlined"
996
- onClick={() => this.sendTo()}
997
- title={
998
- this.props.schema.buttonTooltip
999
- ? this.getText(
1000
- this.props.schema.buttonTooltip,
1001
- this.props.schema.buttonTooltipNoTranslation,
1002
- )
1003
- : I18n.t('ra_Request data by instance')
1004
- }
1005
- >
1006
- {this.getText(this.props.schema.button)}
1007
- </Button>
1008
- </Grid>
1009
- </Grid> : renderedItem}
1010
- </Grid>;
1011
-
1012
- if (schema.newLine) {
1013
- return <>
1014
- <div style={{ flexBasis: '100%', height: 0 }} />
1015
- {this.renderConfirmDialog()}
1016
- {item}
1017
- </>;
1018
- }
1019
- if (this.state.confirmDialog) {
1020
- return <>
1021
- {this.renderConfirmDialog()}
1022
- {item}
1023
- </>;
1024
- }
1025
- return item;
1026
- }
1027
- }