@iobroker/gui-components 10.0.1 → 10.0.3

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 (43) hide show
  1. package/README.md +6 -2
  2. package/build/Components/FileBrowser.js +18 -13
  3. package/build/Components/FileBrowser.js.map +1 -1
  4. package/build/Components/{ObjectBrowser.d.ts → ObjectBrowser/ObjectBrowserClass.d.ts} +142 -77
  5. package/build/Components/ObjectBrowser/ObjectBrowserClass.js +2462 -0
  6. package/build/Components/ObjectBrowser/ObjectBrowserClass.js.map +1 -0
  7. package/build/Components/ObjectBrowser/constants.d.ts +50 -0
  8. package/build/Components/ObjectBrowser/constants.js +138 -0
  9. package/build/Components/ObjectBrowser/constants.js.map +1 -0
  10. package/build/Components/ObjectBrowser/contextMenu.d.ts +13 -0
  11. package/build/Components/ObjectBrowser/contextMenu.js +354 -0
  12. package/build/Components/ObjectBrowser/contextMenu.js.map +1 -0
  13. package/build/Components/ObjectBrowser/dialogs.d.ts +31 -0
  14. package/build/Components/ObjectBrowser/dialogs.js +421 -0
  15. package/build/Components/ObjectBrowser/dialogs.js.map +1 -0
  16. package/build/Components/ObjectBrowser/index.d.ts +20 -0
  17. package/build/Components/ObjectBrowser/index.js +20 -0
  18. package/build/Components/ObjectBrowser/index.js.map +1 -0
  19. package/build/Components/ObjectBrowser/renderLeaf.d.ts +41 -0
  20. package/build/Components/ObjectBrowser/renderLeaf.js +1077 -0
  21. package/build/Components/ObjectBrowser/renderLeaf.js.map +1 -0
  22. package/build/Components/ObjectBrowser/styles.d.ts +7 -0
  23. package/build/Components/ObjectBrowser/styles.js +662 -0
  24. package/build/Components/ObjectBrowser/styles.js.map +1 -0
  25. package/build/Components/ObjectBrowser/toolbar.d.ts +26 -0
  26. package/build/Components/ObjectBrowser/toolbar.js +327 -0
  27. package/build/Components/ObjectBrowser/toolbar.js.map +1 -0
  28. package/build/Components/{objectBrowser.types.d.ts → ObjectBrowser/types.d.ts} +15 -10
  29. package/build/Components/{objectBrowserUtils.d.ts → ObjectBrowser/utils.d.ts} +22 -2
  30. package/build/Components/{objectBrowserUtils.js → ObjectBrowser/utils.js} +46 -2
  31. package/build/Components/ObjectBrowser/utils.js.map +1 -0
  32. package/build/Components/TreeTable.d.ts +2 -2
  33. package/build/Components/TreeTable.js.map +1 -1
  34. package/build/Dialogs/SelectID.d.ts +4 -4
  35. package/build/Dialogs/SelectID.js +2 -2
  36. package/build/Dialogs/SelectID.js.map +1 -1
  37. package/build/index.d.ts +2 -2
  38. package/build/index.js +1 -1
  39. package/build/index.js.map +1 -1
  40. package/package.json +5 -5
  41. package/build/Components/ObjectBrowser.js +0 -5162
  42. package/build/Components/ObjectBrowser.js.map +0 -1
  43. package/build/Components/objectBrowserUtils.js.map +0 -1
