@iobroker/json-config 6.17.6 → 6.17.12

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 (173) hide show
  1. package/LICENSE +21 -21
  2. package/build/JsonConfig.d.ts +1 -1
  3. package/build/JsonConfig.js +18 -19
  4. package/build/JsonConfig.js.map +1 -1
  5. package/build/JsonConfigComponent/ChipInput.d.ts +89 -11
  6. package/build/JsonConfigComponent/ChipInput.js +48 -137
  7. package/build/JsonConfigComponent/ChipInput.js.map +1 -1
  8. package/build/JsonConfigComponent/ConfigAccordion.d.ts +7 -14
  9. package/build/JsonConfigComponent/ConfigAccordion.js +10 -21
  10. package/build/JsonConfigComponent/ConfigAccordion.js.map +1 -1
  11. package/build/JsonConfigComponent/ConfigAlive.d.ts +5 -1
  12. package/build/JsonConfigComponent/ConfigAlive.js +0 -1
  13. package/build/JsonConfigComponent/ConfigAlive.js.map +1 -1
  14. package/build/JsonConfigComponent/ConfigAutocomplete.d.ts +5 -29
  15. package/build/JsonConfigComponent/ConfigAutocomplete.js +7 -5
  16. package/build/JsonConfigComponent/ConfigAutocomplete.js.map +1 -1
  17. package/build/JsonConfigComponent/ConfigAutocompleteSendTo.d.ts +5 -14
  18. package/build/JsonConfigComponent/ConfigAutocompleteSendTo.js +3 -3
  19. package/build/JsonConfigComponent/ConfigAutocompleteSendTo.js.map +1 -1
  20. package/build/JsonConfigComponent/ConfigCRON.d.ts +1 -1
  21. package/build/JsonConfigComponent/ConfigCertCollection.d.ts +7 -13
  22. package/build/JsonConfigComponent/ConfigCertCollection.js +8 -18
  23. package/build/JsonConfigComponent/ConfigCertCollection.js.map +1 -1
  24. package/build/JsonConfigComponent/ConfigCertificateSelect.d.ts +7 -13
  25. package/build/JsonConfigComponent/ConfigCertificateSelect.js +5 -18
  26. package/build/JsonConfigComponent/ConfigCertificateSelect.js.map +1 -1
  27. package/build/JsonConfigComponent/ConfigCertificates.d.ts +7 -13
  28. package/build/JsonConfigComponent/ConfigCertificates.js +7 -18
  29. package/build/JsonConfigComponent/ConfigCertificates.js.map +1 -1
  30. package/build/JsonConfigComponent/ConfigCheckbox.d.ts +3 -11
  31. package/build/JsonConfigComponent/ConfigCheckbox.js +2 -2
  32. package/build/JsonConfigComponent/ConfigCheckbox.js.map +1 -1
  33. package/build/JsonConfigComponent/ConfigChip.d.ts +1 -1
  34. package/build/JsonConfigComponent/ConfigColor.d.ts +13 -20
  35. package/build/JsonConfigComponent/ConfigColor.js +9 -23
  36. package/build/JsonConfigComponent/ConfigColor.js.map +1 -1
  37. package/build/JsonConfigComponent/ConfigCoordinates.d.ts +8 -13
  38. package/build/JsonConfigComponent/ConfigCoordinates.js +29 -39
  39. package/build/JsonConfigComponent/ConfigCoordinates.js.map +1 -1
  40. package/build/JsonConfigComponent/ConfigCustom.d.ts +4 -50
  41. package/build/JsonConfigComponent/ConfigCustom.js +0 -1
  42. package/build/JsonConfigComponent/ConfigCustom.js.map +1 -1
  43. package/build/JsonConfigComponent/ConfigDatePicker.d.ts +8 -3
  44. package/build/JsonConfigComponent/ConfigDatePicker.js +21 -13
  45. package/build/JsonConfigComponent/ConfigDatePicker.js.map +1 -1
  46. package/build/JsonConfigComponent/ConfigDeviceManager.d.ts +5 -1
  47. package/build/JsonConfigComponent/ConfigDeviceManager.js +1 -1
  48. package/build/JsonConfigComponent/ConfigDeviceManager.js.map +1 -1
  49. package/build/JsonConfigComponent/ConfigFile.d.ts +1 -1
  50. package/build/JsonConfigComponent/ConfigFunc.d.ts +1 -1
  51. package/build/JsonConfigComponent/ConfigGeneric.d.ts +46 -32
  52. package/build/JsonConfigComponent/ConfigGeneric.js +23 -12
  53. package/build/JsonConfigComponent/ConfigGeneric.js.map +1 -1
  54. package/build/JsonConfigComponent/ConfigIP.d.ts +1 -1
  55. package/build/JsonConfigComponent/ConfigImageSendTo.d.ts +1 -1
  56. package/build/JsonConfigComponent/ConfigInstanceSelect.d.ts +1 -1
  57. package/build/JsonConfigComponent/ConfigInterface.d.ts +1 -1
  58. package/build/JsonConfigComponent/ConfigJsonEditor.d.ts +1 -1
  59. package/build/JsonConfigComponent/ConfigLanguage.d.ts +3 -2
  60. package/build/JsonConfigComponent/ConfigLanguage.js +2 -2
  61. package/build/JsonConfigComponent/ConfigLanguage.js.map +1 -1
  62. package/build/JsonConfigComponent/ConfigNumber.d.ts +3 -13
  63. package/build/JsonConfigComponent/ConfigNumber.js +2 -2
  64. package/build/JsonConfigComponent/ConfigNumber.js.map +1 -1
  65. package/build/JsonConfigComponent/ConfigObjectId.d.ts +1 -1
  66. package/build/JsonConfigComponent/ConfigPanel.d.ts +7 -2
  67. package/build/JsonConfigComponent/ConfigPanel.js +5 -40
  68. package/build/JsonConfigComponent/ConfigPanel.js.map +1 -1
  69. package/build/JsonConfigComponent/ConfigPassword.d.ts +1 -1
  70. package/build/JsonConfigComponent/ConfigPort.d.ts +6 -1
  71. package/build/JsonConfigComponent/ConfigPort.js +2 -3
  72. package/build/JsonConfigComponent/ConfigPort.js.map +1 -1
  73. package/build/JsonConfigComponent/ConfigRoom.d.ts +1 -1
  74. package/build/JsonConfigComponent/ConfigSelect.d.ts +1 -1
  75. package/build/JsonConfigComponent/ConfigSelectSendTo.d.ts +7 -16
  76. package/build/JsonConfigComponent/ConfigSelectSendTo.js +15 -61
  77. package/build/JsonConfigComponent/ConfigSelectSendTo.js.map +1 -1
  78. package/build/JsonConfigComponent/ConfigSendto.d.ts +3 -20
  79. package/build/JsonConfigComponent/ConfigSendto.js +8 -8
  80. package/build/JsonConfigComponent/ConfigSendto.js.map +1 -1
  81. package/build/JsonConfigComponent/ConfigSetState.d.ts +1 -1
  82. package/build/JsonConfigComponent/ConfigSlider.d.ts +1 -1
  83. package/build/JsonConfigComponent/ConfigStaticDivider.d.ts +1 -1
  84. package/build/JsonConfigComponent/ConfigStaticHeader.d.ts +1 -1
  85. package/build/JsonConfigComponent/ConfigStaticImage.d.ts +1 -1
  86. package/build/JsonConfigComponent/ConfigStaticText.d.ts +1 -1
  87. package/build/JsonConfigComponent/ConfigTable.d.ts +4 -25
  88. package/build/JsonConfigComponent/ConfigTable.js +5 -4
  89. package/build/JsonConfigComponent/ConfigTable.js.map +1 -1
  90. package/build/JsonConfigComponent/ConfigTabs.d.ts +8 -33
  91. package/build/JsonConfigComponent/ConfigTabs.js +10 -43
  92. package/build/JsonConfigComponent/ConfigTabs.js.map +1 -1
  93. package/build/JsonConfigComponent/ConfigText.d.ts +7 -13
  94. package/build/JsonConfigComponent/ConfigText.js +13 -18
  95. package/build/JsonConfigComponent/ConfigText.js.map +1 -1
  96. package/build/JsonConfigComponent/ConfigTextSendTo.d.ts +7 -9
  97. package/build/JsonConfigComponent/ConfigTextSendTo.js +11 -21
  98. package/build/JsonConfigComponent/ConfigTextSendTo.js.map +1 -1
  99. package/build/JsonConfigComponent/ConfigTimePicker.d.ts +9 -3
  100. package/build/JsonConfigComponent/ConfigTimePicker.js +28 -18
  101. package/build/JsonConfigComponent/ConfigTimePicker.js.map +1 -1
  102. package/build/JsonConfigComponent/ConfigTopic.d.ts +1 -1
  103. package/build/JsonConfigComponent/ConfigUUID.d.ts +12 -13
  104. package/build/JsonConfigComponent/ConfigUUID.js +1 -6
  105. package/build/JsonConfigComponent/ConfigUUID.js.map +1 -1
  106. package/build/JsonConfigComponent/ConfigUser.d.ts +1 -1
  107. package/build/JsonConfigComponent/index.d.ts +66 -25
  108. package/build/JsonConfigComponent/index.js +48 -61
  109. package/build/JsonConfigComponent/index.js.map +1 -1
  110. package/build/index.d.ts +2 -2
  111. package/build/index.js +2 -2
  112. package/build/index.js.map +1 -1
  113. package/package.json +27 -26
  114. package/src/JsonConfig.tsx +710 -0
  115. package/src/JsonConfigComponent/ChipInput.tsx +752 -0
  116. package/src/JsonConfigComponent/ConfigAccordion.tsx +278 -0
  117. package/src/JsonConfigComponent/ConfigAlive.tsx +74 -0
  118. package/src/JsonConfigComponent/ConfigAutocomplete.tsx +108 -0
  119. package/src/JsonConfigComponent/ConfigAutocompleteSendTo.tsx +183 -0
  120. package/src/JsonConfigComponent/ConfigCRON.jsx +101 -0
  121. package/src/JsonConfigComponent/ConfigCertCollection.tsx +102 -0
  122. package/src/JsonConfigComponent/ConfigCertificateSelect.tsx +92 -0
  123. package/src/JsonConfigComponent/ConfigCertificates.tsx +202 -0
  124. package/src/JsonConfigComponent/ConfigCheckLicense.jsx +662 -0
  125. package/src/JsonConfigComponent/ConfigCheckbox.tsx +67 -0
  126. package/src/JsonConfigComponent/ConfigChip.jsx +81 -0
  127. package/src/JsonConfigComponent/ConfigColor.tsx +86 -0
  128. package/src/JsonConfigComponent/ConfigCoordinates.tsx +234 -0
  129. package/src/JsonConfigComponent/ConfigCustom.tsx +246 -0
  130. package/src/JsonConfigComponent/ConfigDatePicker.tsx +48 -0
  131. package/src/JsonConfigComponent/ConfigDeviceManager.tsx +33 -0
  132. package/src/JsonConfigComponent/ConfigFile.jsx +181 -0
  133. package/src/JsonConfigComponent/ConfigFileSelector.jsx +520 -0
  134. package/src/JsonConfigComponent/ConfigFunc.jsx +90 -0
  135. package/src/JsonConfigComponent/ConfigGeneric.tsx +1027 -0
  136. package/src/JsonConfigComponent/ConfigIP.jsx +96 -0
  137. package/src/JsonConfigComponent/ConfigImageSendTo.jsx +79 -0
  138. package/src/JsonConfigComponent/ConfigImageUpload.jsx +114 -0
  139. package/src/JsonConfigComponent/ConfigInstanceSelect.jsx +172 -0
  140. package/src/JsonConfigComponent/ConfigInterface.jsx +112 -0
  141. package/src/JsonConfigComponent/ConfigJsonEditor.jsx +103 -0
  142. package/src/JsonConfigComponent/ConfigLanguage.tsx +153 -0
  143. package/src/JsonConfigComponent/ConfigLicense.jsx +148 -0
  144. package/src/JsonConfigComponent/ConfigNumber.tsx +207 -0
  145. package/src/JsonConfigComponent/ConfigObjectId.jsx +113 -0
  146. package/src/JsonConfigComponent/ConfigPanel.tsx +360 -0
  147. package/src/JsonConfigComponent/ConfigPassword.jsx +160 -0
  148. package/src/JsonConfigComponent/ConfigPattern.jsx +50 -0
  149. package/src/JsonConfigComponent/ConfigPort.tsx +232 -0
  150. package/src/JsonConfigComponent/ConfigRoom.jsx +90 -0
  151. package/src/JsonConfigComponent/ConfigSelect.jsx +124 -0
  152. package/src/JsonConfigComponent/ConfigSelectSendTo.tsx +251 -0
  153. package/src/JsonConfigComponent/ConfigSendto.tsx +340 -0
  154. package/src/JsonConfigComponent/ConfigSetState.jsx +116 -0
  155. package/src/JsonConfigComponent/ConfigSlider.jsx +97 -0
  156. package/src/JsonConfigComponent/ConfigStaticDivider.jsx +51 -0
  157. package/src/JsonConfigComponent/ConfigStaticHeader.jsx +63 -0
  158. package/src/JsonConfigComponent/ConfigStaticImage.jsx +48 -0
  159. package/src/JsonConfigComponent/ConfigStaticText.jsx +72 -0
  160. package/src/JsonConfigComponent/ConfigTable.tsx +1040 -0
  161. package/src/JsonConfigComponent/ConfigTabs.tsx +150 -0
  162. package/src/JsonConfigComponent/ConfigText.tsx +188 -0
  163. package/src/JsonConfigComponent/ConfigTextSendTo.tsx +102 -0
  164. package/src/JsonConfigComponent/ConfigTimePicker.tsx +63 -0
  165. package/src/JsonConfigComponent/ConfigTopic.jsx +78 -0
  166. package/src/JsonConfigComponent/ConfigUUID.tsx +55 -0
  167. package/src/JsonConfigComponent/ConfigUser.jsx +104 -0
  168. package/src/JsonConfigComponent/index.tsx +435 -0
  169. package/src/JsonConfigComponent/wrapper/Components/CustomModal.jsx +145 -0
  170. package/src/JsonConfigComponent/wrapper/Components/Editor.jsx +65 -0
  171. package/src/Utils.jsx +1683 -0
  172. package/src/index.tsx +14 -0
  173. package/src/types.d.ts +372 -0
