@iobroker/adapter-react-v5 8.0.7 → 8.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/build/Components/ObjectBrowser.d.ts +7 -399
- package/build/Components/ObjectBrowser.js +277 -1605
- package/build/Components/ObjectBrowser.js.map +1 -1
- package/build/Components/objectBrowserUtils.d.ts +170 -0
- package/build/Components/objectBrowserUtils.js +1372 -0
- package/build/Components/objectBrowserUtils.js.map +1 -0
- package/build/Dialogs/SelectID.d.ts +1 -1
- package/build/Dialogs/SelectID.js +1 -1
- package/build/Dialogs/SelectID.js.map +1 -1
- package/build/GenericApp.js.map +1 -1
- package/build/i18n/de.json +7 -5
- package/build/i18n/en.json +7 -5
- package/build/i18n/es.json +7 -5
- package/build/i18n/fr.json +7 -5
- package/build/i18n/it.json +7 -0
- package/build/i18n/nl.json +7 -0
- package/build/i18n/pl.json +7 -0
- package/build/i18n/pt.json +7 -0
- package/build/i18n/ru.json +7 -0
- package/build/i18n/uk.json +7 -0
- package/build/i18n/zh-cn.json +7 -0
- package/build/index.d.ts +2 -1
- package/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/build/types.d.ts +0 -79
- package/i18n/de.json +7 -5
- package/i18n/en.json +7 -5
- package/i18n/es.json +7 -5
- package/i18n/fr.json +7 -5
- package/i18n/it.json +7 -0
- package/i18n/nl.json +7 -0
- package/i18n/pl.json +7 -0
- package/i18n/pt.json +7 -0
- package/i18n/ru.json +7 -0
- package/i18n/uk.json +7 -0
- package/i18n/zh-cn.json +7 -0
- package/package.json +1 -1
|
@@ -0,0 +1,1372 @@
|
|
|
1
|
+
import React, { Component } from 'react';
|
|
2
|
+
import { Box, FormControl, IconButton, Input, MenuItem, Select } from '@mui/material';
|
|
3
|
+
import SVG from 'react-inlinesvg';
|
|
4
|
+
import { Description as IconMeta, PersonOutlined as IconUser, Router as IconHost, SupervisedUserCircle as IconGroup, SettingsApplications as IconSystem, DataObject as IconData, Info as IconInfo, Link as IconLink, Close as IconClose, Wifi as IconConnection, } from '@mui/icons-material';
|
|
5
|
+
import { Utils } from './Utils';
|
|
6
|
+
export const ICON_SIZE = 24;
|
|
7
|
+
export const ROW_HEIGHT = 32;
|
|
8
|
+
export const COLOR_NAME_USERDATA = (themeType) => (themeType === 'dark' ? '#62ff25' : '#37c400');
|
|
9
|
+
export const COLOR_NAME_ALIAS = (themeType) => (themeType === 'dark' ? '#ee56ff' : '#a204b4');
|
|
10
|
+
export const COLOR_NAME_JAVASCRIPT = (themeType) => (themeType === 'dark' ? '#fff46e' : '#b89101');
|
|
11
|
+
export const COLOR_NAME_SYSTEM = (themeType) => (themeType === 'dark' ? '#ff6d69' : '#ff6d69');
|
|
12
|
+
export const COLOR_NAME_SYSTEM_ADAPTER = (themeType) => themeType === 'dark' ? '#5773ff' : '#5773ff';
|
|
13
|
+
/** Namespaces which are allowed to be edited by non-expert users */
|
|
14
|
+
const NON_EXPERT_NAMESPACES = ['0_userdata.0.', 'alias.0.'];
|
|
15
|
+
export const styles = {
|
|
16
|
+
headerCellInput: {
|
|
17
|
+
width: 'calc(100% - 5px)',
|
|
18
|
+
height: ROW_HEIGHT,
|
|
19
|
+
pt: 0,
|
|
20
|
+
'& .itemIcon': {
|
|
21
|
+
verticalAlign: 'middle',
|
|
22
|
+
width: ICON_SIZE,
|
|
23
|
+
height: ICON_SIZE,
|
|
24
|
+
display: 'inline-block',
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
headerCellSelectItem: {
|
|
28
|
+
'& .itemIcon': {
|
|
29
|
+
width: ICON_SIZE,
|
|
30
|
+
height: ICON_SIZE,
|
|
31
|
+
mr: '5px',
|
|
32
|
+
display: 'inline-block',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
selectNone: {
|
|
36
|
+
opacity: 0.5,
|
|
37
|
+
},
|
|
38
|
+
selectClearButton: {
|
|
39
|
+
position: 'absolute',
|
|
40
|
+
top: 0,
|
|
41
|
+
right: 0,
|
|
42
|
+
borderRadius: 5,
|
|
43
|
+
backgroundColor: 'background.default',
|
|
44
|
+
},
|
|
45
|
+
cellIdTooltipLink: {
|
|
46
|
+
color: '#7ec2fd',
|
|
47
|
+
'&:hover': {
|
|
48
|
+
color: '#7ec2fd',
|
|
49
|
+
},
|
|
50
|
+
'&:visited': {
|
|
51
|
+
color: '#7ec2fd',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
cellIdTooltip: {
|
|
55
|
+
fontSize: 14,
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
export function ButtonIcon(props) {
|
|
59
|
+
return (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 436 436", style: props?.style, width: "24", height: "24", className: "admin-button" },
|
|
60
|
+
React.createElement("g", { fill: "currentColor" },
|
|
61
|
+
React.createElement("path", { d: "m195.23077,24.30769c-36,3 -67,12 -96,26c-49,24 -82,61 -93,104l-3,11l-1,50c0,46 0,49 2,59l5,20c21,58 84,103 165,116c16,3 53,4 70,2c60,-6 111,-28 147,-64c21,-21 36,-49 40,-74a866,866 0 0 0 1,-104c-3,-18 -6,-28 -13,-43c-26,-52 -87,-90 -162,-101c-16,-2 -48,-3 -63,-2l1,0zm60,23c36,5 70,18 95,35c31,20 51,47 59,77c2,7 2,11 2,25c1,15 0,18 -2,26c-19,69 -104,117 -200,114c-47,-2 -90,-15 -124,-38c-31,-20 -51,-47 -59,-77c-3,-11 -4,-32 -2,-43c8,-42 41,-78 91,-101a260,260 0 0 1 140,-19l0,1zm-221,222c21,26 57,49 95,62c81,27 174,14 239,-32c14,-10 31,-27 41,-41c2,-2 2,-2 2,7c-1,23 -16,50 -38,72c-78,74 -233,74 -311,-1a121,121 0 0 1 -39,-76l0,-6l3,4l8,11z" }),
|
|
62
|
+
React.createElement("path", { d: "m201.23077,47.30769c-40,3 -79,19 -104,44c-55,55 -38,133 37,171c52,26 122,24 172,-5c30,-17 51,-42 58,-71c3,-11 3,-34 0,-45c-6,-23 -21,-44 -40,-60l-27,-16a184,184 0 0 0 -96,-18zm30,21c56,5 100,35 112,75c4,11 4,30 0,41c-8,25 -26,45 -54,59a166,166 0 0 1 -160,-8a98,98 0 0 1 -41,-53c-5,-18 -2,-39 8,-57c23,-39 79,-62 135,-57z" }))));
|
|
63
|
+
}
|
|
64
|
+
/** Converts ioB pattern into regex */
|
|
65
|
+
export function pattern2RegEx(pattern) {
|
|
66
|
+
pattern = (pattern || '').toString();
|
|
67
|
+
const startsWithWildcard = pattern[0] === '*';
|
|
68
|
+
const endsWithWildcard = pattern[pattern.length - 1] === '*';
|
|
69
|
+
pattern = pattern.replace(/[-/\\^$+?.()|[\]{}]/g, '\\$&').replace(/\*/g, '.*');
|
|
70
|
+
return (startsWithWildcard ? '' : '^') + pattern + (endsWithWildcard ? '' : '$');
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Function that walks through all keys of an object or array and applies a function to each key.
|
|
74
|
+
*/
|
|
75
|
+
export function walkThroughArray(object, iteratee) {
|
|
76
|
+
const copiedObject = [];
|
|
77
|
+
for (let index = 0; index < object.length; index++) {
|
|
78
|
+
iteratee(copiedObject, object[index], index);
|
|
79
|
+
}
|
|
80
|
+
return copiedObject;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Function that walks through all keys of an object or array and applies a function to each key.
|
|
84
|
+
*/
|
|
85
|
+
export function walkThroughObject(object, iteratee) {
|
|
86
|
+
const copiedObject = {};
|
|
87
|
+
for (const key in object) {
|
|
88
|
+
if (Object.prototype.hasOwnProperty.call(object, key)) {
|
|
89
|
+
iteratee(copiedObject, object[key], key);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return copiedObject;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Function to reduce an object primarily by a given list of keys
|
|
96
|
+
*/
|
|
97
|
+
export function filterObject(
|
|
98
|
+
/** The objects which should be filtered */
|
|
99
|
+
obj,
|
|
100
|
+
/** The keys which should be excluded */
|
|
101
|
+
filterKeys,
|
|
102
|
+
/** Whether translations should be reduced to only the english value */
|
|
103
|
+
excludeTranslations) {
|
|
104
|
+
if (Array.isArray(obj)) {
|
|
105
|
+
return walkThroughArray(obj, (result, value, key) => {
|
|
106
|
+
if (value === undefined || value === null) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// if the key is an object, run it through the inner function - omitFromObject
|
|
110
|
+
const isObject = typeof value === 'object';
|
|
111
|
+
if (excludeTranslations && isObject) {
|
|
112
|
+
if (typeof value.en === 'string' && typeof value.de === 'string') {
|
|
113
|
+
result[key] = value.en;
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
result[key] = isObject ? filterObject(value, filterKeys, excludeTranslations) : value;
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return walkThroughObject(obj, (result, value, key) => {
|
|
121
|
+
if (value === undefined || value === null) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (filterKeys.includes(key)) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
// if the key is an object, run it through the inner function - omitFromObject
|
|
128
|
+
const isObject = typeof value === 'object';
|
|
129
|
+
if (excludeTranslations && isObject) {
|
|
130
|
+
if (typeof value.en === 'string' && typeof value.de === 'string') {
|
|
131
|
+
result[key] = value.en;
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
result[key] = isObject ? filterObject(value, filterKeys, excludeTranslations) : value;
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
// It is an export function and used somewhere else
|
|
139
|
+
export function filterRoles(roleArray, type, defaultRoles) {
|
|
140
|
+
const bigRoleArray = [];
|
|
141
|
+
roleArray.forEach(role => (role.type === 'mixed' || role.type) === type &&
|
|
142
|
+
!bigRoleArray.includes(role.role) &&
|
|
143
|
+
bigRoleArray.push(role.role));
|
|
144
|
+
defaultRoles?.forEach(role => (role.type === 'mixed' || role.type) === type &&
|
|
145
|
+
!bigRoleArray.includes(role.role) &&
|
|
146
|
+
bigRoleArray.push(role.role));
|
|
147
|
+
bigRoleArray.sort();
|
|
148
|
+
return bigRoleArray;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Function to generate a json-file for an object and trigger download it
|
|
152
|
+
*/
|
|
153
|
+
export function generateFile(
|
|
154
|
+
/** The desired filename */
|
|
155
|
+
fileName,
|
|
156
|
+
/** The objects which should be downloaded */
|
|
157
|
+
obj,
|
|
158
|
+
/** Options to filter/reduce the output */
|
|
159
|
+
options) {
|
|
160
|
+
const el = document.createElement('a');
|
|
161
|
+
const filterKeys = [];
|
|
162
|
+
if (options.excludeSystemRepositories) {
|
|
163
|
+
filterKeys.push('system.repositories');
|
|
164
|
+
}
|
|
165
|
+
const filteredObject = filterKeys.length > 0 || options.excludeTranslations
|
|
166
|
+
? filterObject(obj, filterKeys, options.excludeTranslations)
|
|
167
|
+
: obj;
|
|
168
|
+
const data = options.beautify ? JSON.stringify(filteredObject, null, 2) : JSON.stringify(filteredObject);
|
|
169
|
+
el.setAttribute('href', `data:application/json;charset=utf-8,${encodeURIComponent(data)}`);
|
|
170
|
+
el.setAttribute('download', fileName);
|
|
171
|
+
el.style.display = 'none';
|
|
172
|
+
document.body.appendChild(el);
|
|
173
|
+
el.click();
|
|
174
|
+
document.body.removeChild(el);
|
|
175
|
+
}
|
|
176
|
+
export class CustomFilterSelect extends Component {
|
|
177
|
+
hasIcons;
|
|
178
|
+
timer = null;
|
|
179
|
+
constructor(props) {
|
|
180
|
+
super(props);
|
|
181
|
+
this.state = {
|
|
182
|
+
value: props.initialValue || [],
|
|
183
|
+
};
|
|
184
|
+
this.hasIcons = !!props.values?.find(item => item.icon);
|
|
185
|
+
}
|
|
186
|
+
componentWillUnmount() {
|
|
187
|
+
if (this.timer) {
|
|
188
|
+
clearTimeout(this.timer);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
render() {
|
|
192
|
+
return (React.createElement("div", { style: { position: 'relative' } },
|
|
193
|
+
React.createElement(Select, { variant: "standard", key: this.props.name, sx: styles.headerCellInput, className: "no-underline", multiple: true, renderValue: value => {
|
|
194
|
+
if (!value?.length) {
|
|
195
|
+
return this.props.name === 'custom'
|
|
196
|
+
? this.props.texts.showAll
|
|
197
|
+
: this.props.texts[`filter_${this.props.name}`];
|
|
198
|
+
}
|
|
199
|
+
return value.map(val => {
|
|
200
|
+
const item = this.props.values.find(i => typeof i === 'object' ? i.value === val : i === val);
|
|
201
|
+
let id;
|
|
202
|
+
let _name;
|
|
203
|
+
let icon;
|
|
204
|
+
if (typeof item === 'object') {
|
|
205
|
+
id = item.value;
|
|
206
|
+
_name = item.name;
|
|
207
|
+
icon = item.icon;
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
id = item;
|
|
211
|
+
_name = item;
|
|
212
|
+
}
|
|
213
|
+
return (React.createElement(Box, { component: "span", sx: styles.headerCellSelectItem, key: id },
|
|
214
|
+
icon || (this.hasIcons ? React.createElement("div", { className: "itemIcon" }) : null),
|
|
215
|
+
_name));
|
|
216
|
+
});
|
|
217
|
+
}, value: this.state.value, onChange: event => {
|
|
218
|
+
let selectedValues = event.target.value;
|
|
219
|
+
// '_' may be selected only alone
|
|
220
|
+
if (this.state.value[0] === '_' && selectedValues.includes('_') && selectedValues.length > 1) {
|
|
221
|
+
const pos = selectedValues.indexOf('_');
|
|
222
|
+
if (pos !== -1) {
|
|
223
|
+
selectedValues.splice(pos, 1);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
else if (this.state.value[0] !== '_' && selectedValues.includes('_')) {
|
|
227
|
+
selectedValues = ['_'];
|
|
228
|
+
}
|
|
229
|
+
// '_' may be selected only alone
|
|
230
|
+
if (selectedValues.includes('')) {
|
|
231
|
+
selectedValues = [];
|
|
232
|
+
}
|
|
233
|
+
this.setState({ value: selectedValues }, () => {
|
|
234
|
+
if (this.timer) {
|
|
235
|
+
clearTimeout(this.timer);
|
|
236
|
+
}
|
|
237
|
+
this.timer = setTimeout(() => {
|
|
238
|
+
this.timer = null;
|
|
239
|
+
this.props.onChange(this.props.name, selectedValues);
|
|
240
|
+
}, 400);
|
|
241
|
+
});
|
|
242
|
+
}, onClose: () => {
|
|
243
|
+
if (this.timer) {
|
|
244
|
+
clearTimeout(this.timer);
|
|
245
|
+
this.timer = null;
|
|
246
|
+
this.props.onChange(this.props.name, this.state.value);
|
|
247
|
+
}
|
|
248
|
+
}, inputProps: { name: this.props.name, id: this.props.name }, displayEmpty: true },
|
|
249
|
+
React.createElement(MenuItem, { key: "empty", value: "" },
|
|
250
|
+
React.createElement("span", { style: styles.selectNone }, this.props.name === 'custom'
|
|
251
|
+
? this.props.texts.showAll
|
|
252
|
+
: this.props.texts[`filter_${this.props.name}`])),
|
|
253
|
+
this.props.values?.map(item => {
|
|
254
|
+
let id;
|
|
255
|
+
let _name;
|
|
256
|
+
let icon;
|
|
257
|
+
if (typeof item === 'object') {
|
|
258
|
+
id = item.value;
|
|
259
|
+
_name = item.name;
|
|
260
|
+
icon = item.icon;
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
id = item;
|
|
264
|
+
_name = item;
|
|
265
|
+
}
|
|
266
|
+
return (React.createElement(MenuItem, { sx: styles.headerCellSelectItem, key: id, value: id },
|
|
267
|
+
icon || (this.hasIcons ? React.createElement("div", { className: "itemIcon" }) : null),
|
|
268
|
+
_name));
|
|
269
|
+
})),
|
|
270
|
+
this.state.value.length ? (React.createElement(Box, { component: "div", sx: styles.selectClearButton },
|
|
271
|
+
React.createElement(IconButton, { size: "small", onClick: () => {
|
|
272
|
+
if (this.timer) {
|
|
273
|
+
clearTimeout(this.timer);
|
|
274
|
+
this.timer = null;
|
|
275
|
+
}
|
|
276
|
+
this.setState({ value: [] }, () => this.props.onChange(this.props.name, undefined));
|
|
277
|
+
} },
|
|
278
|
+
React.createElement(IconClose, null)))) : null));
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
export class CustomFilterInput extends Component {
|
|
282
|
+
timer = null;
|
|
283
|
+
constructor(props) {
|
|
284
|
+
super(props);
|
|
285
|
+
this.state = {
|
|
286
|
+
value: props.initialValue || '',
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
componentWillUnmount() {
|
|
290
|
+
if (this.timer) {
|
|
291
|
+
clearTimeout(this.timer);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
render() {
|
|
295
|
+
return (React.createElement(FormControl, { sx: this.props.styles, key: this.props.name, title: this.props.t('ra_You can use * as wildcard'), margin: "dense" },
|
|
296
|
+
React.createElement(Input, { classes: { underline: 'no-underline' }, id: this.props.name, placeholder: this.props.texts[`filter_${this.props.name}`], value: this.state.value, onChange: event => {
|
|
297
|
+
const selectedValues = event.target.value;
|
|
298
|
+
this.setState({ value: selectedValues }, () => {
|
|
299
|
+
if (this.timer) {
|
|
300
|
+
clearTimeout(this.timer);
|
|
301
|
+
}
|
|
302
|
+
this.timer = setTimeout(() => {
|
|
303
|
+
this.timer = null;
|
|
304
|
+
this.props.onChange(this.props.name, selectedValues);
|
|
305
|
+
}, 400);
|
|
306
|
+
});
|
|
307
|
+
}, onBlur: () => {
|
|
308
|
+
if (this.timer) {
|
|
309
|
+
clearTimeout(this.timer);
|
|
310
|
+
this.timer = null;
|
|
311
|
+
this.props.onChange(this.props.name, this.state.value);
|
|
312
|
+
}
|
|
313
|
+
}, autoComplete: "off" }),
|
|
314
|
+
this.state.value ? (React.createElement("div", { style: {
|
|
315
|
+
position: 'absolute',
|
|
316
|
+
right: 0,
|
|
317
|
+
} },
|
|
318
|
+
React.createElement(IconButton, { size: "small", onClick: () => {
|
|
319
|
+
if (this.timer) {
|
|
320
|
+
clearTimeout(this.timer);
|
|
321
|
+
this.timer = null;
|
|
322
|
+
}
|
|
323
|
+
this.setState({ value: '' }, () => this.props.onChange(this.props.name, undefined));
|
|
324
|
+
} },
|
|
325
|
+
React.createElement(IconClose, null)))) : null));
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
// d=data, t=target, s=start, e=end, m=middle
|
|
329
|
+
export function binarySearch(list, find, _start, _end) {
|
|
330
|
+
_start ||= 0;
|
|
331
|
+
if (_end === undefined) {
|
|
332
|
+
_end = list.length - 1;
|
|
333
|
+
if (!_end) {
|
|
334
|
+
return list[0] === find;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
const middle = Math.floor((_start + _end) / 2);
|
|
338
|
+
if (find === list[middle]) {
|
|
339
|
+
return true;
|
|
340
|
+
}
|
|
341
|
+
if (_end - 1 === _start) {
|
|
342
|
+
return list[_start] === find || list[_end] === find;
|
|
343
|
+
}
|
|
344
|
+
if (find > list[middle]) {
|
|
345
|
+
return binarySearch(list, find, middle, _end);
|
|
346
|
+
}
|
|
347
|
+
if (find < list[middle]) {
|
|
348
|
+
return binarySearch(list, find, _start, middle);
|
|
349
|
+
}
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
export function getName(name, lang) {
|
|
353
|
+
if (typeof name === 'object') {
|
|
354
|
+
if (!name) {
|
|
355
|
+
return '';
|
|
356
|
+
}
|
|
357
|
+
return (name[lang] || name.en || '').toString();
|
|
358
|
+
}
|
|
359
|
+
return name ? name.toString() : '';
|
|
360
|
+
}
|
|
361
|
+
export function getSelectIdIconFromObjects(objects, id, lang, imagePrefix) {
|
|
362
|
+
// `admin` has prefix '.' and `web` has '../..'
|
|
363
|
+
imagePrefix ||= '.'; // http://localhost:8081';
|
|
364
|
+
let src = '';
|
|
365
|
+
const _id_ = `system.adapter.${id}`;
|
|
366
|
+
const aIcon = id && objects[_id_]?.common?.icon;
|
|
367
|
+
if (aIcon) {
|
|
368
|
+
// if not BASE64
|
|
369
|
+
if (!aIcon.startsWith('data:image/')) {
|
|
370
|
+
if (aIcon.includes('.')) {
|
|
371
|
+
const name = objects[_id_].common.name;
|
|
372
|
+
if (typeof name === 'object') {
|
|
373
|
+
src = `${imagePrefix}/adapter/${name[lang] || name.en}/${aIcon}`;
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
src = `${imagePrefix}/adapter/${name}/${aIcon}`;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
else if (aIcon && aIcon.length < 3) {
|
|
380
|
+
return aIcon; // utf-8
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
return null; // '<i class="material-icons iob-list-icon">' + objects[_id_].common.icon + '</i>';
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
else if (aIcon.startsWith('data:image/svg')) {
|
|
387
|
+
src = (React.createElement(SVG, { className: "iconOwn", src: aIcon, width: 28, height: 28 }));
|
|
388
|
+
}
|
|
389
|
+
else {
|
|
390
|
+
src = aIcon;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
const common = objects[id] && objects[id].common;
|
|
395
|
+
if (common) {
|
|
396
|
+
const cIcon = common.icon;
|
|
397
|
+
if (cIcon) {
|
|
398
|
+
if (!cIcon.startsWith('data:image/')) {
|
|
399
|
+
if (cIcon.includes('.')) {
|
|
400
|
+
let instance;
|
|
401
|
+
if (objects[id].type === 'instance' || objects[id].type === 'adapter') {
|
|
402
|
+
if (typeof common.name === 'object') {
|
|
403
|
+
src = `${imagePrefix}/adapter/${common.name[lang] || common.name.en}/${cIcon}`;
|
|
404
|
+
}
|
|
405
|
+
else {
|
|
406
|
+
src = `${imagePrefix}/adapter/${common.name}/${cIcon}`;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
else if (id && id.startsWith('system.adapter.')) {
|
|
410
|
+
instance = id.split('.', 3);
|
|
411
|
+
if (cIcon[0] === '/') {
|
|
412
|
+
instance[2] += cIcon;
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
instance[2] += `/${cIcon}`;
|
|
416
|
+
}
|
|
417
|
+
src = `${imagePrefix}/adapter/${instance[2]}`;
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
instance = id.split('.', 2);
|
|
421
|
+
if (cIcon[0] === '/') {
|
|
422
|
+
instance[0] += cIcon;
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
instance[0] += `/${cIcon}`;
|
|
426
|
+
}
|
|
427
|
+
src = `${imagePrefix}/adapter/${instance[0]}`;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
else if (aIcon && aIcon.length < 3) {
|
|
431
|
+
return aIcon; // utf-8
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
else if (cIcon.startsWith('data:image/svg')) {
|
|
438
|
+
// if base 64 image
|
|
439
|
+
src = (React.createElement(SVG, { className: "iconOwn", src: cIcon, width: 28, height: 28 }));
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
src = cIcon;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
return src || null;
|
|
448
|
+
}
|
|
449
|
+
export function applyFilter(item, filters, lang, objects, context, counter, customFilter, selectedTypes, _depth) {
|
|
450
|
+
_depth ||= 0;
|
|
451
|
+
let filteredOut = false;
|
|
452
|
+
if (!context) {
|
|
453
|
+
context = {};
|
|
454
|
+
if (filters.id) {
|
|
455
|
+
const id = filters.id.toLowerCase();
|
|
456
|
+
if (id.includes('*')) {
|
|
457
|
+
context.idRx = new RegExp(pattern2RegEx(filters.id), 'i');
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
context.id = id;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
if (filters.name) {
|
|
464
|
+
const name = filters.name.toLowerCase();
|
|
465
|
+
if (name.includes('*')) {
|
|
466
|
+
context.nameRx = new RegExp(pattern2RegEx(name), 'i');
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
context.name = name;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
if (filters.type?.length) {
|
|
473
|
+
context.type = filters.type.map(f => f.toLowerCase());
|
|
474
|
+
}
|
|
475
|
+
if (filters.custom?.length) {
|
|
476
|
+
context.custom = filters.custom.map(c => c.toLowerCase());
|
|
477
|
+
}
|
|
478
|
+
if (filters.role?.length) {
|
|
479
|
+
context.role = filters.role.map(r => r.toLowerCase());
|
|
480
|
+
}
|
|
481
|
+
if (filters.room?.length) {
|
|
482
|
+
context.room = [];
|
|
483
|
+
filters.room.forEach(room => {
|
|
484
|
+
context.room = context.room.concat(objects[room]?.common?.members || []);
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
if (filters.func?.length) {
|
|
488
|
+
context.func = [];
|
|
489
|
+
filters.func.forEach(func => {
|
|
490
|
+
context.func = context.func.concat(objects[func]?.common?.members || []);
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
const data = item.data;
|
|
495
|
+
if (data?.id) {
|
|
496
|
+
const common = data.obj?.common;
|
|
497
|
+
if (customFilter) {
|
|
498
|
+
if (customFilter.type) {
|
|
499
|
+
if (typeof customFilter.type === 'string') {
|
|
500
|
+
if (!data.obj || customFilter.type !== data.obj.type) {
|
|
501
|
+
filteredOut = true;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
else if (Array.isArray(customFilter.type)) {
|
|
505
|
+
if (!data.obj || !customFilter.type.includes(data.obj.type)) {
|
|
506
|
+
filteredOut = true;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
if (!filteredOut && customFilter.common?.type) {
|
|
511
|
+
if (!common?.type) {
|
|
512
|
+
filteredOut = true;
|
|
513
|
+
}
|
|
514
|
+
else if (typeof customFilter.common.type === 'string') {
|
|
515
|
+
if (customFilter.common.type !== common.type) {
|
|
516
|
+
filteredOut = true;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
else if (Array.isArray(customFilter.common.type)) {
|
|
520
|
+
if (!customFilter.common.type.includes(common.type)) {
|
|
521
|
+
filteredOut = true;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
if (!filteredOut && customFilter.common?.role) {
|
|
526
|
+
if (!common?.role) {
|
|
527
|
+
filteredOut = true;
|
|
528
|
+
}
|
|
529
|
+
else if (typeof customFilter.common.role === 'string') {
|
|
530
|
+
if (common.role.startsWith(customFilter.common.role)) {
|
|
531
|
+
filteredOut = true;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
else if (Array.isArray(customFilter.common.role)) {
|
|
535
|
+
if (!customFilter.common.role.find(role => common.role.startsWith(role))) {
|
|
536
|
+
filteredOut = true;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
if (!filteredOut && customFilter.common?.custom === '_' && common?.custom) {
|
|
541
|
+
filteredOut = true;
|
|
542
|
+
}
|
|
543
|
+
else if (!filteredOut && customFilter.common?.custom && customFilter.common?.custom !== '_') {
|
|
544
|
+
const filterOfCustom = customFilter.common.custom;
|
|
545
|
+
if (!common?.custom) {
|
|
546
|
+
filteredOut = true;
|
|
547
|
+
}
|
|
548
|
+
else if (filterOfCustom === '_dataSources') {
|
|
549
|
+
// TODO: make it configurable
|
|
550
|
+
if (!Object.keys(common.custom).find(id => id.startsWith('history.') || id.startsWith('sql.') || id.startsWith('influxdb.'))) {
|
|
551
|
+
filteredOut = true;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
else if (Array.isArray(filterOfCustom)) {
|
|
555
|
+
// here are ['influxdb.', 'telegram.']
|
|
556
|
+
const customs = Object.keys(common.custom); // here are ['influxdb.0', 'telegram.2']
|
|
557
|
+
if (filterOfCustom.find(cst => customs.find(id => id.startsWith(cst)))) {
|
|
558
|
+
filteredOut = true;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
else if (filterOfCustom !== true &&
|
|
562
|
+
!Object.keys(common.custom).find(id => id.startsWith(filterOfCustom))) {
|
|
563
|
+
filteredOut = true;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
if (!filteredOut && !filters.expertMode) {
|
|
568
|
+
filteredOut =
|
|
569
|
+
data.id === 'system' ||
|
|
570
|
+
data.id === 'enum' ||
|
|
571
|
+
// (data.obj && data.obj.type === 'meta') ||
|
|
572
|
+
data.id.startsWith('system.') ||
|
|
573
|
+
data.id.startsWith('enum.') ||
|
|
574
|
+
data.id.startsWith('_design/') ||
|
|
575
|
+
data.id.endsWith('.admin') ||
|
|
576
|
+
!!common?.expert;
|
|
577
|
+
}
|
|
578
|
+
if (!filteredOut && context.id) {
|
|
579
|
+
if (data.fID === undefined) {
|
|
580
|
+
data.fID = data.id.toLowerCase();
|
|
581
|
+
}
|
|
582
|
+
filteredOut = !data.fID.includes(context.id);
|
|
583
|
+
}
|
|
584
|
+
if (!filteredOut && context.idRx) {
|
|
585
|
+
filteredOut = !context.idRx.test(data.id);
|
|
586
|
+
}
|
|
587
|
+
if (!filteredOut && context.name) {
|
|
588
|
+
if (common) {
|
|
589
|
+
if (data.fName === undefined) {
|
|
590
|
+
data.fName = getName(common.name, lang) || '';
|
|
591
|
+
data.fName = data.fName.toLowerCase();
|
|
592
|
+
}
|
|
593
|
+
filteredOut = !data.fName.includes(context.name);
|
|
594
|
+
}
|
|
595
|
+
else {
|
|
596
|
+
filteredOut = true;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
if (!filteredOut && context.nameRx) {
|
|
600
|
+
if (common) {
|
|
601
|
+
if (data.fName === undefined) {
|
|
602
|
+
data.fName = getName(common.name, lang) || '';
|
|
603
|
+
data.fName = data.fName.toLowerCase();
|
|
604
|
+
}
|
|
605
|
+
filteredOut = !context.nameRx.test(data.fName);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
if (!filteredOut && filters.role?.length && common) {
|
|
609
|
+
filteredOut = !(typeof common.role === 'string' && context.role.find(role => common.role.startsWith(role)));
|
|
610
|
+
}
|
|
611
|
+
if (!filteredOut && context.room?.length) {
|
|
612
|
+
filteredOut = !context.room.find(id => id === data.id || data.id.startsWith(`${id}.`));
|
|
613
|
+
}
|
|
614
|
+
if (!filteredOut && context.func?.length) {
|
|
615
|
+
filteredOut = !context.func.find(id => id === data.id || data.id.startsWith(`${id}.`));
|
|
616
|
+
}
|
|
617
|
+
if (!filteredOut && context.type?.length) {
|
|
618
|
+
filteredOut = !(data.obj?.type && context.type.includes(data.obj.type));
|
|
619
|
+
}
|
|
620
|
+
if (!filteredOut && selectedTypes) {
|
|
621
|
+
filteredOut = !(data.obj?.type && selectedTypes.includes(data.obj.type));
|
|
622
|
+
}
|
|
623
|
+
if (!filteredOut && context.custom?.length) {
|
|
624
|
+
if (common) {
|
|
625
|
+
if (context.custom[0] === '_') {
|
|
626
|
+
filteredOut = !!common.custom;
|
|
627
|
+
}
|
|
628
|
+
else if (common.custom) {
|
|
629
|
+
filteredOut = !context.custom.find(custom => common.custom[custom]);
|
|
630
|
+
}
|
|
631
|
+
else {
|
|
632
|
+
filteredOut = true;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
else {
|
|
636
|
+
filteredOut = context.custom[0] !== '_';
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
data.visible = !filteredOut;
|
|
641
|
+
data.hasVisibleChildren = false;
|
|
642
|
+
if (item.children && _depth < 20) {
|
|
643
|
+
item.children.forEach(_item => {
|
|
644
|
+
const visible = applyFilter(_item, filters, lang, objects, context, counter, customFilter, selectedTypes, _depth + 1);
|
|
645
|
+
if (visible) {
|
|
646
|
+
data.hasVisibleChildren = true;
|
|
647
|
+
}
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
// const visible = data.visible || data.hasVisibleChildren;
|
|
651
|
+
data.sumVisibility = data.visible || data.hasVisibleChildren; // || data.hasVisibleParent;
|
|
652
|
+
if (counter && data.sumVisibility) {
|
|
653
|
+
counter.count++;
|
|
654
|
+
}
|
|
655
|
+
// show all children of visible object with opacity 0.5
|
|
656
|
+
if (data.id && data.sumVisibility && item.children) {
|
|
657
|
+
item.children.forEach(_item => (_item.data.hasVisibleParent = true));
|
|
658
|
+
}
|
|
659
|
+
return data.visible || data.hasVisibleChildren;
|
|
660
|
+
}
|
|
661
|
+
export function getVisibleItems(item, type, objects, _result) {
|
|
662
|
+
_result ||= [];
|
|
663
|
+
const data = item.data;
|
|
664
|
+
if (data.sumVisibility) {
|
|
665
|
+
if (data.id && objects[data.id] && (!type || objects[data.id].type === type)) {
|
|
666
|
+
_result.push(data.id);
|
|
667
|
+
}
|
|
668
|
+
item.children?.forEach(_item => getVisibleItems(_item, type, objects, _result));
|
|
669
|
+
}
|
|
670
|
+
return _result;
|
|
671
|
+
}
|
|
672
|
+
function getSystemIcon(objects, id, level, themeType, lang, imagePrefix) {
|
|
673
|
+
let icon;
|
|
674
|
+
// system or design has special icons
|
|
675
|
+
if (id === 'alias' || id === 'alias.0') {
|
|
676
|
+
icon = (React.createElement(IconLink, { className: "iconOwn", style: { color: COLOR_NAME_ALIAS(themeType) } }));
|
|
677
|
+
}
|
|
678
|
+
else if (id === '0_userdata' || id === '0_userdata.0') {
|
|
679
|
+
icon = (React.createElement(IconData, { className: "iconOwn", style: { color: COLOR_NAME_USERDATA(themeType) } }));
|
|
680
|
+
}
|
|
681
|
+
else if (id.startsWith('_design/') || id === 'system') {
|
|
682
|
+
icon = (React.createElement(IconSystem, { className: "iconOwn", style: { color: COLOR_NAME_SYSTEM(themeType) } }));
|
|
683
|
+
}
|
|
684
|
+
else if (id === 'system.adapter') {
|
|
685
|
+
icon = (React.createElement(IconSystem, { className: "iconOwn", style: { color: COLOR_NAME_SYSTEM_ADAPTER(themeType) } }));
|
|
686
|
+
}
|
|
687
|
+
else if (id === 'system.group') {
|
|
688
|
+
icon = React.createElement(IconGroup, { className: "iconOwn" });
|
|
689
|
+
}
|
|
690
|
+
else if (id === 'system.user') {
|
|
691
|
+
icon = React.createElement(IconUser, { className: "iconOwn" });
|
|
692
|
+
}
|
|
693
|
+
else if (id === 'system.host') {
|
|
694
|
+
icon = React.createElement(IconHost, { className: "iconOwn" });
|
|
695
|
+
}
|
|
696
|
+
else if (id.endsWith('.connection') || id.endsWith('.connected')) {
|
|
697
|
+
icon = React.createElement(IconConnection, { className: "iconOwn" });
|
|
698
|
+
}
|
|
699
|
+
else if (id.endsWith('.info')) {
|
|
700
|
+
icon = React.createElement(IconInfo, { className: "iconOwn" });
|
|
701
|
+
}
|
|
702
|
+
else if (objects[id] && objects[id].type === 'meta') {
|
|
703
|
+
icon = React.createElement(IconMeta, { className: "iconOwn" });
|
|
704
|
+
}
|
|
705
|
+
else if (level < 2) {
|
|
706
|
+
// detect "cloud.0"
|
|
707
|
+
if (objects[`system.adapter.${id}`]) {
|
|
708
|
+
icon = getSelectIdIconFromObjects(objects, `system.adapter.${id}`, lang, imagePrefix);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
return icon || null;
|
|
712
|
+
}
|
|
713
|
+
export function getObjectTooltip(data, lang) {
|
|
714
|
+
if (data?.obj?.common?.desc) {
|
|
715
|
+
return getName(data.obj.common.desc, lang) || null;
|
|
716
|
+
}
|
|
717
|
+
return null;
|
|
718
|
+
}
|
|
719
|
+
export function getIdFieldTooltip(data, lang) {
|
|
720
|
+
const tooltip = getObjectTooltip(data, lang);
|
|
721
|
+
if (tooltip?.startsWith('http')) {
|
|
722
|
+
return (React.createElement(Box, { component: "a", sx: styles.cellIdTooltipLink, href: tooltip, target: "_blank", rel: "noreferrer" }, tooltip));
|
|
723
|
+
}
|
|
724
|
+
return React.createElement("span", { style: styles.cellIdTooltip }, tooltip || data.id || '');
|
|
725
|
+
}
|
|
726
|
+
export function buildTree(objects, options) {
|
|
727
|
+
const imagePrefix = options.imagePrefix || '.';
|
|
728
|
+
let ids = Object.keys(objects);
|
|
729
|
+
ids.sort((a, b) => {
|
|
730
|
+
if (a === b) {
|
|
731
|
+
return 0;
|
|
732
|
+
}
|
|
733
|
+
a = a.replace(/\./g, '!!!');
|
|
734
|
+
b = b.replace(/\./g, '!!!');
|
|
735
|
+
if (a > b) {
|
|
736
|
+
return 1;
|
|
737
|
+
}
|
|
738
|
+
return -1;
|
|
739
|
+
});
|
|
740
|
+
if (options.root) {
|
|
741
|
+
ids = ids.filter(id => id === options.root || id.startsWith(`${options.root}.`));
|
|
742
|
+
}
|
|
743
|
+
// find empty nodes and create names for it
|
|
744
|
+
let currentPathArr = [];
|
|
745
|
+
let currentPath = '';
|
|
746
|
+
let currentPathLen = 0;
|
|
747
|
+
const root = {
|
|
748
|
+
data: {
|
|
749
|
+
name: '',
|
|
750
|
+
id: '',
|
|
751
|
+
},
|
|
752
|
+
children: [],
|
|
753
|
+
};
|
|
754
|
+
const info = {
|
|
755
|
+
funcEnums: [],
|
|
756
|
+
roomEnums: [],
|
|
757
|
+
roles: [],
|
|
758
|
+
ids: [],
|
|
759
|
+
types: [],
|
|
760
|
+
objects,
|
|
761
|
+
customs: ['_'],
|
|
762
|
+
enums: [],
|
|
763
|
+
hasSomeCustoms: false,
|
|
764
|
+
aliasesMap: {},
|
|
765
|
+
};
|
|
766
|
+
let cRoot = root;
|
|
767
|
+
for (let i = 0; i < ids.length; i++) {
|
|
768
|
+
const id = ids[i];
|
|
769
|
+
if (!id) {
|
|
770
|
+
continue;
|
|
771
|
+
}
|
|
772
|
+
const obj = objects[id];
|
|
773
|
+
const parts = id.split('.');
|
|
774
|
+
if (obj.type && !info.types.includes(obj.type)) {
|
|
775
|
+
info.types.push(obj.type);
|
|
776
|
+
}
|
|
777
|
+
if (obj) {
|
|
778
|
+
const common = obj.common;
|
|
779
|
+
const role = common?.role;
|
|
780
|
+
if (role && !info.roles.find(it => it.role === role)) {
|
|
781
|
+
if (typeof role !== 'string') {
|
|
782
|
+
console.warn(`Invalid role type "${typeof role}" in "${obj._id}"`);
|
|
783
|
+
}
|
|
784
|
+
else {
|
|
785
|
+
info.roles.push({ role, type: common.type });
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
else if (id.startsWith('enum.rooms.')) {
|
|
789
|
+
info.roomEnums.push(id);
|
|
790
|
+
info.enums.push(id);
|
|
791
|
+
}
|
|
792
|
+
else if (id.startsWith('enum.functions.')) {
|
|
793
|
+
info.funcEnums.push(id);
|
|
794
|
+
info.enums.push(id);
|
|
795
|
+
}
|
|
796
|
+
else if (obj.type === 'enum') {
|
|
797
|
+
info.enums.push(id);
|
|
798
|
+
}
|
|
799
|
+
else if (obj.type === 'instance' && common && (common.supportCustoms || common.adminUI?.custom)) {
|
|
800
|
+
info.hasSomeCustoms = true;
|
|
801
|
+
info.customs.push(id.substring('system.adapter.'.length));
|
|
802
|
+
}
|
|
803
|
+
// Build a map of aliases
|
|
804
|
+
if (id.startsWith('alias.') && obj.common.alias?.id) {
|
|
805
|
+
if (typeof obj.common.alias.id === 'string') {
|
|
806
|
+
const usedId = obj.common.alias.id;
|
|
807
|
+
if (!info.aliasesMap[usedId]) {
|
|
808
|
+
info.aliasesMap[usedId] = [id];
|
|
809
|
+
}
|
|
810
|
+
else if (!info.aliasesMap[usedId].includes(id)) {
|
|
811
|
+
info.aliasesMap[usedId].push(id);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
else {
|
|
815
|
+
const readId = obj.common.alias.id.read;
|
|
816
|
+
if (readId) {
|
|
817
|
+
if (!info.aliasesMap[readId]) {
|
|
818
|
+
info.aliasesMap[readId] = [id];
|
|
819
|
+
}
|
|
820
|
+
else if (!info.aliasesMap[readId].includes(id)) {
|
|
821
|
+
info.aliasesMap[readId].push(id);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
const writeId = obj.common.alias.id.write;
|
|
825
|
+
if (writeId) {
|
|
826
|
+
if (!info.aliasesMap[writeId]) {
|
|
827
|
+
info.aliasesMap[writeId] = [id];
|
|
828
|
+
}
|
|
829
|
+
else if (!info.aliasesMap[writeId].includes(id)) {
|
|
830
|
+
info.aliasesMap[writeId].push(id);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
info.ids.push(id);
|
|
837
|
+
let repeat;
|
|
838
|
+
// if next level
|
|
839
|
+
do {
|
|
840
|
+
repeat = false;
|
|
841
|
+
// If the current level is still OK, and we can add ID to children
|
|
842
|
+
if (!currentPath || id.startsWith(`${currentPath}.`)) {
|
|
843
|
+
// if more than one level added
|
|
844
|
+
if (parts.length - currentPathLen > 1) {
|
|
845
|
+
let curPath = currentPath;
|
|
846
|
+
// generate missing levels
|
|
847
|
+
for (let k = currentPathLen; k < parts.length - 1; k++) {
|
|
848
|
+
curPath += (curPath ? '.' : '') + parts[k];
|
|
849
|
+
// level does not exist
|
|
850
|
+
if (!binarySearch(info.ids, curPath)) {
|
|
851
|
+
const _cRoot = {
|
|
852
|
+
data: {
|
|
853
|
+
name: parts[k],
|
|
854
|
+
parent: cRoot,
|
|
855
|
+
id: curPath,
|
|
856
|
+
obj: objects[curPath],
|
|
857
|
+
level: k,
|
|
858
|
+
icon: getSystemIcon(objects, curPath, k, options.themeType, options.lang, imagePrefix),
|
|
859
|
+
generated: true,
|
|
860
|
+
},
|
|
861
|
+
};
|
|
862
|
+
cRoot.children ||= [];
|
|
863
|
+
cRoot.children.push(_cRoot);
|
|
864
|
+
cRoot = _cRoot;
|
|
865
|
+
info.ids.push(curPath); // IDs will be added by alphabet
|
|
866
|
+
}
|
|
867
|
+
else if (cRoot.children) {
|
|
868
|
+
cRoot = cRoot.children.find(item => item.data.name === parts[k]);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
const _cRoot = {
|
|
873
|
+
data: {
|
|
874
|
+
name: parts[parts.length - 1],
|
|
875
|
+
title: getName(obj?.common?.name, options.lang),
|
|
876
|
+
obj,
|
|
877
|
+
parent: cRoot,
|
|
878
|
+
icon: getSelectIdIconFromObjects(objects, id, options.lang, imagePrefix) ||
|
|
879
|
+
getSystemIcon(objects, id, 0, options.themeType, options.lang, imagePrefix),
|
|
880
|
+
id,
|
|
881
|
+
hasCustoms: !!(obj.common?.custom && Object.keys(obj.common.custom).length),
|
|
882
|
+
level: parts.length - 1,
|
|
883
|
+
generated: false,
|
|
884
|
+
button: obj.type === 'state' &&
|
|
885
|
+
!!obj.common?.role &&
|
|
886
|
+
typeof obj.common.role === 'string' &&
|
|
887
|
+
obj.common.role.startsWith('button') &&
|
|
888
|
+
obj.common?.write !== false,
|
|
889
|
+
switch: obj.type === 'state' &&
|
|
890
|
+
obj.common?.type === 'boolean' &&
|
|
891
|
+
obj.common?.write !== false &&
|
|
892
|
+
obj.common?.read !== false,
|
|
893
|
+
url: !!obj.common?.role &&
|
|
894
|
+
typeof obj.common.role === 'string' &&
|
|
895
|
+
obj.common.role.startsWith('url'),
|
|
896
|
+
},
|
|
897
|
+
};
|
|
898
|
+
cRoot.children ||= [];
|
|
899
|
+
cRoot.children.push(_cRoot);
|
|
900
|
+
cRoot = _cRoot;
|
|
901
|
+
currentPathLen = parts.length;
|
|
902
|
+
currentPathArr = parts;
|
|
903
|
+
currentPath = id;
|
|
904
|
+
}
|
|
905
|
+
else {
|
|
906
|
+
let u = 0;
|
|
907
|
+
while (currentPathArr[u] === parts[u]) {
|
|
908
|
+
u++;
|
|
909
|
+
}
|
|
910
|
+
if (u > 0) {
|
|
911
|
+
let move = currentPathArr.length;
|
|
912
|
+
currentPathArr = currentPathArr.splice(0, u);
|
|
913
|
+
currentPathLen = u;
|
|
914
|
+
currentPath = currentPathArr.join('.');
|
|
915
|
+
while (move > u) {
|
|
916
|
+
if (cRoot.data.parent) {
|
|
917
|
+
cRoot = cRoot.data.parent;
|
|
918
|
+
}
|
|
919
|
+
else {
|
|
920
|
+
console.error(`Parent is null for ${id} ${currentPath} ${currentPathArr.join('.')}`);
|
|
921
|
+
}
|
|
922
|
+
move--;
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
else {
|
|
926
|
+
cRoot = root;
|
|
927
|
+
currentPathArr = [];
|
|
928
|
+
currentPath = '';
|
|
929
|
+
currentPathLen = 0;
|
|
930
|
+
}
|
|
931
|
+
repeat = true;
|
|
932
|
+
}
|
|
933
|
+
} while (repeat);
|
|
934
|
+
}
|
|
935
|
+
info.roomEnums.sort((a, b) => {
|
|
936
|
+
const aName = getName(objects[a]?.common?.name, options.lang) || a.split('.').pop();
|
|
937
|
+
const bName = getName(objects[b]?.common?.name, options.lang) || b.split('.').pop();
|
|
938
|
+
if (aName > bName) {
|
|
939
|
+
return 1;
|
|
940
|
+
}
|
|
941
|
+
if (aName < bName) {
|
|
942
|
+
return -1;
|
|
943
|
+
}
|
|
944
|
+
return 0;
|
|
945
|
+
});
|
|
946
|
+
info.funcEnums.sort((a, b) => {
|
|
947
|
+
const aName = getName(objects[a]?.common?.name, options.lang) || a.split('.').pop();
|
|
948
|
+
const bName = getName(objects[b]?.common?.name, options.lang) || b.split('.').pop();
|
|
949
|
+
if (aName > bName) {
|
|
950
|
+
return 1;
|
|
951
|
+
}
|
|
952
|
+
if (aName < bName) {
|
|
953
|
+
return -1;
|
|
954
|
+
}
|
|
955
|
+
return 0;
|
|
956
|
+
});
|
|
957
|
+
info.roles.sort((a, b) => a.role.localeCompare(b.role));
|
|
958
|
+
info.types.sort();
|
|
959
|
+
return { info, root };
|
|
960
|
+
}
|
|
961
|
+
export function findNode(root, id, _parts, _path, _level) {
|
|
962
|
+
if (root.data.id === id) {
|
|
963
|
+
return root;
|
|
964
|
+
}
|
|
965
|
+
if (!_parts) {
|
|
966
|
+
_parts = id.split('.');
|
|
967
|
+
_level = 0;
|
|
968
|
+
_path = _parts[_level];
|
|
969
|
+
}
|
|
970
|
+
if (!root.children && root.data.id !== id) {
|
|
971
|
+
return null;
|
|
972
|
+
}
|
|
973
|
+
let found;
|
|
974
|
+
if (root.children) {
|
|
975
|
+
for (let i = 0; i < root.children.length; i++) {
|
|
976
|
+
const _id = root.children[i].data.id;
|
|
977
|
+
if (_id === _path) {
|
|
978
|
+
found = root.children[i];
|
|
979
|
+
break;
|
|
980
|
+
}
|
|
981
|
+
else if (_id > _path) {
|
|
982
|
+
break;
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
if (found) {
|
|
987
|
+
_level ||= 0;
|
|
988
|
+
return findNode(found, id, _parts, `${_path}.${_parts[_level + 1]}`, _level + 1);
|
|
989
|
+
}
|
|
990
|
+
return null;
|
|
991
|
+
}
|
|
992
|
+
export function findRoomsForObject(info, id, lang, rooms) {
|
|
993
|
+
if (!id) {
|
|
994
|
+
return { rooms: [], per: false };
|
|
995
|
+
}
|
|
996
|
+
rooms ||= [];
|
|
997
|
+
for (const room of info.roomEnums) {
|
|
998
|
+
const common = info.objects[room]?.common;
|
|
999
|
+
if (!common) {
|
|
1000
|
+
continue;
|
|
1001
|
+
}
|
|
1002
|
+
const name = getName(common.name, lang);
|
|
1003
|
+
if (common.members?.includes(id) && !rooms.includes(name)) {
|
|
1004
|
+
rooms.push(name);
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
let ownEnums;
|
|
1008
|
+
// Check parent
|
|
1009
|
+
const parts = id.split('.');
|
|
1010
|
+
parts.pop();
|
|
1011
|
+
id = parts.join('.');
|
|
1012
|
+
if (info.objects[id]) {
|
|
1013
|
+
ownEnums = rooms.length;
|
|
1014
|
+
findRoomsForObject(info, id, lang, rooms);
|
|
1015
|
+
}
|
|
1016
|
+
return { rooms, per: !ownEnums }; // per is if the enums are from parent
|
|
1017
|
+
}
|
|
1018
|
+
export function findEnumsForObjectAsIds(info, id, enumName, funcs) {
|
|
1019
|
+
if (!id) {
|
|
1020
|
+
return [];
|
|
1021
|
+
}
|
|
1022
|
+
funcs ||= [];
|
|
1023
|
+
for (let i = 0; i < info[enumName].length; i++) {
|
|
1024
|
+
const common = info.objects[info[enumName][i]]?.common;
|
|
1025
|
+
if (common?.members?.includes(id) && !funcs.includes(info[enumName][i])) {
|
|
1026
|
+
funcs.push(info[enumName][i]);
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
funcs.sort();
|
|
1030
|
+
return funcs;
|
|
1031
|
+
}
|
|
1032
|
+
export function findFunctionsForObject(info, id, lang, funcs) {
|
|
1033
|
+
if (!id) {
|
|
1034
|
+
return { funcs: [], pef: false };
|
|
1035
|
+
}
|
|
1036
|
+
funcs ||= [];
|
|
1037
|
+
for (let i = 0; i < info.funcEnums.length; i++) {
|
|
1038
|
+
const common = info.objects[info.funcEnums[i]]?.common;
|
|
1039
|
+
if (!common) {
|
|
1040
|
+
continue;
|
|
1041
|
+
}
|
|
1042
|
+
const name = getName(common.name, lang);
|
|
1043
|
+
if (common.members?.includes(id) && !funcs.includes(name)) {
|
|
1044
|
+
funcs.push(name);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
let ownEnums;
|
|
1048
|
+
// Check parent
|
|
1049
|
+
const parts = id.split('.');
|
|
1050
|
+
parts.pop();
|
|
1051
|
+
id = parts.join('.');
|
|
1052
|
+
if (info.objects[id]) {
|
|
1053
|
+
ownEnums = funcs.length;
|
|
1054
|
+
findFunctionsForObject(info, id, lang, funcs);
|
|
1055
|
+
}
|
|
1056
|
+
return { funcs, pef: !ownEnums };
|
|
1057
|
+
}
|
|
1058
|
+
/*
|
|
1059
|
+
function quality2text(q) {
|
|
1060
|
+
if (!q) {
|
|
1061
|
+
return 'ok';
|
|
1062
|
+
}
|
|
1063
|
+
const custom = q & 0xFFFF0000;
|
|
1064
|
+
let text = '';
|
|
1065
|
+
if (q & 0x40) text += 'device';
|
|
1066
|
+
if (q & 0x80) text += 'sensor';
|
|
1067
|
+
if (q & 0x01) text += ' bad';
|
|
1068
|
+
if (q & 0x02) text += ' not connected';
|
|
1069
|
+
if (q & 0x04) text += ' error';
|
|
1070
|
+
|
|
1071
|
+
return text + (custom ? '|0x' + (custom >> 16).toString(16).toUpperCase() : '') + ' [0x' + q.toString(16).toUpperCase() + ']';
|
|
1072
|
+
}
|
|
1073
|
+
*/
|
|
1074
|
+
/**
|
|
1075
|
+
* Format a state value for visualization
|
|
1076
|
+
*/
|
|
1077
|
+
export function formatValue(options) {
|
|
1078
|
+
const { dateFormat, state, isFloatComma, texts, obj } = options;
|
|
1079
|
+
const states = Utils.getStates(obj);
|
|
1080
|
+
const isCommon = obj.common;
|
|
1081
|
+
let fileViewer;
|
|
1082
|
+
let v =
|
|
1083
|
+
// @ts-expect-error deprecated from js-controller 6
|
|
1084
|
+
isCommon?.type === 'file'
|
|
1085
|
+
? '[file]'
|
|
1086
|
+
: !state || state.val === null
|
|
1087
|
+
? '(null)'
|
|
1088
|
+
: state.val === undefined
|
|
1089
|
+
? '[undef]'
|
|
1090
|
+
: state.val;
|
|
1091
|
+
const type = typeof v;
|
|
1092
|
+
if (isCommon?.role && typeof isCommon.role === 'string' && isCommon.role.match(/^value\.time|^date/)) {
|
|
1093
|
+
if (v && typeof v === 'string') {
|
|
1094
|
+
if (Utils.isStringInteger(v)) {
|
|
1095
|
+
// we assume a unix ts
|
|
1096
|
+
v = new Date(parseInt(v, 10)).toString();
|
|
1097
|
+
}
|
|
1098
|
+
else {
|
|
1099
|
+
// check if parsable by new date
|
|
1100
|
+
try {
|
|
1101
|
+
const parsedDate = new Date(v);
|
|
1102
|
+
if (Utils.isValidDate(parsedDate)) {
|
|
1103
|
+
v = parsedDate.toString();
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
catch {
|
|
1107
|
+
// ignore
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
else {
|
|
1112
|
+
if (v > 946681200 && v < 946681200000) {
|
|
1113
|
+
// '2000-01-01T00:00:00' => 946681200000
|
|
1114
|
+
v *= 1_000; // maybe the time is in seconds (UNIX time)
|
|
1115
|
+
}
|
|
1116
|
+
// "null" and undefined could not be here. See `let v = (isCommon && isCommon.type === 'file') ....` above
|
|
1117
|
+
v = v ? new Date(v).toString() : v;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
else if (isCommon?.role && typeof isCommon.role === 'string' && isCommon.role.match(/^value\.duration/)) {
|
|
1121
|
+
// Format duration values in HH:mm:ss format
|
|
1122
|
+
if (typeof v === 'number' && v >= 0) {
|
|
1123
|
+
const hours = Math.floor(v / 3600);
|
|
1124
|
+
const minutes = Math.floor((v % 3600) / 60);
|
|
1125
|
+
const seconds = Math.floor(v % 60);
|
|
1126
|
+
v = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
|
|
1127
|
+
}
|
|
1128
|
+
else if (typeof v === 'string' && Utils.isStringInteger(v)) {
|
|
1129
|
+
const numValue = parseInt(v, 10);
|
|
1130
|
+
if (numValue >= 0) {
|
|
1131
|
+
const hours = Math.floor(numValue / 3600);
|
|
1132
|
+
const minutes = Math.floor((numValue % 3600) / 60);
|
|
1133
|
+
const seconds = Math.floor(numValue % 60);
|
|
1134
|
+
v = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
else {
|
|
1139
|
+
if (type === 'number') {
|
|
1140
|
+
if (!Number.isInteger(v)) {
|
|
1141
|
+
v = Math.round(v * 100_000_000) / 100_000_000; // remove 4.00000000000000001
|
|
1142
|
+
if (isFloatComma) {
|
|
1143
|
+
v = v.toString().replace('.', ',');
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
else if (type === 'object') {
|
|
1148
|
+
v = JSON.stringify(v);
|
|
1149
|
+
}
|
|
1150
|
+
else if (type !== 'string') {
|
|
1151
|
+
v = v.toString();
|
|
1152
|
+
}
|
|
1153
|
+
else if (v.startsWith('data:image/')) {
|
|
1154
|
+
fileViewer = 'image';
|
|
1155
|
+
}
|
|
1156
|
+
if (typeof v !== 'string') {
|
|
1157
|
+
v = v.toString();
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
const valText = { v: v };
|
|
1161
|
+
// try to replace number with "common.states"
|
|
1162
|
+
if (states && states[v] !== undefined) {
|
|
1163
|
+
if (v !== states[v]) {
|
|
1164
|
+
valText.s = v;
|
|
1165
|
+
v = states[v];
|
|
1166
|
+
valText.v = v;
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
if (valText.v?.length > 40) {
|
|
1170
|
+
valText.c = valText.v;
|
|
1171
|
+
valText.v = `${valText.v.substring(0, 40)}...`;
|
|
1172
|
+
}
|
|
1173
|
+
if (isCommon?.unit) {
|
|
1174
|
+
valText.u = isCommon.unit;
|
|
1175
|
+
}
|
|
1176
|
+
let valFull;
|
|
1177
|
+
if (options.full) {
|
|
1178
|
+
if (typeof v === 'string' && v.length > 100) {
|
|
1179
|
+
valFull = [{ t: texts.value, v: `${v.substring(0, 100)}...` }];
|
|
1180
|
+
}
|
|
1181
|
+
else {
|
|
1182
|
+
valFull = [{ t: texts.value, v }];
|
|
1183
|
+
}
|
|
1184
|
+
if (state) {
|
|
1185
|
+
if (state.ack !== undefined && state.ack !== null) {
|
|
1186
|
+
valFull.push({ t: texts.ack, v: state.ack.toString() });
|
|
1187
|
+
}
|
|
1188
|
+
if (state.ts) {
|
|
1189
|
+
valFull.push({ t: texts.ts, v: state.ts ? Utils.formatDate(new Date(state.ts), dateFormat) : '' });
|
|
1190
|
+
}
|
|
1191
|
+
if (state.lc) {
|
|
1192
|
+
valFull.push({ t: texts.lc, v: state.lc ? Utils.formatDate(new Date(state.lc), dateFormat) : '' });
|
|
1193
|
+
}
|
|
1194
|
+
if (state.from) {
|
|
1195
|
+
let from = state.from.toString();
|
|
1196
|
+
if (from.startsWith('system.adapter.')) {
|
|
1197
|
+
from = from.substring(15);
|
|
1198
|
+
}
|
|
1199
|
+
valFull.push({ t: texts.from, v: from });
|
|
1200
|
+
}
|
|
1201
|
+
if (state.user) {
|
|
1202
|
+
let user = state.user.toString();
|
|
1203
|
+
if (user.startsWith('system.user.')) {
|
|
1204
|
+
user = user.substring(12);
|
|
1205
|
+
}
|
|
1206
|
+
valFull.push({ t: texts.user, v: user });
|
|
1207
|
+
}
|
|
1208
|
+
if (state.c) {
|
|
1209
|
+
valFull.push({ t: texts.c, v: state.c });
|
|
1210
|
+
}
|
|
1211
|
+
valFull.push({ t: texts.quality, v: Utils.quality2text(state.q || 0).join(', '), nbr: true });
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
return {
|
|
1215
|
+
valText,
|
|
1216
|
+
valFull,
|
|
1217
|
+
fileViewer,
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
/**
|
|
1221
|
+
* Get CSS style for given state value
|
|
1222
|
+
*/
|
|
1223
|
+
export function getValueStyle(options) {
|
|
1224
|
+
const { state /* , isExpertMode, isButton */ } = options;
|
|
1225
|
+
const color = state?.ack ? (state.q ? '#ffa500' : '') : '#ff2222c9';
|
|
1226
|
+
// do not show the color of the button in non-expert mode
|
|
1227
|
+
// if (!isExpertMode && isButton) {
|
|
1228
|
+
// color = '';
|
|
1229
|
+
// }
|
|
1230
|
+
return { color };
|
|
1231
|
+
}
|
|
1232
|
+
export function prepareSparkData(values, from) {
|
|
1233
|
+
// set one point every hour
|
|
1234
|
+
let time = from;
|
|
1235
|
+
let i = 1;
|
|
1236
|
+
const v = [];
|
|
1237
|
+
while (i < values.length && time < from + 25 * 3600000) {
|
|
1238
|
+
// find the interval
|
|
1239
|
+
while (values[i - 1].ts < time && time <= values[i].ts && i < values.length) {
|
|
1240
|
+
i++;
|
|
1241
|
+
}
|
|
1242
|
+
if (i === 1 && values[i - 1].ts >= time) {
|
|
1243
|
+
// assume the value was always null
|
|
1244
|
+
v.push(0);
|
|
1245
|
+
}
|
|
1246
|
+
else if (i < values.length) {
|
|
1247
|
+
if (typeof values[i].val === 'boolean' || typeof values[i - 1].val === 'boolean') {
|
|
1248
|
+
v.push(values[i].val ? 1 : 0);
|
|
1249
|
+
}
|
|
1250
|
+
else {
|
|
1251
|
+
// remove nulls
|
|
1252
|
+
values[i - 1].val ||= 0;
|
|
1253
|
+
values[i].val ||= 0;
|
|
1254
|
+
// interpolate
|
|
1255
|
+
const nm1 = values[i - 1].val;
|
|
1256
|
+
const n = values[i].val;
|
|
1257
|
+
const val = nm1 + ((n - nm1) * (time - values[i - 1].ts)) / (values[i].ts - values[i - 1].ts);
|
|
1258
|
+
v.push(val);
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
time += 3600000;
|
|
1262
|
+
}
|
|
1263
|
+
return v;
|
|
1264
|
+
}
|
|
1265
|
+
export function getCustomValue(obj, it) {
|
|
1266
|
+
if (obj?._id?.startsWith(`${it.adapter}.`) && it.path.length > 1) {
|
|
1267
|
+
const p = it.path;
|
|
1268
|
+
let value;
|
|
1269
|
+
const anyObj = obj;
|
|
1270
|
+
if (anyObj[p[0]] && typeof anyObj[p[0]] === 'object') {
|
|
1271
|
+
if (p.length === 2) {
|
|
1272
|
+
// most common case
|
|
1273
|
+
value = anyObj[p[0]][p[1]];
|
|
1274
|
+
}
|
|
1275
|
+
else if (p.length === 3) {
|
|
1276
|
+
value = anyObj[p[0]][p[1]] && typeof anyObj[p[0]][p[1]] === 'object' ? anyObj[p[0]][p[1]][p[2]] : null;
|
|
1277
|
+
}
|
|
1278
|
+
else if (p.length === 4) {
|
|
1279
|
+
value =
|
|
1280
|
+
anyObj[p[0]][p[1]] && typeof anyObj[p[0]][p[1]] === 'object' && anyObj[p[0]][p[1]][p[2]]
|
|
1281
|
+
? anyObj[p[0]][p[1]][p[2]][p[3]]
|
|
1282
|
+
: null;
|
|
1283
|
+
}
|
|
1284
|
+
else if (p.length === 5) {
|
|
1285
|
+
value =
|
|
1286
|
+
anyObj[p[0]][p[1]] &&
|
|
1287
|
+
typeof anyObj[p[0]][p[1]] === 'object' &&
|
|
1288
|
+
anyObj[p[0]][p[1]][p[2]] &&
|
|
1289
|
+
anyObj[p[0]][p[1]][p[2]][p[3]]
|
|
1290
|
+
? anyObj[p[0]][p[1]][p[2]][p[3]][p[4]]
|
|
1291
|
+
: null;
|
|
1292
|
+
}
|
|
1293
|
+
else if (p.length === 6) {
|
|
1294
|
+
value =
|
|
1295
|
+
anyObj[p[0]][p[1]] &&
|
|
1296
|
+
typeof anyObj[p[0]][p[1]] === 'object' &&
|
|
1297
|
+
anyObj[p[0]][p[1]][p[2]] &&
|
|
1298
|
+
anyObj[p[0]][p[1]][p[2]][p[3]] &&
|
|
1299
|
+
anyObj[p[0]][p[1]][p[2]][p[3]][p[4]]
|
|
1300
|
+
? anyObj[p[0]][p[1]][p[2]][p[3]][p[4]][p[5]]
|
|
1301
|
+
: null;
|
|
1302
|
+
}
|
|
1303
|
+
if (value === undefined || value === null) {
|
|
1304
|
+
return null;
|
|
1305
|
+
}
|
|
1306
|
+
return value;
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
return null;
|
|
1310
|
+
}
|
|
1311
|
+
export function setCustomValue(obj, it, value) {
|
|
1312
|
+
if (obj?._id?.startsWith(`${it.adapter}.`) && it.path.length > 1) {
|
|
1313
|
+
const p = it.path;
|
|
1314
|
+
const anyObj = obj;
|
|
1315
|
+
if (anyObj[p[0]] && typeof anyObj[p[0]] === 'object') {
|
|
1316
|
+
if (p.length === 2) {
|
|
1317
|
+
// most common case
|
|
1318
|
+
anyObj[p[0]][p[1]] = value;
|
|
1319
|
+
return true;
|
|
1320
|
+
}
|
|
1321
|
+
if (p.length === 3) {
|
|
1322
|
+
if (anyObj[p[0]][p[1]] && typeof anyObj[p[0]][p[1]] === 'object') {
|
|
1323
|
+
anyObj[p[0]][p[1]][p[2]] = value;
|
|
1324
|
+
return true;
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
else if (p.length === 4) {
|
|
1328
|
+
if (anyObj[p[0]][p[1]] &&
|
|
1329
|
+
typeof anyObj[p[0]][p[1]] === 'object' &&
|
|
1330
|
+
anyObj[p[0]][p[1]][p[2]] &&
|
|
1331
|
+
typeof anyObj[p[0]][p[1]][p[2]] === 'object') {
|
|
1332
|
+
anyObj[p[0]][p[1]][p[2]][p[3]] = value;
|
|
1333
|
+
return true;
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
else if (p.length === 5) {
|
|
1337
|
+
if (anyObj[p[0]][p[1]] &&
|
|
1338
|
+
typeof anyObj[p[0]][p[1]] === 'object' &&
|
|
1339
|
+
anyObj[p[0]][p[1]][p[2]] &&
|
|
1340
|
+
typeof anyObj[p[0]][p[1]][p[2]] === 'object' &&
|
|
1341
|
+
anyObj[p[0]][p[1]][p[2]][p[3]] &&
|
|
1342
|
+
typeof anyObj[p[0]][p[1]][p[2]][p[3]] === 'object') {
|
|
1343
|
+
anyObj[p[0]][p[1]][p[2]][p[3]][p[4]] = value;
|
|
1344
|
+
return true;
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
else if (p.length === 6) {
|
|
1348
|
+
if (anyObj[p[0]][p[1]] &&
|
|
1349
|
+
typeof anyObj[p[0]][p[1]] === 'object' &&
|
|
1350
|
+
anyObj[p[0]][p[1]][p[2]] &&
|
|
1351
|
+
typeof anyObj[p[0]][p[1]][p[2]] === 'object' &&
|
|
1352
|
+
anyObj[p[0]][p[1]][p[2]][p[3]] &&
|
|
1353
|
+
typeof anyObj[p[0]][p[1]][p[2]][p[3]] === 'object' &&
|
|
1354
|
+
anyObj[p[0]][p[1]][p[2]][p[3]][p[4]] &&
|
|
1355
|
+
typeof anyObj[p[0]][p[1]][p[2]][p[3]][p[4]] === 'object') {
|
|
1356
|
+
anyObj[p[0]][p[1]][p[2]][p[3]][p[4]][p[5]] = value;
|
|
1357
|
+
return true;
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
return false;
|
|
1363
|
+
}
|
|
1364
|
+
/**
|
|
1365
|
+
* Check if it is a non-expert id
|
|
1366
|
+
*
|
|
1367
|
+
* @param id id to test
|
|
1368
|
+
*/
|
|
1369
|
+
export function isNonExpertId(id) {
|
|
1370
|
+
return !!NON_EXPERT_NAMESPACES.find(saveNamespace => id.startsWith(saveNamespace));
|
|
1371
|
+
}
|
|
1372
|
+
//# sourceMappingURL=objectBrowserUtils.js.map
|