@@ -0,0 +1,1077 @@
1
+ /**
2
+ * Copyright 2020-2026, Denis Haev <dogafox@gmail.com>
3
+ *
4
+ * MIT License
5
+ *
6
+ * Part of the object browser, see ./ObjectBrowserClass.tsx
7
+ */
8
+ import React from 'react';
9
+ import { Utils } from '../Utils';
10
+ import { Box, Checkbox, Grid, IconButton, Paper, Switch, Tooltip } from '@mui/material';
11
+ import { Delete as IconDelete, Edit as IconEdit, Error as IconError, Settings as IconConfig, Wifi as IconConnection, WifiOff as IconDisconnected, } from '@mui/icons-material';
12
+ import { IconCopy } from '../../icons/IconCopy';
13
+ import { IconDocument } from '../../icons/IconDocument';
14
+ import { IconDocumentReadOnly } from '../../icons/IconDocumentReadOnly';
15
+ import { IconClosed } from '../../icons/IconClosed';
16
+ import { IconOpen } from '../../icons/IconOpen';
17
+ import { Icon } from '../Icon';
18
+ import { ButtonIcon, colGrow, colWidth, binarySearch, findEnumsForObjectAsIds, findFunctionsForObject, findRoomsForObject, formatValue, getCustomValue, getIdFieldTooltip, getObjectTooltip, getValueStyle, isNonExpertId, COLOR_NAME_USERDATA, COLOR_NAME_ALIAS, COLOR_NAME_JAVASCRIPT, COLOR_NAME_SYSTEM, COLOR_NAME_SYSTEM_ADAPTER, ROW_HEIGHT, } from './utils';
19
+ import { styles } from './styles';
20
+ import { COLOR_NAME_CONNECTED_DARK, COLOR_NAME_CONNECTED_LIGHT, COLOR_NAME_DISCONNECTED_DARK, COLOR_NAME_DISCONNECTED_LIGHT, COLOR_NAME_ERROR_DARK, COLOR_NAME_ERROR_LIGHT, DEFAULT_DATE_FORMAT, ITEM_IMAGES, } from './constants';
21
+ export function renderTooltipAccessControl(that, acl) {
22
+ // acl ={object,state,owner,ownerGroup}
23
+ if (!acl) {
24
+ return null;
25
+ }
26
+ const check = [
27
+ {
28
+ value: '0x400',
29
+ valueNum: 0x400,
30
+ title: 'read',
31
+ group: 'Owner',
32
+ },
33
+ {
34
+ value: '0x200',
35
+ valueNum: 0x200,
36
+ title: 'write',
37
+ group: 'Owner',
38
+ },
39
+ {
40
+ value: '0x40',
41
+ valueNum: 0x40,
42
+ title: 'read',
43
+ group: 'Group',
44
+ },
45
+ {
46
+ value: '0x20',
47
+ valueNum: 0x20,
48
+ title: 'write',
49
+ group: 'Group',
50
+ },
51
+ {
52
+ value: '0x4',
53
+ valueNum: 0x4,
54
+ title: 'read',
55
+ group: 'Everyone',
56
+ },
57
+ {
58
+ value: '0x2',
59
+ valueNum: 0x2,
60
+ title: 'write',
61
+ group: 'Everyone',
62
+ },
63
+ ];
64
+ const arrayTooltipText = [];
65
+ const funcRenderStateObject = (value) => {
66
+ const rights = acl[value];
67
+ check.forEach((el, i) => {
68
+ if (rights & el.valueNum) {
69
+ arrayTooltipText.push(React.createElement("span", { key: value + i },
70
+ that.texts[`acl${el.group}_${el.title}_${value}`],
71
+ ",",
72
+ React.createElement("span", { style: value === 'object' ? styles.rightsObject : styles.rightsState }, el.value)));
73
+ }
74
+ });
75
+ };
76
+ arrayTooltipText.push(React.createElement("span", { key: "group" }, `${that.texts.ownerGroup}: ${(acl.ownerGroup || '').replace('system.group.', '')}`));
77
+ arrayTooltipText.push(React.createElement("span", { key: "owner" }, `${that.texts.ownerUser}: ${(acl.owner || '').replace('system.user.', '')}`));
78
+ funcRenderStateObject('object');
79
+ if (acl.state) {
80
+ funcRenderStateObject('state');
81
+ }
82
+ return arrayTooltipText.length ? (React.createElement("span", { style: styles.tooltipAccessControl }, arrayTooltipText.map(el => el))) : null;
83
+ }
84
+ export function renderColumnButtons(that, id, item) {
85
+ if (!item.data.obj) {
86
+ return that.props.onObjectDelete || that.props.objectEditOfAccessControl ? (React.createElement("div", { style: styles.buttonDiv },
87
+ that.state.filter.expertMode && that.props.objectEditOfAccessControl ? (React.createElement(IconButton, { sx: {
88
+ ...styles.cellButtonsButton,
89
+ ...styles.cellButtonsEmptyButton,
90
+ ...styles.cellButtonMinWidth,
91
+ }, onClick: () => that.setState({ modalEditOfAccess: true, modalEditOfAccessObjData: item.data }), size: "large" },
92
+ React.createElement("div", { style: { height: 15 } }, "---"))) : null,
93
+ that.props.onObjectDelete && item.children?.length ? (React.createElement(IconButton, { sx: {
94
+ ...styles.cellButtonsButton,
95
+ ...styles.cellButtonsButtonAlone,
96
+ }, size: "small", "aria-label": "delete", title: that.texts.deleteObject, onClick: () => {
97
+ // calculate the number of children
98
+ const keys = Object.keys(that.objects);
99
+ keys.sort();
100
+ let count = 0;
101
+ const start = `${id}.`;
102
+ for (let i = 0; i < keys.length; i++) {
103
+ if (keys[i].startsWith(start)) {
104
+ count++;
105
+ }
106
+ else if (keys[i] > start) {
107
+ break;
108
+ }
109
+ }
110
+ if (that.props.onObjectDelete) {
111
+ that.props.onObjectDelete(id, !!item.children?.length, false, count + 1);
112
+ }
113
+ } },
114
+ React.createElement(IconDelete, { style: styles.cellButtonsButtonIcon }))) : null)) : null;
115
+ }
116
+ item.data.aclTooltip =
117
+ item.data.aclTooltip || renderTooltipAccessControl(that, item.data.obj.acl);
118
+ const acl = item.data.obj.acl
119
+ ? item.data.obj.type === 'state'
120
+ ? item.data.obj.acl.state
121
+ : item.data.obj.acl.object
122
+ : 0;
123
+ const aclSystemConfig = item.data.obj.acl &&
124
+ (item.data.obj.type === 'state'
125
+ ? that.systemConfig?.common.defaultNewAcl.state
126
+ : that.systemConfig?.common.defaultNewAcl.object);
127
+ const showEdit = !!item.data.obj && (that.state.filter.expertMode || isNonExpertId(item.data.id));
128
+ return [
129
+ that.state.filter.expertMode && that.props.objectEditOfAccessControl ? (React.createElement(Tooltip, { key: "acl", title: item.data.aclTooltip, slotProps: { popper: { sx: styles.tooltip } } },
130
+ React.createElement(IconButton, { sx: {
131
+ ...styles.cellButtonsButton,
132
+ ...styles.cellButtonMinWidth,
133
+ opacity: 1,
134
+ }, onClick: () => that.setState({ modalEditOfAccess: true, modalEditOfAccessObjData: item.data }), size: "large" },
135
+ React.createElement("div", { style: styles.aclText }, Number.isNaN(Number(acl)) ? Number(aclSystemConfig).toString(16) : Number(acl).toString(16))))) : (React.createElement("div", { key: "aclEmpty", style: styles.cellButtonMinWidth })),
136
+ showEdit ? (React.createElement(IconButton, { key: "edit", sx: {
137
+ marginRight: '2px',
138
+ ...styles.cellButtonsButton,
139
+ }, size: "small", "aria-label": "edit", title: that.texts.editObject, onClick: () => {
140
+ that.localStorage.setItem(`${that.props.dialogName || 'App'}.objectSelected`, id);
141
+ that.setState({ editObjectDialog: id, editObjectAlias: false });
142
+ } },
143
+ React.createElement(IconEdit, { style: styles.cellButtonsButtonIcon }))) : (React.createElement(Box, { component: "div", key: "editDisabled", sx: styles.cellButtonsButton })),
144
+ that.props.onObjectDelete && (item.children?.length || !item.data.obj.common?.dontDelete) ? (React.createElement(IconButton, { key: "delete", sx: styles.cellButtonsButton, size: "small", "aria-label": "delete", onClick: () => {
145
+ const keys = Object.keys(that.objects);
146
+ keys.sort();
147
+ let count = 0;
148
+ const start = `${id}.`;
149
+ for (let i = 0; i < keys.length; i++) {
150
+ if (keys[i].startsWith(start)) {
151
+ count++;
152
+ }
153
+ else if (keys[i] > start) {
154
+ break;
155
+ }
156
+ }
157
+ if (that.props.onObjectDelete) {
158
+ that.props.onObjectDelete(id, !!item.children?.length, !item.data.obj?.common?.dontDelete, count);
159
+ }
160
+ }, title: that.texts.deleteObject },
161
+ React.createElement(IconDelete, { style: styles.cellButtonsButtonIcon }))) : null,
162
+ that.props.objectCustomDialog &&
163
+ that.info.hasSomeCustoms &&
164
+ item.data.obj.type === 'state' &&
165
+ // @ts-expect-error deprecated from js-controller 6
166
+ item.data.obj.common?.type !== 'file' ? (React.createElement(IconButton, { sx: {
167
+ ...styles.cellButtonsButton,
168
+ ...(item.data.hasCustoms
169
+ ? that.styles.cellButtonsButtonWithCustoms
170
+ : styles.cellButtonsButtonWithoutCustoms),
171
+ }, key: "custom", size: "small", "aria-label": "config", title: that.texts.customConfig, onClick: () => {
172
+ that.localStorage.setItem(`${that.props.dialogName || 'App'}.objectSelected`, id);
173
+ that.pauseSubscribe(true);
174
+ that.props.router?.doNavigate(null, 'customs', id);
175
+ that.setState({ customDialog: [id], customDialogAll: false });
176
+ } },
177
+ React.createElement(IconConfig, { style: styles.cellButtonsButtonIcon }))) : null,
178
+ ];
179
+ }
180
+ /**
181
+ * This function renders the value in different forms in the table
182
+ *
183
+ * @param that the object browser instance
184
+ * @param id state ID
185
+ * @param item Item
186
+ * @param narrowStyleWithDetails if use mobile view
187
+ */
188
+ export function renderColumnValue(that, id, item, narrowStyleWithDetails) {
189
+ const obj = item.data.obj;
190
+ if (!obj || !that.states) {
191
+ return null;
192
+ }
193
+ if (obj.common?.type === 'file') {
194
+ return (React.createElement(Box, { component: "div", sx: { ...styles.cellValueText, ...styles.cellValueFile } }, "[file]"));
195
+ }
196
+ if (!that.states[id]) {
197
+ if (obj.type === 'state') {
198
+ // we are waiting for state
199
+ if (!that.recordStates.includes(id)) {
200
+ that.recordStates.push(id);
201
+ }
202
+ that.states[id] = { val: null };
203
+ that.subscribe(id);
204
+ }
205
+ return null;
206
+ }
207
+ if (!that.recordStates.includes(id)) {
208
+ that.recordStates.push(id);
209
+ }
210
+ const state = that.states[id];
211
+ let info = item.data.state;
212
+ if (!info) {
213
+ const { valText } = formatValue({
214
+ state,
215
+ obj: obj,
216
+ texts: that.texts,
217
+ dateFormat: that.props.dateFormat || that.systemConfig?.common.dateFormat || DEFAULT_DATE_FORMAT,
218
+ isFloatComma: that.props.isFloatComma === undefined
219
+ ? (that.systemConfig?.common.isFloatComma ?? true)
220
+ : that.props.isFloatComma,
221
+ });
222
+ const valTextRx = [];
223
+ item.data.state = { valTextRx };
224
+ valTextRx.push(React.createElement("span", { className: `newValueBrowser-${that.props.themeType || 'light'}`, key: `${valText.v.toString()}valText`, style: {
225
+ whiteSpace: 'nowrap',
226
+ display: 'inline-block',
227
+ overflow: 'hidden',
228
+ textOverflow: 'ellipsis',
229
+ } }, valText.v.toString()));
230
+ if (valText.u) {
231
+ valTextRx.push(React.createElement("span", { className: `newValueBrowser-${that.props.themeType || 'light'}`, style: styles.cellValueTextUnit, key: `${valText.v.toString()}unit` }, valText.u));
232
+ }
233
+ if (valText.s !== undefined) {
234
+ valTextRx.push(React.createElement("span", { style: styles.cellValueTextState, className: `newValueBrowser-${that.props.themeType || 'light'}`, key: `${valText.v.toString()}states` },
235
+ "(",
236
+ valText.s,
237
+ ")"));
238
+ }
239
+ if (!narrowStyleWithDetails) {
240
+ const copyText = valText.c !== undefined ? valText.c : valText.v || '';
241
+ valTextRx.push(React.createElement(IconCopy, { className: "copyButton", style: that.styles.iconCopy, onClick: e => that.onCopy(e, copyText), key: "cc" }));
242
+ }
243
+ // <IconEdit className="copyButton" style={{{ ...styles.cellButtonsValueButton, styles.cellButtonsValueButtonEdit)} key="ce" />
244
+ info = item.data.state;
245
+ }
246
+ info.style = getValueStyle({
247
+ state,
248
+ isExpertMode: that.state.filter.expertMode,
249
+ isButton: item.data.button,
250
+ nonAckColor: that.props.theme.palette.nonAck,
251
+ });
252
+ let val = info.valTextRx;
253
+ if (!that.state.filter.expertMode) {
254
+ if (item.data.button) {
255
+ val = [
256
+ React.createElement(ButtonIcon, { key: "button", style: { color: info.style.color, ...styles.cellValueButton } }),
257
+ ];
258
+ }
259
+ else if (item.data.switch) {
260
+ val = [
261
+ React.createElement(Switch, { key: "switch", sx: {
262
+ '& .MuiSwitch-thumb': { color: info.style.color },
263
+ '& .MuiSwitch-track': {
264
+ backgroundColor: !!that.states[id].val && that.state.selected.includes(id)
265
+ ? that.props.themeType === 'dark'
266
+ ? '#FFF !important'
267
+ : '#111 !important'
268
+ : undefined,
269
+ },
270
+ }, checked: !!that.states[id].val }),
271
+ ];
272
+ }
273
+ }
274
+ return (React.createElement(Tooltip, { key: "value", title: that.state.tooltipInfo?.el, slotProps: {
275
+ popper: { sx: styles.cellValueTooltipBox },
276
+ tooltip: { sx: styles.cellValueTooltip },
277
+ }, onOpen: () => that.getTooltipInfo(id, () => that.readHistory(id)), onClose: () => that.state.tooltipInfo?.id === id && that.setState({ tooltipInfo: null }) },
278
+ React.createElement(Box, { component: "div", style: info.style, className: item.data.url ? 'iob-link' : undefined, sx: {
279
+ ...styles.cellValueText,
280
+ height: narrowStyleWithDetails ? undefined : ROW_HEIGHT,
281
+ '& .admin-button:active': {
282
+ transform: 'translate(0, 2px)',
283
+ },
284
+ } }, val)));
285
+ }
286
+ /**
287
+ * Renders a custom value.
288
+ */
289
+ export function renderCustomValue(that, obj, it, item) {
290
+ const text = getCustomValue(obj, it);
291
+ if (text !== null && text !== undefined) {
292
+ if (it.edit && !that.props.notEditable && (!it.objTypes || it.objTypes.includes(obj.type))) {
293
+ return (React.createElement(Box, { component: "div", style: {
294
+ ...styles.columnCustom,
295
+ ...styles.columnCustomEditable,
296
+ ...styles[`columnCustom_${it.align}`],
297
+ }, onClick: () => that.setState({
298
+ columnsEditCustomDialog: { item, it, obj },
299
+ customColumnDialogValueChanged: false,
300
+ }) }, text));
301
+ }
302
+ return (React.createElement(Box, { component: "div", style: {
303
+ ...styles.columnCustom,
304
+ ...styles[`columnCustom_${it.align}`],
305
+ } }, text));
306
+ }
307
+ return null;
308
+ }
309
+ export function renderAliasLink(that, id, index, customStyle) {
310
+ const _index = index || 0;
311
+ // read the type of operation
312
+ const aliasObj = that.objects[that.info.aliasesMap[id][_index]].common.alias.id;
313
+ if (aliasObj) {
314
+ return (React.createElement(Box, { component: "div", onClick: e => {
315
+ e.stopPropagation();
316
+ e.preventDefault();
317
+ const aliasId = that.info.aliasesMap[id][_index];
318
+ // if more than one alias, close the menu
319
+ if (that.info.aliasesMap[id].length > 1) {
320
+ that.setState({ aliasMenu: '' });
321
+ }
322
+ that.onSelect(aliasId);
323
+ setTimeout(() => that.expandAllSelected(() => that.scrollToItem(aliasId)), 100);
324
+ }, sx: customStyle || that.styles.aliasAlone },
325
+ React.createElement("span", { className: "admin-browser-arrow" }, typeof aliasObj === 'string' || (aliasObj.read === id && aliasObj.write === id)
326
+ ? '↔'
327
+ : aliasObj.read === id
328
+ ? '→'
329
+ : '←'),
330
+ that.info.aliasesMap[id][_index]));
331
+ }
332
+ return null;
333
+ }
334
+ /**
335
+ * Renders a leaf.
336
+ */
337
+ export function renderLeaf(that, item, isExpanded, counter) {
338
+ const id = item.data.id;
339
+ counter.count++;
340
+ isExpanded = isExpanded === undefined ? that.state.expanded.includes(id) : isExpanded;
341
+ // icon
342
+ let iconFolder;
343
+ const obj = item.data.obj;
344
+ const itemType = obj?.type;
345
+ if (item.children ||
346
+ itemType === 'folder' ||
347
+ itemType === 'device' ||
348
+ itemType === 'channel' ||
349
+ itemType === 'meta') {
350
+ iconFolder = isExpanded ? (React.createElement(IconOpen, { style: that.styles.cellIdIconFolder, onClick: () => that.toggleExpanded(id) })) : (React.createElement(IconClosed, { style: that.styles.cellIdIconFolder, onClick: () => that.toggleExpanded(id) }));
351
+ }
352
+ else if (obj && obj.common && obj.common.write === false && obj.type === 'state') {
353
+ iconFolder = React.createElement(IconDocumentReadOnly, { style: that.styles.cellIdIconDocument });
354
+ }
355
+ else {
356
+ iconFolder = React.createElement(IconDocument, { style: that.styles.cellIdIconDocument });
357
+ }
358
+ let iconItem = null;
359
+ if (item.data.icon) {
360
+ if (typeof item.data.icon === 'string') {
361
+ if (item.data.icon.length < 3) {
362
+ iconItem = (React.createElement("span", { className: "iconOwn", style: styles.cellIdIconOwn }, item.data.icon)); // utf-8 char
363
+ }
364
+ else {
365
+ iconItem = (React.createElement(Icon, { style: styles.cellIdIconOwn, className: "iconOwn", src: item.data.icon, alt: "" }));
366
+ }
367
+ }
368
+ else {
369
+ iconItem = item.data.icon;
370
+ }
371
+ }
372
+ const common = obj?.common;
373
+ const typeImg = (obj?.type && ITEM_IMAGES[obj.type]) || React.createElement("div", { className: "itemIcon" });
374
+ const paddingLeft = that.levelPadding * (item.data.level || 0);
375
+ // recalculate rooms and function names if the language changed
376
+ if (item.data.lang !== that.props.lang) {
377
+ const { rooms, per } = findRoomsForObject(that.info, id, that.props.lang);
378
+ item.data.rooms = rooms.join(', ');
379
+ item.data.per = per;
380
+ const { funcs, pef } = findFunctionsForObject(that.info, id, that.props.lang);
381
+ item.data.funcs = funcs.join(', ');
382
+ item.data.pef = pef;
383
+ item.data.lang = that.props.lang;
384
+ }
385
+ const checkbox = that.props.multiSelect &&
386
+ that.objects[id] &&
387
+ (!that.props.types || that.props.types.includes(that.objects[id].type)) ? (React.createElement(Checkbox, { style: styles.checkBox, checked: that.state.selected.includes(id) })) : null;
388
+ let valueEditable = !that.props.notEditable && itemType === 'state' && (that.state.filter.expertMode || common?.write !== false);
389
+ if (that.props.objectBrowserViewFile && common?.type === 'file') {
390
+ valueEditable = true;
391
+ }
392
+ const enumEditable = !that.props.notEditable &&
393
+ that.objects[id] &&
394
+ (that.state.filter.expertMode || itemType === 'state' || itemType === 'channel' || itemType === 'device');
395
+ const checkVisibleObjectType = that.state.statesView && (itemType === 'state' || itemType === 'channel' || itemType === 'device');
396
+ let newValue = '';
397
+ const newValueTitle = [];
398
+ if (checkVisibleObjectType) {
399
+ newValue = that.states[id]?.from;
400
+ if (newValue === undefined) {
401
+ newValue = '&nbsp;';
402
+ }
403
+ else {
404
+ newValue = newValue ? newValue.replace(/^system\.adapter\.|^system\./, '') : '';
405
+ newValueTitle.push(`${that.texts.stateChangedFrom} ${newValue}`);
406
+ }
407
+ if (obj?.user) {
408
+ const user = obj.user.replace('system.user.', '');
409
+ newValue += `/${user}`;
410
+ newValueTitle.push(`${that.texts.stateChangedBy} ${user}`);
411
+ }
412
+ }
413
+ if (obj) {
414
+ if (obj.from) {
415
+ newValueTitle.push(`${that.texts.objectChangedFrom} ${obj.from.replace(/^system\.adapter\.|^system\./, '')}`);
416
+ }
417
+ if (obj.user) {
418
+ newValueTitle.push(`${that.texts.objectChangedBy} ${obj.user.replace(/^system\.user\./, '')}`);
419
+ }
420
+ if (obj.ts) {
421
+ newValueTitle.push(`${that.texts.objectChangedByUser} ${Utils.formatDate(new Date(obj.ts), that.props.dateFormat || that.systemConfig?.common.dateFormat || DEFAULT_DATE_FORMAT)}`);
422
+ }
423
+ }
424
+ let readWriteAlias = false;
425
+ let alias = null;
426
+ if (id.startsWith('alias.') && common?.alias?.id) {
427
+ readWriteAlias = typeof common.alias.id === 'object';
428
+ if (readWriteAlias) {
429
+ alias = (React.createElement("div", { style: styles.cellIdAliasReadWriteDiv },
430
+ common.alias.id.read ? (React.createElement(Box, { component: "div", onClick: e => {
431
+ e.stopPropagation();
432
+ e.preventDefault();
433
+ that.onSelect(common.alias.id.read);
434
+ setTimeout(() => that.expandAllSelected(() => that.scrollToItem(common.alias.id.read)), 100);
435
+ }, sx: that.styles.aliasReadWrite },
436
+ "\u2190",
437
+ common.alias.id.read)) : null,
438
+ common.alias.id.write ? (React.createElement(Box, { component: "div", onClick: e => {
439
+ e.stopPropagation();
440
+ e.preventDefault();
441
+ that.onSelect(common.alias.id.write);
442
+ setTimeout(() => that.expandAllSelected(() => that.scrollToItem(common.alias.id.write)), 100);
443
+ }, sx: that.styles.aliasReadWrite },
444
+ "\u2192",
445
+ common.alias.id.write)) : null));
446
+ }
447
+ else {
448
+ alias = (React.createElement(Box, { component: "div", onClick: e => {
449
+ e.stopPropagation();
450
+ e.preventDefault();
451
+ that.onSelect(common.alias.id);
452
+ setTimeout(() => that.expandAllSelected(() => that.scrollToItem(common.alias.id)), 100);
453
+ }, sx: that.styles.aliasAlone },
454
+ "\u2192",
455
+ common.alias.id));
456
+ }
457
+ }
458
+ else if (that.info.aliasesMap[id]) {
459
+ // Some alias points to that object. It can be more than one
460
+ if (that.info.aliasesMap[id].length > 1) {
461
+ // Show number of aliases and open a menu by click
462
+ alias = (React.createElement(Box, { component: "div", id: `alias_${id}`, onClick: e => {
463
+ e.stopPropagation();
464
+ e.preventDefault();
465
+ that.setState({ aliasMenu: id });
466
+ }, sx: that.styles.aliasAlone }, that.props.t('ra_%s links from aliases', that.info.aliasesMap[id].length)));
467
+ }
468
+ else {
469
+ // Show name of alias and open it by click
470
+ alias = renderAliasLink(that, id, 0);
471
+ }
472
+ }
473
+ let checkColor = common?.color;
474
+ let invertBackground;
475
+ if (checkColor && !that.state.selected.includes(id)) {
476
+ const background = that.props.themeName === 'dark' ? '#1f1f1f' : that.props.themeName === 'blue' ? '#222a2e' : '#FFFFFF';
477
+ const distance = Utils.colorDistance(checkColor, background);
478
+ // console.log(`Distance: ${checkColor} - ${background} = ${distance}`);
479
+ if (distance < 1000) {
480
+ invertBackground = that.props.themeType === 'dark' ? '#9a9a9a' : '#565656';
481
+ }
482
+ }
483
+ let bold = false;
484
+ if (id === '0_userdata') {
485
+ checkColor = COLOR_NAME_USERDATA(that.props.themeType);
486
+ bold = true;
487
+ invertBackground = false;
488
+ }
489
+ else if (id === 'alias') {
490
+ checkColor = COLOR_NAME_ALIAS(that.props.themeType);
491
+ bold = true;
492
+ invertBackground = false;
493
+ }
494
+ else if (id === 'javascript') {
495
+ checkColor = COLOR_NAME_JAVASCRIPT(that.props.themeType);
496
+ bold = true;
497
+ invertBackground = false;
498
+ }
499
+ else if (id === 'system') {
500
+ checkColor = COLOR_NAME_SYSTEM(that.props.themeType);
501
+ bold = true;
502
+ invertBackground = false;
503
+ }
504
+ else if (id === 'system.adapter') {
505
+ checkColor = COLOR_NAME_SYSTEM_ADAPTER(that.props.themeType);
506
+ invertBackground = false;
507
+ }
508
+ else if (!checkColor || that.state.selected.includes(id)) {
509
+ checkColor = 'inherit';
510
+ invertBackground = false;
511
+ }
512
+ const icons = [];
513
+ if (common?.statusStates) {
514
+ const ids = {};
515
+ Object.keys(common.statusStates).forEach(name => {
516
+ let _id = common.statusStates[name];
517
+ if (_id.split('.').length < 3) {
518
+ _id = `${id}.${_id}`;
519
+ }
520
+ ids[name] = _id;
521
+ if (!that.states[_id]) {
522
+ if (that.objects[_id]?.type === 'state') {
523
+ if (!that.recordStates.includes(_id)) {
524
+ that.recordStates.push(_id);
525
+ }
526
+ that.states[_id] = { val: null };
527
+ that.subscribe(_id);
528
+ }
529
+ }
530
+ else if (!that.recordStates.includes(_id)) {
531
+ that.recordStates.push(_id);
532
+ }
533
+ });
534
+ // calculate color
535
+ // errorId has priority
536
+ let colorSet = false;
537
+ if (common.statusStates.errorId && that.states[ids.errorId] && that.states[ids.errorId].val) {
538
+ checkColor = that.props.themeType === 'dark' ? COLOR_NAME_ERROR_DARK : COLOR_NAME_ERROR_LIGHT;
539
+ invertBackground = false;
540
+ colorSet = true;
541
+ icons.push(React.createElement(IconError, { key: "error",
542
+ // title={that.texts.deviceError}
543
+ style: that.styles.iconDeviceError }));
544
+ }
545
+ if (ids.onlineId && that.states[ids.onlineId]) {
546
+ if (!colorSet) {
547
+ if (that.states[ids.onlineId].val) {
548
+ checkColor =
549
+ that.props.themeType === 'dark' ? COLOR_NAME_CONNECTED_DARK : COLOR_NAME_CONNECTED_LIGHT;
550
+ invertBackground = false;
551
+ icons.push(React.createElement(IconConnection, { key: "conn",
552
+ // title={that.texts.deviceError}
553
+ style: that.styles.iconDeviceConnected }));
554
+ }
555
+ else {
556
+ checkColor =
557
+ that.props.themeType === 'dark' ? COLOR_NAME_DISCONNECTED_DARK : COLOR_NAME_DISCONNECTED_LIGHT;
558
+ invertBackground = false;
559
+ icons.push(React.createElement(IconDisconnected, { key: "disc",
560
+ // title={that.texts.deviceError}
561
+ style: that.styles.iconDeviceDisconnected }));
562
+ }
563
+ }
564
+ else if (that.states[ids.onlineId].val) {
565
+ icons.push(React.createElement(IconConnection, { key: "conn",
566
+ // title={that.texts.deviceError}
567
+ style: that.styles.iconDeviceConnected }));
568
+ }
569
+ else {
570
+ icons.push(React.createElement(IconDisconnected, { key: "disc",
571
+ // title={that.texts.deviceError}
572
+ style: that.styles.iconDeviceDisconnected }));
573
+ }
574
+ }
575
+ else if (ids.offlineId && that.states[ids.offlineId]) {
576
+ if (!colorSet) {
577
+ if (that.states[ids.offlineId].val) {
578
+ checkColor =
579
+ that.props.themeType === 'dark' ? COLOR_NAME_DISCONNECTED_DARK : COLOR_NAME_DISCONNECTED_LIGHT;
580
+ invertBackground = false;
581
+ icons.push(React.createElement(IconDisconnected, { key: "disc",
582
+ // title={that.texts.deviceError}
583
+ style: that.styles.iconDeviceDisconnected }));
584
+ }
585
+ else {
586
+ checkColor =
587
+ that.props.themeType === 'dark' ? COLOR_NAME_CONNECTED_DARK : COLOR_NAME_CONNECTED_LIGHT;
588
+ invertBackground = false;
589
+ icons.push(React.createElement(IconConnection, { key: "conn",
590
+ // title={that.texts.deviceError}
591
+ style: that.styles.iconDeviceConnected }));
592
+ }
593
+ }
594
+ else if (that.states[ids.offlineId].val) {
595
+ icons.push(React.createElement(IconDisconnected, { key: "disc",
596
+ // title={that.texts.deviceError}
597
+ style: that.styles.iconDeviceDisconnected }));
598
+ }
599
+ else {
600
+ icons.push(React.createElement(IconConnection, { key: "conn",
601
+ // title={that.texts.deviceError}
602
+ style: that.styles.iconDeviceConnected }));
603
+ }
604
+ }
605
+ }
606
+ const q = checkVisibleObjectType ? Utils.quality2text(that.states[id]?.q || 0).join(', ') : null;
607
+ let name = item.data?.title || '';
608
+ let useDesc = false;
609
+ if (that.state.showDescription) {
610
+ const oTooltip = getObjectTooltip(item.data, that.props.lang);
611
+ if (oTooltip) {
612
+ name = [
613
+ React.createElement("div", { key: "name", style: styles.cellNameDivDiv }, name),
614
+ React.createElement("div", { key: "desc", style: styles.cellDescription }, oTooltip),
615
+ ];
616
+ useDesc = !!oTooltip;
617
+ }
618
+ }
619
+ const narrowStyleWithDetails = that.width === 'xs' && that.state.focused === id;
620
+ const colID = (React.createElement(Grid, { container: true, wrap: "nowrap", direction: "row", sx: styles.cellId, style: { width: colWidth('id'), flexGrow: colGrow('id'), paddingLeft } },
621
+ React.createElement(Grid, { container: true,
622
+ // the icons must not be squeezed by a long name
623
+ sx: { alignItems: 'center', flexShrink: 0 } },
624
+ checkbox,
625
+ iconFolder),
626
+ React.createElement(Grid, { style: {
627
+ ...styles.cellIdSpan,
628
+ // only the name may shrink (it is cut with an ellipsis), and for that a flex item
629
+ // needs `minWidth: 0`, otherwise its content defines the minimal width
630
+ minWidth: 0,
631
+ ...(invertBackground ? that.styles.invertedBackground : undefined),
632
+ color: checkColor,
633
+ fontWeight: bold ? 'bold' : undefined,
634
+ } },
635
+ React.createElement(Tooltip, { title: getIdFieldTooltip(item.data, that.props.lang), slotProps: { popper: { sx: styles.tooltip } } },
636
+ React.createElement("div", null, item.data.name)),
637
+ alias,
638
+ icons),
639
+ React.createElement("div", { style: { ...styles.grow, ...(invertBackground ? that.styles.invertedBackgroundFlex : {}) } }),
640
+ React.createElement(Grid, { container: true, sx: { alignItems: 'center', flexShrink: 0 } }, iconItem),
641
+ that.width !== 'xs' ? (React.createElement("div", { style: { flexShrink: 0 } },
642
+ React.createElement(IconCopy, { className: narrowStyleWithDetails ? '' : 'copyButton', style: styles.cellCopyButton, onClick: e => that.onCopy(e, id) }))) : null));
643
+ let colName = (narrowStyleWithDetails && name) || that.columnsVisibility.name ? (React.createElement(Box, { component: "div", sx: {
644
+ ...styles.cellName,
645
+ ...(useDesc ? styles.cellNameWithDesc : undefined),
646
+ width: that.width !== 'xs' ? colWidth('name') : undefined,
647
+ flexGrow: that.width !== 'xs' ? colGrow('name') : undefined,
648
+ // padding and not margin: a margin is added to the width of the column and all
649
+ // following columns would not match the header anymore
650
+ pl: narrowStyleWithDetails ? 0 : '5px',
651
+ } },
652
+ name,
653
+ !narrowStyleWithDetails && item.data?.title ? (React.createElement(Box, { style: { color: checkColor } },
654
+ React.createElement(IconCopy, { className: "copyButton", style: styles.cellCopyButton, onClick: e => that.onCopy(e, item.data?.title) }))) : null)) : null;
655
+ let colMiddle;
656
+ if (!that.state.statesView) {
657
+ colMiddle = [
658
+ (narrowStyleWithDetails && obj?.type) || that.columnsVisibility.type
659
+ ? {
660
+ el: (React.createElement("div", { key: "type", style: {
661
+ ...styles.cellType,
662
+ width: that.width !== 'xs' ? colWidth('type') : undefined,
663
+ } },
664
+ typeImg,
665
+ "\u00A0",
666
+ obj?.type)),
667
+ type: 'filter_type',
668
+ }
669
+ : null,
670
+ (narrowStyleWithDetails && common) || that.columnsVisibility.role
671
+ ? {
672
+ el: (React.createElement("div", { key: "role", style: {
673
+ ...styles.cellRole,
674
+ width: that.width !== 'xs' ? colWidth('role') : '100%',
675
+ cursor: that.state.filter.expertMode && enumEditable && that.props.objectBrowserEditRole
676
+ ? 'text'
677
+ : 'default',
678
+ }, onClick: !narrowStyleWithDetails &&
679
+ that.state.filter.expertMode &&
680
+ enumEditable &&
681
+ that.props.objectBrowserEditRole
682
+ ? () => that.setState({ roleDialog: item.data.id })
683
+ : undefined }, common?.role)),
684
+ type: 'filter_role',
685
+ onClick: narrowStyleWithDetails &&
686
+ that.state.filter.expertMode &&
687
+ enumEditable &&
688
+ that.props.objectBrowserEditRole
689
+ ? () => that.setState({ roleDialog: item.data.id })
690
+ : undefined,
691
+ }
692
+ : null,
693
+ (narrowStyleWithDetails && common) || that.columnsVisibility.room
694
+ ? {
695
+ el: (React.createElement("div", { key: "room", style: {
696
+ ...styles.cellRoom,
697
+ ...(item.data.per ? styles.cellEnumParent : {}),
698
+ width: that.width !== 'xs' ? colWidth('room') : '100%',
699
+ cursor: enumEditable ? 'text' : 'default',
700
+ }, onClick: !narrowStyleWithDetails && enumEditable
701
+ ? () => {
702
+ const enums = findEnumsForObjectAsIds(that.info, item.data.id, 'roomEnums');
703
+ that.setState({
704
+ enumDialogEnums: enums,
705
+ enumDialog: {
706
+ item,
707
+ type: 'room',
708
+ enumsOriginal: JSON.stringify(enums),
709
+ },
710
+ });
711
+ }
712
+ : undefined }, item.data.rooms)),
713
+ type: 'filter_room',
714
+ onClick: narrowStyleWithDetails && enumEditable
715
+ ? () => {
716
+ const enums = findEnumsForObjectAsIds(that.info, item.data.id, 'roomEnums');
717
+ that.setState({
718
+ enumDialogEnums: enums,
719
+ enumDialog: {
720
+ item,
721
+ type: 'room',
722
+ enumsOriginal: JSON.stringify(enums),
723
+ },
724
+ });
725
+ }
726
+ : undefined,
727
+ }
728
+ : null,
729
+ (narrowStyleWithDetails && common) || that.columnsVisibility.func
730
+ ? {
731
+ el: (React.createElement("div", { key: "func", style: {
732
+ ...styles.cellFunc,
733
+ ...(item.data.pef ? styles.cellEnumParent : {}),
734
+ width: that.width !== 'xs' ? colWidth('func') : '100%',
735
+ cursor: enumEditable ? 'text' : 'default',
736
+ }, onClick: !narrowStyleWithDetails && enumEditable
737
+ ? () => {
738
+ const enums = findEnumsForObjectAsIds(that.info, item.data.id, 'funcEnums');
739
+ that.setState({
740
+ enumDialogEnums: enums,
741
+ enumDialog: {
742
+ item,
743
+ type: 'func',
744
+ enumsOriginal: JSON.stringify(enums),
745
+ },
746
+ });
747
+ }
748
+ : undefined }, item.data.funcs)),
749
+ type: 'filter_func',
750
+ onClick: narrowStyleWithDetails && enumEditable
751
+ ? () => {
752
+ const enums = findEnumsForObjectAsIds(that.info, item.data.id, 'funcEnums');
753
+ that.setState({
754
+ enumDialogEnums: enums,
755
+ enumDialog: {
756
+ item,
757
+ type: 'func',
758
+ enumsOriginal: JSON.stringify(enums),
759
+ },
760
+ });
761
+ }
762
+ : undefined,
763
+ }
764
+ : null,
765
+ ];
766
+ }
767
+ else {
768
+ colMiddle = [
769
+ (narrowStyleWithDetails && checkVisibleObjectType && that.states[id]?.from) ||
770
+ that.columnsVisibility.changedFrom
771
+ ? {
772
+ el: (React.createElement("div", { key: "from", style: {
773
+ ...styles.cellRole,
774
+ width: that.width !== 'xs' ? colWidth('changedFrom') : undefined,
775
+ }, title: newValueTitle.join('\n') }, checkVisibleObjectType && that.states[id]?.from ? newValue : null)),
776
+ type: 'from',
777
+ }
778
+ : null,
779
+ (narrowStyleWithDetails && q) || that.columnsVisibility.qualityCode
780
+ ? {
781
+ el: (React.createElement("div", { key: "q", style: {
782
+ ...styles.cellRole,
783
+ width: that.width !== 'xs' ? colWidth('qualityCode') : undefined,
784
+ }, title: q || '' }, q)),
785
+ type: 'quality',
786
+ }
787
+ : null,
788
+ (narrowStyleWithDetails && checkVisibleObjectType && that.states[id]?.ts) ||
789
+ that.columnsVisibility.timestamp
790
+ ? {
791
+ el: (React.createElement("div", { key: "ts", style: {
792
+ ...styles.cellRole,
793
+ width: that.width !== 'xs' ? colWidth('timestamp') : undefined,
794
+ } }, checkVisibleObjectType && that.states[id]?.ts
795
+ ? Utils.formatDate(new Date(that.states[id].ts), that.props.dateFormat ||
796
+ that.systemConfig?.common.dateFormat ||
797
+ DEFAULT_DATE_FORMAT)
798
+ : null)),
799
+ type: 'ts',
800
+ }
801
+ : null,
802
+ (narrowStyleWithDetails && checkVisibleObjectType && that.states[id]?.lc) ||
803
+ that.columnsVisibility.lastChange
804
+ ? {
805
+ el: (React.createElement("div", { key: "lc", style: {
806
+ ...styles.cellRole,
807
+ width: that.width !== 'xs' ? colWidth('lastChange') : undefined,
808
+ } }, checkVisibleObjectType && that.states[id]?.lc
809
+ ? Utils.formatDate(new Date(that.states[id].lc), that.props.dateFormat ||
810
+ that.systemConfig?.common.dateFormat ||
811
+ DEFAULT_DATE_FORMAT)
812
+ : null)),
813
+ type: 'lc',
814
+ }
815
+ : null,
816
+ ];
817
+ }
818
+ let colCustom = that.adapterColumns?.map(it => (React.createElement("div", { style: {
819
+ ...styles.cellAdapter,
820
+ width: that.width !== 'xs' ? colWidth(it.id) : undefined,
821
+ }, key: it.id, title: `${it.adapter} => ${it.pathText}` }, obj ? renderCustomValue(that, obj, it, item) : null))) || null;
822
+ const columnValue = narrowStyleWithDetails || that.columnsVisibility.val
823
+ ? renderColumnValue(that, id, item, narrowStyleWithDetails)
824
+ : null;
825
+ let colValue = (narrowStyleWithDetails && columnValue) || that.columnsVisibility.val ? (React.createElement("div", { style: {
826
+ ...styles.cellValue,
827
+ width: that.width !== 'xs' ? colWidth('val') : 'calc(100% - 100px)',
828
+ cursor: valueEditable
829
+ ? common?.type === 'file'
830
+ ? 'zoom-in'
831
+ : item.data.button
832
+ ? 'grab'
833
+ : 'text'
834
+ : 'default',
835
+ }, onClick: e => {
836
+ if (valueEditable) {
837
+ if (!obj || !that.states) {
838
+ // return;
839
+ }
840
+ else if (common?.type === 'file') {
841
+ that.setState({ viewFileDialog: id });
842
+ }
843
+ else if (item.data.url && e.ctrlKey) {
844
+ if (that.states[id]?.val && typeof that.states[id].val === 'string') {
845
+ if (common?.role === 'url.self') {
846
+ window.location.href = that.states[id].val;
847
+ }
848
+ else {
849
+ const opened = window.open(that.states[id].val, '_blank');
850
+ opened?.focus();
851
+ }
852
+ }
853
+ }
854
+ else if (!that.state.filter.expertMode && item.data.button) {
855
+ // in non-expert mode control button directly
856
+ that.props.socket
857
+ .setState(id, true)
858
+ .catch(e => window.alert(`Cannot write state "${id}": ${e}`));
859
+ }
860
+ else if (!that.state.filter.expertMode && item.data.switch) {
861
+ // in non-expert mode control switch directly
862
+ that.props.socket
863
+ .setState(id, !that.states[id].val)
864
+ .catch(e => window.alert(`Cannot write state "${id}": ${e}`));
865
+ }
866
+ else {
867
+ that.edit = {
868
+ val: that.states[id] ? that.states[id].val : '',
869
+ q: that.states[id] ? that.states[id].q || 0 : 0,
870
+ ack: false,
871
+ id,
872
+ };
873
+ that.setState({ updateOpened: true });
874
+ }
875
+ }
876
+ else if (common?.role === 'url' || (common?.role === 'url.blank' && e.ctrlKey)) {
877
+ if (that.states[id]?.val && typeof that.states[id].val === 'string') {
878
+ window.open(that.states[id].val, '_blank');
879
+ }
880
+ }
881
+ else if (common?.role === 'url.self' && e.ctrlKey) {
882
+ if (that.states[id]?.val && typeof that.states[id].val === 'string') {
883
+ window.location.href = that.states[id].val;
884
+ }
885
+ }
886
+ } }, columnValue)) : null;
887
+ let colButtons = narrowStyleWithDetails || that.columnsVisibility.buttons ? (React.createElement("div", { style: {
888
+ ...styles.cellButtons,
889
+ width: that.width !== 'xs' ? colWidth('buttons') : undefined,
890
+ } }, renderColumnButtons(that, id, item))) : null;
891
+ let colDetails = null;
892
+ if (that.width === 'xs' && that.state.focused === id) {
893
+ colMiddle = colMiddle.filter(a => a);
894
+ let renderedMiddle;
895
+ if (!colMiddle.length) {
896
+ renderedMiddle = null;
897
+ }
898
+ else {
899
+ renderedMiddle = colMiddle.map(it => {
900
+ if (!it) {
901
+ return null;
902
+ }
903
+ return (React.createElement("div", { key: it.type, style: styles.cellDetailsLine },
904
+ React.createElement("span", { style: styles.cellDetailsName },
905
+ that.texts[it.type],
906
+ ":"),
907
+ it.el,
908
+ React.createElement("div", { style: { flexGrow: 1 } }),
909
+ it.onClick ? (React.createElement(IconEdit, { style: styles.cellCopyButtonInDetails, onClick: () => {
910
+ if (it?.onClick) {
911
+ it.onClick();
912
+ }
913
+ } })) : null));
914
+ });
915
+ }
916
+ if (!colCustom.length) {
917
+ colCustom = null;
918
+ }
919
+ colDetails = (React.createElement(Paper, { style: {
920
+ width: '100%',
921
+ // the padding must be inside of the width, else the row is wider than the table
922
+ boxSizing: 'border-box',
923
+ display: 'flex',
924
+ flexDirection: 'column',
925
+ padding: 10,
926
+ backgroundColor: that.props.theme.palette.mode === 'dark' ? '#333' : '#ccc',
927
+ } },
928
+ React.createElement("div", { style: styles.cellDetailsLine },
929
+ React.createElement("div", { style: { flexGrow: 1 } }),
930
+ React.createElement(IconCopy, { style: styles.cellCopyButtonInDetails, onClick: e => that.onCopy(e, id) })),
931
+ colName && (React.createElement("div", { style: styles.cellDetailsLine },
932
+ React.createElement("span", { style: styles.cellDetailsName },
933
+ that.texts.name,
934
+ ":"),
935
+ colName,
936
+ React.createElement("div", { style: { flexGrow: 1 } }),
937
+ item.data?.title ? (React.createElement(IconCopy, { className: "copyButton", style: styles.cellCopyButtonInDetails, onClick: e => that.onCopy(e, item.data?.title) })) : null)),
938
+ renderedMiddle,
939
+ colCustom && React.createElement("div", { style: styles.cellDetailsLine }, colCustom),
940
+ that.objects[id]?.type === 'state' && (React.createElement("div", { style: styles.cellDetailsLine },
941
+ React.createElement("span", { style: styles.cellDetailsName },
942
+ that.texts.value,
943
+ ":"),
944
+ colValue,
945
+ React.createElement("div", { style: { flexGrow: 1 } }),
946
+ React.createElement(IconCopy, { className: "copyButton", style: styles.cellCopyButtonInDetails, onClick: e => {
947
+ const { valText } = formatValue({
948
+ state: that.states[id],
949
+ obj: that.objects[id],
950
+ texts: that.texts,
951
+ dateFormat: that.props.dateFormat ||
952
+ that.systemConfig?.common.dateFormat ||
953
+ DEFAULT_DATE_FORMAT,
954
+ isFloatComma: that.props.isFloatComma === undefined
955
+ ? (that.systemConfig?.common.isFloatComma ?? true)
956
+ : that.props.isFloatComma,
957
+ });
958
+ that.onCopy(e, valText.c !== undefined ? valText.c : valText.v.toString());
959
+ }, key: "cc" }))),
960
+ colButtons && React.createElement("div", { style: { ...styles.cellDetailsLine, justifyContent: 'right' } }, colButtons)));
961
+ colName = null;
962
+ colMiddle = null;
963
+ colCustom = null;
964
+ colValue = null;
965
+ colButtons = null;
966
+ }
967
+ const row = (React.createElement(Grid, { container: true, direction: "row", wrap: "nowrap", sx: Utils.getStyle(that.props.theme, styles.tableRow, that.state.linesEnabled && styles.tableRowLines, !that.props.dragEnabled && styles.tableRowNoDragging, alias && styles.tableRowAlias, readWriteAlias && styles.tableRowAliasReadWrite, that.state.focused === id && that.props.multiSelect && styles.tableRowFocused, !item.data.visible && styles.filteredOut, item.data.hasVisibleParent &&
968
+ !item.data.visible &&
969
+ !item.data.hasVisibleChildren &&
970
+ styles.filteredParentOut, that.state.selected.includes(id) && styles.itemSelected, that.state.selectedNonObject === id && styles.itemSelected), key: id, id: id, onMouseDown: e => {
971
+ that.onSelect(id);
972
+ let isRightMB;
973
+ if ('which' in e) {
974
+ // Gecko (Firefox), WebKit (Safari/Chrome) & Opera
975
+ isRightMB = e.which === 3;
976
+ }
977
+ else if ('button' in e) {
978
+ // IE, Opera
979
+ isRightMB = e.button === 2;
980
+ }
981
+ if (isRightMB) {
982
+ that.contextMenu = {
983
+ item,
984
+ ts: Date.now(),
985
+ };
986
+ }
987
+ else {
988
+ that.contextMenu = null;
989
+ }
990
+ }, onDoubleClick: () => {
991
+ if (!item.children) {
992
+ that.onSelect(id, true);
993
+ }
994
+ else {
995
+ that.toggleExpanded(id);
996
+ }
997
+ } },
998
+ colID,
999
+ colName,
1000
+ colMiddle?.map(it => it?.el),
1001
+ colCustom,
1002
+ colValue,
1003
+ colButtons));
1004
+ return { row, details: colDetails };
1005
+ }
1006
+ /**
1007
+ * Renders an item.
1008
+ */
1009
+ export function renderItem(that, root, isExpanded, counter) {
1010
+ const items = [];
1011
+ counter = counter || { count: 0 };
1012
+ const result = renderLeaf(that, root, isExpanded, counter);
1013
+ let leaf;
1014
+ const DragWrapper = that.props.DragWrapper;
1015
+ if (that.props.dragEnabled && DragWrapper) {
1016
+ if (root.data.sumVisibility) {
1017
+ leaf = (React.createElement(DragWrapper, { key: root.data.id, item: root, style: styles.draggable }, result.row));
1018
+ }
1019
+ else {
1020
+ // change cursor
1021
+ leaf = (React.createElement("div", { key: root.data.id, style: styles.nonDraggable }, result.row));
1022
+ }
1023
+ }
1024
+ else {
1025
+ leaf = result.row;
1026
+ }
1027
+ if (root.data.id && leaf) {
1028
+ items.push(leaf);
1029
+ }
1030
+ if (result.details) {
1031
+ items.push(result.details);
1032
+ }
1033
+ isExpanded = isExpanded === undefined ? binarySearch(that.state.expanded, root.data.id) : isExpanded;
1034
+ if (!root.data.id || isExpanded) {
1035
+ if (!that.state.foldersFirst) {
1036
+ if (root.children) {
1037
+ items.push(root.children.map(item => {
1038
+ // do not render too many items in column editor mode
1039
+ if (!that.state.columnsSelectorShow || counter.count < 15) {
1040
+ if (item.data.sumVisibility) {
1041
+ return renderItem(that, item, undefined, counter);
1042
+ }
1043
+ }
1044
+ return null;
1045
+ }));
1046
+ }
1047
+ }
1048
+ else if (root.children) {
1049
+ // first only folder
1050
+ items.push(root.children.map(item => {
1051
+ if (item.children) {
1052
+ // do not render too many items in column editor mode
1053
+ if (!that.state.columnsSelectorShow || counter.count < 15) {
1054
+ if (item.data.sumVisibility) {
1055
+ return renderItem(that, item, undefined, counter);
1056
+ }
1057
+ }
1058
+ }
1059
+ return null;
1060
+ }));
1061
+ // then items
1062
+ items.push(root.children.map(item => {
1063
+ if (!item.children) {
1064
+ // do not render too many items in column editor mode
1065
+ if (!that.state.columnsSelectorShow || counter.count < 15) {
1066
+ if (item.data.sumVisibility) {
1067
+ return renderItem(that, item, undefined, counter);
1068
+ }
1069
+ }
1070
+ }
1071
+ return null;
1072
+ }));
1073
+ }
1074
+ }
1075
+ return items;
1076
+ }
1077
+ //# sourceMappingURL=renderLeaf.js.map