@@ -0,0 +1,278 @@
1
+ import React from 'react';
2
+ import { withStyles } from '@mui/styles';
3
+
4
+ import {
5
+ FormHelperText,
6
+ Accordion, AccordionSummary, AccordionDetails,
7
+ IconButton, Paper,
8
+ Toolbar, Tooltip,
9
+ Typography, type Theme,
10
+ } from '@mui/material';
11
+
12
+ import {
13
+ Add as AddIcon,
14
+ Delete as DeleteIcon,
15
+ ArrowUpward as UpIcon,
16
+ ArrowDownward as DownIcon,
17
+ ContentCopy as CopyContentIcon,
18
+ ExpandMore as ExpandMoreIcon,
19
+ } from '@mui/icons-material';
20
+
21
+ import { Utils, I18n } from '@iobroker/adapter-react-v5';
22
+
23
+ import ConfigGeneric, { type ConfigGenericProps, type ConfigGenericState } from './ConfigGeneric';
24
+ // eslint-disable-next-line import/no-cycle
25
+ import ConfigPanel from './ConfigPanel';
26
+ import type {ConfigItemAccordion, ConfigItemIndexed, ConfigItemPanel} from "#JC/types";
27
+
28
+ const styles: Record<string, any> = (theme: Theme) => ({
29
+ fullWidth: {
30
+ width: '100%',
31
+ },
32
+ accordionSummary: {
33
+ backgroundColor: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.08)' : 'rgba(0, 0, 0, 0.08)',
34
+ },
35
+ accordionTitle: {
36
+ // fontWeight: 'bold',
37
+ },
38
+ toolbar: {
39
+ backgroundColor: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.08)' : 'rgba(0, 0, 0, 0.08)',
40
+ borderRadius: 3,
41
+ },
42
+ });
43
+
44
+ interface ConfigAccordionProps extends ConfigGenericProps {
45
+ schema: ConfigItemAccordion;
46
+ }
47
+
48
+ interface ConfigAccordionState extends ConfigGenericState {
49
+ value: Record<string, any>[];
50
+ activeIndex: number;
51
+ iteration: number;
52
+ }
53
+
54
+ class ConfigAccordion extends ConfigGeneric<ConfigAccordionProps, ConfigAccordionState> {
55
+ private typingTimer: ReturnType<typeof setTimeout> | null = null;
56
+
57
+ constructor(props: ConfigAccordionProps) {
58
+ super(props);
59
+ this.props.schema.items = this.props.schema.items || [];
60
+ }
61
+
62
+ async componentDidMount() {
63
+ super.componentDidMount();
64
+
65
+ let value = ConfigGeneric.getValue(this.props.data, this.props.attr) || [];
66
+
67
+ if (!Array.isArray(value)) {
68
+ value = [];
69
+ }
70
+
71
+ this.setState({
72
+ value,
73
+ activeIndex: -1,
74
+ iteration: 0,
75
+ });
76
+ }
77
+
78
+ componentWillUnmount() {
79
+ this.typingTimer && clearTimeout(this.typingTimer);
80
+ this.typingTimer = null;
81
+ super.componentWillUnmount();
82
+ }
83
+
84
+ itemAccordion(data: Record<string, any>, idx: number) {
85
+ const { value } = this.state;
86
+ const { schema } = this.props;
87
+
88
+ const schemaItem: ConfigItemPanel = {
89
+ type: 'panel',
90
+ items: schema.items.reduce((accumulator: Record<string, ConfigItemIndexed>, currentValue: ConfigItemIndexed) => {
91
+ accumulator[currentValue.attr] = currentValue;
92
+ return accumulator;
93
+ }, {}),
94
+ style: { marginLeft: -8, marginTop: 10, marginBottom: 10 },
95
+ };
96
+
97
+ return <ConfigPanel
98
+ index={idx + this.state.iteration}
99
+ arrayIndex={idx}
100
+ changed={this.props.changed}
101
+ globalData={this.props.data}
102
+ socket={this.props.socket}
103
+ adapterName={this.props.adapterName}
104
+ instance={this.props.instance}
105
+ common={this.props.common}
106
+ alive={this.props.alive}
107
+ themeType={this.props.themeType}
108
+ themeName={this.props.themeName}
109
+ data={data}
110
+ custom
111
+ schema={schemaItem}
112
+ systemConfig={this.props.systemConfig}
113
+ originalData={this.props.originalData}
114
+ customs={this.props.customs}
115
+ dateFormat={this.props.dateFormat}
116
+ isFloatComma={this.props.isFloatComma}
117
+ forceUpdate={this.props.forceUpdate}
118
+ imagePrefix={this.props.imagePrefix}
119
+ onCommandRunning={this.props.onCommandRunning}
120
+ onChange={(attr, valueChange) => {
121
+ const newObj = JSON.parse(JSON.stringify(value));
122
+ (newObj[idx] as Record<string, any>)[attr as string] = valueChange;
123
+ this.setState({ value: newObj }, () =>
124
+ this.onChangeWrapper(newObj));
125
+ }}
126
+ onError={(error, attr) => this.onError(error, attr)}
127
+ table={this.props.table}
128
+ />;
129
+ }
130
+
131
+ onDelete = (index: number) => () => {
132
+ const newValue = JSON.parse(JSON.stringify(this.state.value));
133
+ newValue.splice(index, 1);
134
+
135
+ this.setState({ value: newValue, iteration: this.state.iteration + 10000 }, () => this.onChangeWrapper(newValue));
136
+ };
137
+
138
+ onClone = (index: number) => () => {
139
+ const newValue = JSON.parse(JSON.stringify(this.state.value)) as Record<string, any>[];
140
+ const cloned = JSON.parse(JSON.stringify(newValue[index]));
141
+ if (typeof this.props.schema.clone === 'string' && typeof cloned[this.props.schema.clone] === 'string') {
142
+ let i = 1;
143
+ let text = cloned[this.props.schema.clone];
144
+ const pattern = text.match(/(\d+)$/);
145
+ if (pattern) {
146
+ text = text.replace(pattern[0], '');
147
+ i = parseInt(pattern[0], 10) + 1;
148
+ } else {
149
+ text += '_';
150
+ }
151
+ // eslint-disable-next-line no-loop-func
152
+ while (newValue.find(it => it[this.props.schema.clone as string] === text + i.toString())) {
153
+ i++;
154
+ }
155
+ cloned[this.props.schema.clone] = `${cloned[this.props.schema.clone]}_${i}`;
156
+ }
157
+
158
+ newValue.splice(index, 0, cloned);
159
+
160
+ this.setState({ value: newValue, activeIndex: -1, iteration: this.state.iteration + 10000 }, () => this.onChangeWrapper(newValue));
161
+ };
162
+
163
+ onChangeWrapper = (newValue: any) => {
164
+ this.typingTimer && clearTimeout(this.typingTimer);
165
+
166
+ this.typingTimer = setTimeout(value => {
167
+ this.typingTimer = null;
168
+
169
+ this.onChange(this.props.attr, value);
170
+ }, 300, newValue);
171
+ };
172
+
173
+ onAdd = () => {
174
+ const { schema } = this.props;
175
+ const newValue = JSON.parse(JSON.stringify(this.state.value));
176
+ const newItem: Record<string, any> = schema.items && schema.items.reduce((accumulator: Record<string, any>, currentValue: ConfigItemIndexed) => {
177
+ let defaultValue;
178
+ if (currentValue.defaultFunc) {
179
+ if (this.props.custom) {
180
+ defaultValue = currentValue.defaultFunc ? this.executeCustom(currentValue.defaultFunc, this.props.data, this.props.customObj, this.props.instanceObj, newValue.length, this.props.data) : this.props.schema.default;
181
+ } else {
182
+ defaultValue = currentValue.defaultFunc ? this.execute(currentValue.defaultFunc, this.props.schema.default, this.props.data, newValue.length, this.props.data) : this.props.schema.default;
183
+ }
184
+ } else {
185
+ defaultValue = currentValue.default === undefined ? null : currentValue.default;
186
+ }
187
+
188
+ accumulator[currentValue.attr] = defaultValue;
189
+ return accumulator;
190
+ }, {});
191
+
192
+ newValue.push(newItem);
193
+
194
+ this.setState({ value: newValue, activeIndex: newValue.length - 1 }, () => this.onChangeWrapper(newValue));
195
+ };
196
+
197
+ onMoveUp(idx: number) {
198
+ const newValue = JSON.parse(JSON.stringify(this.state.value));
199
+ const item = newValue[idx];
200
+ newValue.splice(idx, 1);
201
+ newValue.splice(idx - 1, 0, item);
202
+
203
+ const newIndex = this.state.activeIndex - 1;
204
+ this.setState({ value: newValue, activeIndex: newIndex, iteration: this.state.iteration + 10000 }, () => this.onChangeWrapper(newValue));
205
+ }
206
+
207
+ onMoveDown(idx: number) {
208
+ const newValue = JSON.parse(JSON.stringify(this.state.value));
209
+ const item = newValue[idx];
210
+ newValue.splice(idx, 1);
211
+ newValue.splice(idx + 1, 0, item);
212
+
213
+ const newIndex = this.state.activeIndex + 1;
214
+ this.setState({ value: newValue, activeIndex: newIndex, iteration: this.state.iteration + 10000 }, () => this.onChangeWrapper(newValue));
215
+ }
216
+
217
+ renderItem(/* error, disabled, defaultValue */) {
218
+ const { classes, schema } = this.props;
219
+ const { value } = this.state;
220
+
221
+ if (!value) {
222
+ return null;
223
+ }
224
+
225
+ return <Paper>
226
+ {schema.label || !schema.noDelete ? <Toolbar variant="dense">
227
+ {schema.label ? <Typography className={classes.title} variant="h6" id="tableTitle" component="div">
228
+ {this.getText(schema.label)}
229
+ </Typography> : null}
230
+ {!schema.noDelete ? <IconButton size="small" color="primary" onClick={this.onAdd}>
231
+ <AddIcon />
232
+ </IconButton> : null}
233
+ </Toolbar> : null}
234
+ {value.map((idx, i) =>
235
+ <Accordion key={`${idx}_${i}`} expanded={this.state.activeIndex === i} onChange={(e, expanded) => { this.setState({ activeIndex: expanded ? i : -1 }); }}>
236
+ <AccordionSummary
237
+ expandIcon={<ExpandMoreIcon />}
238
+ className={Utils.clsx(classes.fullWidth, classes.accordionSummary)}
239
+ >
240
+ <Typography className={classes.accordionTitle}>{idx[schema.titleAttr]}</Typography>
241
+ </AccordionSummary>
242
+ <AccordionDetails style={({ ...schema.style, ...(this.props.themeType ? schema.darkStyle : {}) })}>
243
+ {this.itemAccordion(value[i], i)}
244
+ <Toolbar className={classes.toolbar}>
245
+ {i ? <Tooltip title={I18n.t('ra_Move up')}>
246
+ <IconButton size="small" onClick={() => this.onMoveUp(i)}>
247
+ <UpIcon />
248
+ </IconButton>
249
+ </Tooltip> : <div className={classes.buttonEmpty} />}
250
+ {i < value.length - 1 ? <Tooltip title={I18n.t('ra_Move down')}>
251
+ <IconButton size="small" onClick={() => this.onMoveDown(i)}>
252
+ <DownIcon />
253
+ </IconButton>
254
+ </Tooltip> : <div className={classes.buttonEmpty} />}
255
+ {!schema.noDelete ? <Tooltip title={I18n.t('ra_Delete current row')}>
256
+ <IconButton size="small" onClick={this.onDelete(i)}>
257
+ <DeleteIcon />
258
+ </IconButton>
259
+ </Tooltip> : null}
260
+ {schema.clone ? <Tooltip title={I18n.t('ra_Clone current row')}>
261
+ <IconButton size="small" onClick={this.onClone(i)}>
262
+ <CopyContentIcon />
263
+ </IconButton>
264
+ </Tooltip> : null}
265
+ </Toolbar>
266
+ </AccordionDetails>
267
+ </Accordion>)}
268
+ {!schema.noDelete && value.length > 0 ? <Toolbar variant="dense" className={classes.rootTool}>
269
+ <IconButton size="small" color="primary" onClick={this.onAdd}>
270
+ <AddIcon />
271
+ </IconButton>
272
+ </Toolbar> : null}
273
+ {schema.help ? <FormHelperText>{this.renderHelp(this.props.schema.help, this.props.schema.helpLink, this.props.schema.noTranslation)}</FormHelperText> : null}
274
+ </Paper>;
275
+ }
276
+ }
277
+
278
+ export default withStyles(styles)(ConfigAccordion);
@@ -0,0 +1,74 @@
1
+ import React from 'react';
2
+ import { withStyles } from '@mui/styles';
3
+
4
+ import { Utils, I18n } from '@iobroker/adapter-react-v5';
5
+ import type { ConfigItemAlive } from '#JC/types';
6
+ import ConfigGeneric, { type ConfigGenericProps, type ConfigGenericState } from './ConfigGeneric';
7
+
8
+ const styles: Record<string, any> = {
9
+ root: {
10
+ width: '100%',
11
+ },
12
+ notAlive: {
13
+ color: '#a30000',
14
+ },
15
+ };
16
+
17
+ interface ConfigAliveProps extends ConfigGenericProps {
18
+ schema: ConfigItemAlive;
19
+ }
20
+
21
+ interface ConfigAliveState extends ConfigGenericState {
22
+ alive?: boolean | null;
23
+ instance?: string;
24
+ }
25
+
26
+ class ConfigAlive extends ConfigGeneric<ConfigAliveProps, ConfigAliveState> {
27
+ componentDidMount() {
28
+ super.componentDidMount();
29
+
30
+ const instance = this.getInstance();
31
+
32
+ this.props.socket.getState(`${instance}.alive`)
33
+ .then(state => this.setState({ alive: !!(state && state.val), instance }));
34
+ }
35
+
36
+ getInstance() {
37
+ let instance = this.props.schema.instance || (`${this.props.adapterName}.${this.props.instance}`);
38
+ if (instance.includes('${')) {
39
+ instance = this.getPattern(instance);
40
+ }
41
+ if (instance && !instance.startsWith('system.adapter.')) {
42
+ instance = `system.adapter.${instance}`;
43
+ }
44
+ return instance;
45
+ }
46
+
47
+ renderItem() {
48
+ if (this.getInstance() !== this.state.instance) {
49
+ setTimeout(() => {
50
+ const instance = this.getInstance();
51
+ if (instance) {
52
+ this.props.socket.getState(`${instance}.alive`)
53
+ .then(state => this.setState({ alive: !!(state && state.val), instance }));
54
+ } else {
55
+ this.setState({ alive: null, instance });
56
+ }
57
+ }, 200);
58
+ }
59
+
60
+ if (this.state.alive !== false && this.state.alive !== true) {
61
+ return null;
62
+ }
63
+
64
+ const instance = this.state.instance.replace(/^system.adapter./, '');
65
+ return <div className={Utils.clsx(this.props.classes.root, !this.state.alive && this.props.classes.notAlive)}>
66
+ {this.state.alive ?
67
+ this.props.schema.textAlive !== undefined ? (this.props.schema.textAlive ? I18n.t(this.props.schema.textAlive, instance) : '') : I18n.t('ra_Instance %s is alive', instance)
68
+ :
69
+ this.props.schema.textNotAlive !== undefined ? (this.props.schema.textNotAlive ? I18n.t(this.props.schema.textNotAlive, instance) : '') : I18n.t('ra_Instance %s is not alive', instance)}
70
+ </div>;
71
+ }
72
+ }
73
+
74
+ export default withStyles(styles)(ConfigAlive);
@@ -0,0 +1,108 @@
1
+ import React from 'react';
2
+ import { withStyles } from '@mui/styles';
3
+
4
+ import { Autocomplete, TextField } from '@mui/material';
5
+
6
+ import { I18n } from '@iobroker/adapter-react-v5';
7
+
8
+ import type { ConfigItemAutocomplete, ConfigItemSelectOption } from '#JC/types';
9
+ import ConfigGeneric, { type ConfigGenericState, type ConfigGenericProps } from './ConfigGeneric';
10
+
11
+ const styles: Record<string, any> = {
12
+ fullWidth: {
13
+ width: '100%',
14
+ },
15
+ };
16
+
17
+ export interface ConfigAutocompleteProps extends ConfigGenericProps {
18
+ schema: ConfigItemAutocomplete;
19
+ }
20
+
21
+ export interface ConfigAutocompleteState extends ConfigGenericState {
22
+ selectOptions: { value: string; label: string }[];
23
+ }
24
+
25
+ class ConfigAutocomplete extends ConfigGeneric<ConfigAutocompleteProps, ConfigAutocompleteState> {
26
+ componentDidMount(): void {
27
+ super.componentDidMount();
28
+ const value = ConfigGeneric.getValue(this.props.data, this.props.attr);
29
+
30
+ const selectOptions = this.props.schema.options.map((item: any) => (typeof item === 'string' ? { label: item, value: item } : JSON.parse(JSON.stringify(item))));
31
+
32
+ // if __different
33
+ if (Array.isArray(value)) {
34
+ selectOptions.unshift({ label: I18n.t(ConfigGeneric.DIFFERENT_LABEL), value: ConfigGeneric.DIFFERENT_VALUE });
35
+ this.setState({ value: ConfigGeneric.DIFFERENT_VALUE, selectOptions });
36
+ } else {
37
+ this.setState({ value, selectOptions });
38
+ }
39
+ }
40
+
41
+ renderItem(error: unknown, disabled: boolean): React.JSX.Element | null {
42
+ if (!this.state.selectOptions) {
43
+ return null;
44
+ }
45
+
46
+ let item;
47
+ const options: (string | ConfigItemSelectOption)[] = JSON.parse(JSON.stringify(this.state.selectOptions));
48
+ const isIndeterminate = Array.isArray(this.state.value) || this.state.value === ConfigGeneric.DIFFERENT_VALUE;
49
+
50
+ if (isIndeterminate) {
51
+ [...this.state.value]
52
+ .filter(val => !options.find(it => (typeof it === 'object' ? (it as ConfigItemSelectOption).value === val : (it as string) === val)))
53
+ .forEach(it => options.push({ label: it.toString(), value: it }));
54
+
55
+ item = { label: I18n.t(ConfigGeneric.DIFFERENT_LABEL), value: ConfigGeneric.DIFFERENT_VALUE };
56
+ options.unshift(item);
57
+ } else {
58
+ item = this.state.value !== null &&
59
+ this.state.value !== undefined &&
60
+ // eslint-disable-next-line eqeqeq
61
+ options.find(_item => (typeof _item === 'object' ? _item.value == this.state.value : _item == this.state.value)); // let "==" be and not ===
62
+
63
+ if (this.state.value !== null && this.state.value !== undefined && !item && this.props.schema.freeSolo) {
64
+ item = { value: this.state.value, label: this.state.value };
65
+ options.push(item);
66
+ }
67
+ }
68
+
69
+ return <Autocomplete
70
+ className={this.props.classes.indeterminate}
71
+ fullWidth
72
+ freeSolo={!!this.props.schema.freeSolo}
73
+ value={item}
74
+ options={options}
75
+ // autoComplete
76
+ onInputChange={e => {
77
+ if (!e || !this.props.schema.freeSolo) {
78
+ return;
79
+ }
80
+
81
+ const val = (e.target as HTMLInputElement).value;
82
+ if (val !== this.state.value) {
83
+ this.setState({ value: val }, () => this.onChange(this.props.attr, val));
84
+ }
85
+ }}
86
+ onChange={(_, value) => {
87
+ const val = typeof value === 'object' ? (value ? value.value : '') : value;
88
+ if (val !== this.state.value) {
89
+ this.setState({ value: val }, () => this.onChange(this.props.attr, val));
90
+ }
91
+ }}
92
+ getOptionLabel={option => (typeof option === 'object' ? (option?.label ?? '') : '')}
93
+ renderInput={params => <TextField
94
+ variant="standard"
95
+ {...params}
96
+ error={!!error}
97
+ // inputProps are important and will be given in params
98
+ // inputProps={{maxLength: this.props.schema.maxLength || this.props.schema.max || undefined}}
99
+ placeholder={this.getText(this.props.schema.placeholder)}
100
+ label={this.getText(this.props.schema.label)}
101
+ helperText={this.renderHelp(this.props.schema.help, this.props.schema.helpLink, this.props.schema.noTranslation)}
102
+ disabled={disabled}
103
+ />}
104
+ />;
105
+ }
106
+ }
107
+
108
+ export default withStyles(styles)(ConfigAutocomplete);
@@ -0,0 +1,183 @@
1
+ import React from 'react';
2
+ import { withStyles } from '@mui/styles';
3
+
4
+ import { Autocomplete, TextField } from '@mui/material';
5
+
6
+ import { I18n } from '@iobroker/adapter-react-v5';
7
+
8
+ import type { ConfigItemAutocompleteSendTo } from '#JC/types';
9
+ import ConfigGeneric, { type ConfigGenericProps } from './ConfigGeneric';
10
+ import type { ConfigAutocompleteState } from './ConfigAutocomplete';
11
+
12
+ interface ConfigAutocompleteSendToProps extends ConfigGenericProps {
13
+ schema: ConfigItemAutocompleteSendTo;
14
+ }
15
+
16
+ interface ConfigAutocompleteSendToState extends ConfigAutocompleteState {
17
+ context: string;
18
+ }
19
+
20
+ const styles: Record<string, any> = {
21
+ fullWidth: {
22
+ width: '100%',
23
+ },
24
+ };
25
+
26
+ class ConfigAutocompleteSendTo extends ConfigGeneric<ConfigAutocompleteSendToProps, ConfigAutocompleteSendToState> {
27
+ componentDidMount() {
28
+ super.componentDidMount();
29
+
30
+ this.askInstance();
31
+ }
32
+
33
+ askInstance() {
34
+ const value = ConfigGeneric.getValue(this.props.data, this.props.attr);
35
+ const selectOptions = this.props.schema.options ?
36
+ this.props.schema.options.map((item: any) => (typeof item === 'string' ? { label: item, value: item } : JSON.parse(JSON.stringify(item))))
37
+ :
38
+ [];
39
+
40
+ if (this.props.alive) {
41
+ let data = this.props.schema.data;
42
+ if (data === undefined && this.props.schema.jsonData) {
43
+ data = this.getPattern(this.props.schema.jsonData);
44
+ try {
45
+ if (typeof data === 'string') {
46
+ data = JSON.parse(data);
47
+ }
48
+ } catch (e) {
49
+ console.error(`Cannot parse json data: ${data}`);
50
+ }
51
+ }
52
+
53
+ if (data === undefined) {
54
+ data = null;
55
+ }
56
+
57
+ this.props.socket.sendTo(`${this.props.adapterName}.${this.props.instance}`, this.props.schema.command || 'send', data)
58
+ .then((list: unknown) => {
59
+ if (list && Array.isArray(list)) {
60
+ list.forEach(item =>
61
+ selectOptions.push(typeof item === 'string' ? { label: item, value: item } : JSON.parse(JSON.stringify(item))));
62
+ }
63
+
64
+ // if __different
65
+ if (Array.isArray(value)) {
66
+ selectOptions.unshift({ label: I18n.t(ConfigGeneric.DIFFERENT_LABEL), value: ConfigGeneric.DIFFERENT_VALUE });
67
+ this.setState({ value: ConfigGeneric.DIFFERENT_VALUE, selectOptions, context: this.getContext() });
68
+ } else {
69
+ this.setState({ value, selectOptions, context: this.getContext() });
70
+ }
71
+ });
72
+ } else if (Array.isArray(value)) {
73
+ // if __different
74
+ selectOptions.unshift({ label: I18n.t(ConfigGeneric.DIFFERENT_LABEL), value: ConfigGeneric.DIFFERENT_VALUE });
75
+ this.setState({ value: ConfigGeneric.DIFFERENT_VALUE, selectOptions });
76
+ } else {
77
+ this.setState({ value, selectOptions });
78
+ }
79
+ }
80
+
81
+ getContext(): string {
82
+ const context: Record<string, any> = {};
83
+ if (Array.isArray(this.props.schema.alsoDependsOn)) {
84
+ this.props.schema.alsoDependsOn.forEach(attr =>
85
+ context[attr] = ConfigGeneric.getValue(this.props.data, attr));
86
+ }
87
+ return JSON.stringify(context);
88
+ }
89
+
90
+ renderItem(error: unknown, disabled: boolean): React.JSX.Element | null {
91
+ if (!this.state.selectOptions) {
92
+ return null;
93
+ }
94
+
95
+ if (this.props.alive) {
96
+ const context = this.getContext();
97
+ if (context !== this.state.context) {
98
+ setTimeout(() => this.askInstance(), 300);
99
+ }
100
+ }
101
+
102
+ let item;
103
+ const options = JSON.parse(JSON.stringify(this.state.selectOptions));
104
+ const isIndeterminate = Array.isArray(this.state.value) || this.state.value === ConfigGeneric.DIFFERENT_LABEL;
105
+
106
+ if (isIndeterminate) {
107
+ [...this.state.value]
108
+ .filter(val => !options.find((it: any) => it.value === val))
109
+ .forEach(it => options.push({ label: it.toString(), value: it }));
110
+
111
+ item = { label: I18n.t(ConfigGeneric.DIFFERENT_LABEL), value: ConfigGeneric.DIFFERENT_VALUE };
112
+ options.unshift(item);
113
+ } else {
114
+ item = this.state.value !== null && this.state.value !== undefined &&
115
+ // eslint-disable-next-line
116
+ options.find((item: any) => item.value == this.state.value); // let "==" be and not ===
117
+
118
+ if (this.state.value !== null && this.state.value !== undefined && !item && this.props.schema.freeSolo) {
119
+ item = { value: this.state.value, label: this.state.value };
120
+ options.push(item);
121
+ }
122
+ item = item || null;
123
+ }
124
+
125
+ if (!options.length) {
126
+ return <TextField
127
+ variant="standard"
128
+ fullWidth
129
+ value={this.state.value === null || this.state.value === undefined ? '' : this.state.value}
130
+ error={!!error}
131
+ disabled={disabled}
132
+ inputProps={{ maxLength: this.props.schema.maxLength || this.props.schema.max || undefined }}
133
+ onChange={e => {
134
+ const value = e.target.value;
135
+ this.setState({ value }, () =>
136
+ this.onChange(this.props.attr, (value || '').trim()));
137
+ }}
138
+ placeholder={this.getText(this.props.schema.placeholder)}
139
+ label={this.getText(this.props.schema.label)}
140
+ helperText={this.renderHelp(this.props.schema.help, this.props.schema.helpLink, this.props.schema.noTranslation)}
141
+ />;
142
+ }
143
+ return <Autocomplete
144
+ value={item}
145
+ fullWidth
146
+ freeSolo={!!this.props.schema.freeSolo}
147
+ options={options}
148
+ // autoComplete
149
+ getOptionLabel={option => option?.label ?? ''}
150
+ className={this.props.classes.indeterminate}
151
+ onInputChange={e => {
152
+ if (!e || !this.props.schema.freeSolo) {
153
+ return;
154
+ }
155
+
156
+ const val = (e.target as HTMLInputElement).value;
157
+ if (val !== this.state.value) {
158
+ this.setState({ value: val }, () => this.onChange(this.props.attr, val));
159
+ }
160
+ }}
161
+ onChange={(_, value) => {
162
+ const val = typeof value === 'object' ? (value ? value.value : '') : value;
163
+ if (val !== this.state.value) {
164
+ this.setState({ value: val }, () => this.onChange(this.props.attr, val));
165
+ }
166
+ }}
167
+ renderInput={params =>
168
+ <TextField
169
+ variant="standard"
170
+ {...params}
171
+ // inputProps are important and will be given in params
172
+ // inputProps={{maxLength: this.props.schema.maxLength || this.props.schema.max || undefined}}
173
+ error={!!error}
174
+ placeholder={this.getText(this.props.schema.placeholder)}
175
+ label={this.getText(this.props.schema.label)}
176
+ helperText={this.renderHelp(this.props.schema.help, this.props.schema.helpLink, this.props.schema.noTranslation)}
177
+ disabled={disabled}
178
+ />}
179
+ />;
180
+ }
181
+ }
182
+
183
+ export default withStyles(styles)(ConfigAutocompleteSendTo);