@iobroker/adapter-react-v5 7.0.2 → 7.1.1
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/Components/404.d.ts +3 -2
- package/Components/404.js +3 -2
- package/Components/ColorPicker.d.ts +22 -8
- package/Components/ColorPicker.js +34 -17
- package/Components/ComplexCron.js +24 -24
- package/Components/CopyToClipboard.d.ts +10 -1
- package/Components/CopyToClipboard.js +17 -8
- package/Components/CustomModal.d.ts +1 -1
- package/Components/CustomModal.js +8 -8
- package/Components/FileBrowser.d.ts +11 -11
- package/Components/FileBrowser.js +135 -152
- package/Components/FileViewer.js +34 -23
- package/Components/Icon.d.ts +16 -2
- package/Components/Icon.js +19 -8
- package/Components/IconPicker.js +10 -14
- package/Components/IconSelector.d.ts +1 -1
- package/Components/IconSelector.js +64 -74
- package/Components/Image.d.ts +8 -4
- package/Components/Image.js +13 -32
- package/Components/Loader.d.ts +2 -2
- package/Components/Loader.js +21 -18
- package/Components/Loaders/MV.d.ts +6 -1
- package/Components/Loaders/MV.js +23 -7
- package/Components/Loaders/PT.d.ts +7 -2
- package/Components/Loaders/PT.js +20 -7
- package/Components/Loaders/Vendor.d.ts +2 -2
- package/Components/Loaders/Vendor.js +15 -7
- package/Components/Logo.js +16 -18
- package/Components/MDUtils.d.ts +1 -1
- package/Components/MDUtils.js +8 -4
- package/Components/ObjectBrowser.d.ts +40 -39
- package/Components/ObjectBrowser.js +550 -435
- package/Components/Router.d.ts +1 -3
- package/Components/Router.js +3 -1
- package/Components/SaveCloseButtons.d.ts +3 -3
- package/Components/SaveCloseButtons.js +3 -3
- package/Components/Schedule.d.ts +15 -15
- package/Components/Schedule.js +177 -154
- package/Components/SelectWithIcon.d.ts +2 -2
- package/Components/SelectWithIcon.js +45 -34
- package/Components/SimpleCron/index.js +83 -43
- package/Components/TabContainer.js +2 -2
- package/Components/TabContent.js +1 -1
- package/Components/TabHeader.js +1 -1
- package/Components/TableResize.d.ts +2 -2
- package/Components/TableResize.js +5 -5
- package/Components/TextWithIcon.d.ts +1 -1
- package/Components/TextWithIcon.js +10 -8
- package/Components/ToggleThemeMenu.d.ts +2 -2
- package/Components/ToggleThemeMenu.js +3 -3
- package/Components/TreeTable.d.ts +18 -18
- package/Components/TreeTable.js +76 -72
- package/Components/UploadImage.d.ts +2 -2
- package/Components/UploadImage.js +25 -21
- package/Components/Utils.d.ts +42 -22
- package/Components/Utils.js +66 -65
- package/Components/withWidth.d.ts +2 -2
- package/Components/withWidth.js +10 -6
- package/Dialogs/ComplexCron.d.ts +2 -2
- package/Dialogs/ComplexCron.js +3 -3
- package/Dialogs/Confirm.d.ts +4 -4
- package/Dialogs/Confirm.js +18 -8
- package/Dialogs/Cron.d.ts +3 -3
- package/Dialogs/Cron.js +21 -17
- package/Dialogs/Error.d.ts +3 -3
- package/Dialogs/Error.js +6 -4
- package/Dialogs/Message.d.ts +3 -3
- package/Dialogs/Message.js +6 -4
- package/Dialogs/SelectFile.d.ts +4 -4
- package/Dialogs/SelectFile.js +6 -4
- package/Dialogs/SelectID.d.ts +12 -10
- package/Dialogs/SelectID.js +12 -8
- package/Dialogs/SimpleCron.d.ts +2 -2
- package/Dialogs/SimpleCron.js +2 -2
- package/Dialogs/TextInput.d.ts +2 -2
- package/Dialogs/TextInput.js +3 -3
- package/GenericApp.d.ts +19 -13
- package/GenericApp.js +128 -85
- package/LegacyConnection.d.ts +240 -248
- package/LegacyConnection.js +500 -525
- package/README.md +1264 -1171
- package/Theme.d.ts +1 -1
- package/Theme.js +9 -12
- package/assets/devices.json +1 -0
- package/assets/rooms.json +1 -0
- package/craco-module-federation.js +3 -12
- package/i18n/de.json +434 -434
- package/i18n/en.json +434 -434
- package/i18n/es.json +434 -434
- package/i18n/fr.json +434 -434
- package/i18n/it.json +434 -434
- package/i18n/nl.json +434 -434
- package/i18n/pl.json +434 -434
- package/i18n/pt.json +434 -434
- package/i18n/ru.json +434 -434
- package/i18n/uk.json +434 -434
- package/i18n/zh-cn.json +434 -434
- package/i18n.d.ts +26 -19
- package/i18n.js +28 -22
- package/icons/IconAdapter.js +2 -2
- package/icons/IconAlias.js +2 -2
- package/icons/IconChannel.js +2 -2
- package/icons/IconClearFilter.js +2 -2
- package/icons/IconClosed.js +2 -2
- package/icons/IconCopy.js +2 -2
- package/icons/IconDevice.js +2 -2
- package/icons/IconDocument.js +2 -2
- package/icons/IconDocumentReadOnly.js +2 -2
- package/icons/IconExpert.js +2 -2
- package/icons/IconFx.js +2 -2
- package/icons/IconInstance.js +2 -2
- package/icons/IconLogout.js +2 -2
- package/icons/IconNoIcon.js +2 -2
- package/icons/IconOpen.d.ts +2 -2
- package/icons/IconOpen.js +2 -2
- package/icons/IconProps.d.ts +4 -3
- package/icons/IconState.d.ts +2 -2
- package/icons/IconState.js +2 -2
- package/index.css +3 -2
- package/package.json +4 -4
- package/src/Components/404.tsx +32 -31
- package/src/Components/ColorPicker.tsx +142 -114
- package/src/Components/ComplexCron.tsx +174 -137
- package/src/Components/CopyToClipboard.tsx +22 -9
- package/src/Components/CustomModal.tsx +76 -69
- package/src/Components/FileBrowser.tsx +959 -852
- package/src/Components/FileViewer.tsx +146 -127
- package/src/Components/Icon.tsx +80 -52
- package/src/Components/IconPicker.tsx +83 -67
- package/src/Components/IconSelector.tsx +159 -141
- package/src/Components/Image.tsx +43 -26
- package/src/Components/Loader.tsx +56 -32
- package/src/Components/Logo.tsx +62 -52
- package/src/Components/MDUtils.tsx +10 -6
- package/src/Components/ObjectBrowser.tsx +3198 -2478
- package/src/Components/Router.tsx +11 -11
- package/src/Components/SaveCloseButtons.tsx +43 -39
- package/src/Components/Schedule.tsx +1091 -853
- package/src/Components/SelectWithIcon.tsx +135 -93
- package/src/Components/TabContainer.tsx +22 -20
- package/src/Components/TabContent.tsx +13 -12
- package/src/Components/TabHeader.tsx +10 -9
- package/src/Components/TableResize.tsx +52 -37
- package/src/Components/TextWithIcon.tsx +30 -19
- package/src/Components/ToggleThemeMenu.tsx +31 -13
- package/src/Components/TreeTable.tsx +468 -385
- package/src/Components/UploadImage.tsx +153 -121
- package/src/Components/Utils.tsx +135 -127
- package/src/Components/loader.css +40 -31
- package/src/Components/withWidth.tsx +23 -12
- package/src/Connection.tsx +1 -3
- package/src/Dialogs/ComplexCron.tsx +55 -61
- package/src/Dialogs/Confirm.tsx +88 -65
- package/src/Dialogs/Cron.tsx +122 -112
- package/src/Dialogs/Error.tsx +37 -42
- package/src/Dialogs/Message.tsx +39 -37
- package/src/Dialogs/SelectFile.tsx +95 -85
- package/src/Dialogs/SelectID.tsx +141 -129
- package/src/Dialogs/SimpleCron.tsx +44 -44
- package/src/Dialogs/TextInput.tsx +60 -68
- package/src/GenericApp.tsx +342 -242
- package/src/LegacyConnection.tsx +972 -842
- package/src/Prompt.tsx +3 -1
- package/src/Theme.tsx +19 -26
- package/src/icons/IconAdapter.tsx +16 -14
- package/src/icons/IconAlias.tsx +16 -14
- package/src/icons/IconChannel.tsx +55 -16
- package/src/icons/IconClearFilter.tsx +17 -15
- package/src/icons/IconClosed.tsx +16 -11
- package/src/icons/IconCopy.tsx +16 -11
- package/src/icons/IconDevice.tsx +121 -22
- package/src/icons/IconDocument.tsx +16 -11
- package/src/icons/IconDocumentReadOnly.tsx +21 -12
- package/src/icons/IconExpert.tsx +20 -12
- package/src/icons/IconFx.tsx +16 -14
- package/src/icons/IconInstance.tsx +16 -14
- package/src/icons/IconLogout.tsx +20 -18
- package/src/icons/IconNoIcon.tsx +16 -14
- package/src/icons/IconOpen.tsx +17 -12
- package/src/icons/IconProps.tsx +4 -3
- package/src/icons/IconState.tsx +34 -13
- package/src/index.css +3 -2
- package/tasks.js +91 -0
- package/types.d.ts +141 -0
- package/Components/Loaders/PT.css +0 -109
- package/Components/Loaders/Vendor.css +0 -13
- package/Components/loader.css +0 -222
- package/Components/types.d.ts +0 -82
- package/assets/devices/Alarm Systems.svg +0 -19
- package/assets/devices/Amplifier.svg +0 -22
- package/assets/devices/Awnings.svg +0 -5
- package/assets/devices/Battery Status.svg +0 -5
- package/assets/devices/Ceiling Spotlights.svg +0 -16
- package/assets/devices/Chandelier.svg +0 -7
- package/assets/devices/Climate.svg +0 -12
- package/assets/devices/Coffee Makers.svg +0 -6
- package/assets/devices/Cold Water.svg +0 -31
- package/assets/devices/Computer.svg +0 -21
- package/assets/devices/Consumption.svg +0 -8
- package/assets/devices/Curtains.svg +0 -43
- package/assets/devices/Dishwashers.svg +0 -12
- package/assets/devices/Doors.svg +0 -6
- package/assets/devices/Doorstep.svg +0 -35
- package/assets/devices/Dryer.svg +0 -14
- package/assets/devices/Fan.svg +0 -20
- package/assets/devices/Floor Lamps.svg +0 -5
- package/assets/devices/Garage Doors.svg +0 -9
- package/assets/devices/Gates.svg +0 -32
- package/assets/devices/Hairdryer.svg +0 -23
- package/assets/devices/Handle.svg +0 -6
- package/assets/devices/Hanging Lamps.svg +0 -9
- package/assets/devices/Heater.svg +0 -44
- package/assets/devices/Hoods.svg +0 -12
- package/assets/devices/Hot Water.svg +0 -10
- package/assets/devices/Humidity.svg +0 -41
- package/assets/devices/Iron.svg +0 -5
- package/assets/devices/Irrigation.svg +0 -23
- package/assets/devices/Led Strip.svg +0 -31
- package/assets/devices/Light.svg +0 -30
- package/assets/devices/Lightings.svg +0 -46
- package/assets/devices/Lock.svg +0 -19
- package/assets/devices/Louvre.svg +0 -7
- package/assets/devices/Mowing Machine.svg +0 -9
- package/assets/devices/Music.svg +0 -13
- package/assets/devices/Outdoor Blinds.svg +0 -7
- package/assets/devices/People.svg +0 -19
- package/assets/devices/Pool.svg +0 -8
- package/assets/devices/Power Consumption.svg +0 -13
- package/assets/devices/Printer.svg +0 -10
- package/assets/devices/Pump.svg +0 -10
- package/assets/devices/Receiver.svg +0 -19
- package/assets/devices/Sconces.svg +0 -10
- package/assets/devices/Security.svg +0 -34
- package/assets/devices/Shading.svg +0 -5
- package/assets/devices/Shutters.svg +0 -11
- package/assets/devices/SmokeDetector.svg +0 -13
- package/assets/devices/Sockets.svg +0 -13
- package/assets/devices/Speaker.svg +0 -35
- package/assets/devices/Stove.svg +0 -12
- package/assets/devices/Table Lamps.svg +0 -12
- package/assets/devices/Temperature Sensors.svg +0 -28
- package/assets/devices/Tv.svg +0 -8
- package/assets/devices/Vacuum Cleaner.svg +0 -16
- package/assets/devices/Ventilation.svg +0 -12
- package/assets/devices/Washing Machines.svg +0 -16
- package/assets/devices/Water Consumption.svg +0 -6
- package/assets/devices/Water Heater.svg +0 -8
- package/assets/devices/Water.svg +0 -40
- package/assets/devices/Weather.svg +0 -28
- package/assets/devices/Window.svg +0 -8
- package/assets/rooms/Anteroom.svg +0 -53
- package/assets/rooms/Attic.svg +0 -21
- package/assets/rooms/Balcony.svg +0 -13
- package/assets/rooms/Barn.svg +0 -6
- package/assets/rooms/Basement.svg +0 -5
- package/assets/rooms/Bathroom.svg +0 -38
- package/assets/rooms/Bedroom.svg +0 -5
- package/assets/rooms/Boiler Room.svg +0 -13
- package/assets/rooms/Carport.svg +0 -17
- package/assets/rooms/Cellar.svg +0 -89
- package/assets/rooms/Chamber.svg +0 -9
- package/assets/rooms/Corridor.svg +0 -53
- package/assets/rooms/Dining Area.svg +0 -37
- package/assets/rooms/Dining Room.svg +0 -37
- package/assets/rooms/Dining.svg +0 -37
- package/assets/rooms/Dressing Room.svg +0 -5
- package/assets/rooms/Driveway.svg +0 -15
- package/assets/rooms/Entrance.svg +0 -44
- package/assets/rooms/Equipment Room.svg +0 -15
- package/assets/rooms/Front Yard.svg +0 -64
- package/assets/rooms/Gallery.svg +0 -14
- package/assets/rooms/Garage.svg +0 -20
- package/assets/rooms/Garden.svg +0 -13
- package/assets/rooms/Ground Floor.svg +0 -95
- package/assets/rooms/Guest Bathroom.svg +0 -33
- package/assets/rooms/Guest Room.svg +0 -5
- package/assets/rooms/Gym.svg +0 -5
- package/assets/rooms/Hall.svg +0 -19
- package/assets/rooms/Home Theater.svg +0 -8
- package/assets/rooms/Kitchen.svg +0 -18
- package/assets/rooms/Laundry Room.svg +0 -12
- package/assets/rooms/Living Area.svg +0 -11
- package/assets/rooms/Living Room.svg +0 -10
- package/assets/rooms/Locker Room.svg +0 -17
- package/assets/rooms/Nursery.svg +0 -5
- package/assets/rooms/Office.svg +0 -8
- package/assets/rooms/Outdoors.svg +0 -7
- package/assets/rooms/Playroom.svg +0 -6
- package/assets/rooms/Pool.svg +0 -8
- package/assets/rooms/Rear Wall.svg +0 -30
- package/assets/rooms/Second Floor.svg +0 -95
- package/assets/rooms/Shed.svg +0 -16
- package/assets/rooms/Sleeping Area.svg +0 -22
- package/assets/rooms/Stairway.svg +0 -5
- package/assets/rooms/Stairwell.svg +0 -15
- package/assets/rooms/Storeroom.svg +0 -5
- package/assets/rooms/Summer House.svg +0 -27
- package/assets/rooms/Swimming Pool.svg +0 -21
- package/assets/rooms/Terrace.svg +0 -7
- package/assets/rooms/Toilet.svg +0 -10
- package/assets/rooms/Upstairs.svg +0 -6
- package/assets/rooms/Wardrobe.svg +0 -60
- package/assets/rooms/Washroom.svg +0 -20
- package/assets/rooms/Wc.svg +0 -10
- package/assets/rooms/Windscreen.svg +0 -60
- package/assets/rooms/Workshop.svg +0 -23
- package/assets/rooms/Workspace.svg +0 -8
package/src/GenericApp.tsx
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* MIT License
|
|
5
5
|
*
|
|
6
|
-
|
|
7
|
-
import React from 'react';
|
|
8
|
-
import { PROGRESS, Connection, AdminConnection } from '@iobroker/socket-client';
|
|
6
|
+
*/
|
|
7
|
+
import React, { type JSX } from 'react';
|
|
8
|
+
import { PROGRESS, Connection, type AdminConnection } from '@iobroker/socket-client';
|
|
9
9
|
import * as Sentry from '@sentry/browser';
|
|
10
10
|
|
|
11
11
|
import { Snackbar, IconButton } from '@mui/material';
|
|
@@ -21,7 +21,7 @@ import SaveCloseButtons from './Components/SaveCloseButtons';
|
|
|
21
21
|
import ConfirmDialog from './Dialogs/Confirm';
|
|
22
22
|
import I18n from './i18n';
|
|
23
23
|
import DialogError from './Dialogs/Error';
|
|
24
|
-
import {
|
|
24
|
+
import type {
|
|
25
25
|
GenericAppProps,
|
|
26
26
|
GenericAppState,
|
|
27
27
|
GenericAppSettings,
|
|
@@ -31,6 +31,18 @@ import {
|
|
|
31
31
|
Width,
|
|
32
32
|
} from './types';
|
|
33
33
|
|
|
34
|
+
import langEn from './i18n/en.json';
|
|
35
|
+
import langDe from './i18n/de.json';
|
|
36
|
+
import langRu from './i18n/ru.json';
|
|
37
|
+
import langPt from './i18n/pt.json';
|
|
38
|
+
import langNl from './i18n/nl.json';
|
|
39
|
+
import langFr from './i18n/fr.json';
|
|
40
|
+
import langIt from './i18n/it.json';
|
|
41
|
+
import langEs from './i18n/es.json';
|
|
42
|
+
import langPl from './i18n/pl.json';
|
|
43
|
+
import langUk from './i18n/uk.json';
|
|
44
|
+
import langZhCn from './i18n/zh-cn.json';
|
|
45
|
+
|
|
34
46
|
declare global {
|
|
35
47
|
/** If config has been changed */
|
|
36
48
|
// eslint-disable-next-line no-var
|
|
@@ -101,7 +113,10 @@ body {
|
|
|
101
113
|
}
|
|
102
114
|
`;
|
|
103
115
|
|
|
104
|
-
class GenericApp<
|
|
116
|
+
class GenericApp<
|
|
117
|
+
TProps extends GenericAppProps = GenericAppProps,
|
|
118
|
+
TState extends GenericAppState = GenericAppState,
|
|
119
|
+
> extends Router<TProps, TState> {
|
|
105
120
|
protected socket: AdminConnection;
|
|
106
121
|
|
|
107
122
|
protected readonly instance: number;
|
|
@@ -134,7 +149,9 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
134
149
|
private resizeTimer: ReturnType<typeof setTimeout> | null = null;
|
|
135
150
|
|
|
136
151
|
constructor(props: TProps, settings?: GenericAppSettings) {
|
|
137
|
-
const ConnectionClass = (props.Connection ||
|
|
152
|
+
const ConnectionClass = (props.Connection ||
|
|
153
|
+
settings?.Connection ||
|
|
154
|
+
Connection) as unknown as typeof AdminConnection;
|
|
138
155
|
// const ConnectionClass = props.Connection === 'admin' || settings.Connection = 'admin' ? AdminConnection : (props.Connection || settings.Connection || Connection);
|
|
139
156
|
|
|
140
157
|
if (!window.document.getElementById('generic-app-iobroker-component')) {
|
|
@@ -150,7 +167,7 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
150
167
|
const io = new window.SocketClient();
|
|
151
168
|
delete window.io;
|
|
152
169
|
window.io = io;
|
|
153
|
-
} catch
|
|
170
|
+
} catch {
|
|
154
171
|
// ignore
|
|
155
172
|
}
|
|
156
173
|
}
|
|
@@ -161,78 +178,98 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
161
178
|
|
|
162
179
|
const query = (window.location.search || '').replace(/^\?/, '').replace(/#.*$/, '');
|
|
163
180
|
const args: Record<string, string | boolean> = {};
|
|
164
|
-
query
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
args[parts[0]] =
|
|
171
|
-
|
|
172
|
-
|
|
181
|
+
query
|
|
182
|
+
.trim()
|
|
183
|
+
.split('&')
|
|
184
|
+
.filter(t => t.trim())
|
|
185
|
+
.forEach(b => {
|
|
186
|
+
const parts = b.split('=');
|
|
187
|
+
args[parts[0]] = parts.length === 2 ? parts[1] : true;
|
|
188
|
+
if (args[parts[0]] === 'true') {
|
|
189
|
+
args[parts[0]] = true;
|
|
190
|
+
} else if (args[parts[0]] === 'false') {
|
|
191
|
+
args[parts[0]] = false;
|
|
192
|
+
}
|
|
193
|
+
});
|
|
173
194
|
|
|
174
195
|
// extract instance from URL
|
|
175
|
-
this.instance =
|
|
196
|
+
this.instance =
|
|
197
|
+
settings?.instance ??
|
|
198
|
+
props.instance ??
|
|
199
|
+
(args.instance !== undefined
|
|
200
|
+
? parseInt(args.instance as string, 10) || 0
|
|
201
|
+
: parseInt(window.location.search.slice(1), 10) || 0);
|
|
176
202
|
// extract adapter name from URL
|
|
177
203
|
const tmp = window.location.pathname.split('/');
|
|
178
|
-
this.adapterName =
|
|
179
|
-
|
|
204
|
+
this.adapterName =
|
|
205
|
+
settings?.adapterName || props.adapterName || window.adapterName || tmp[tmp.length - 2] || 'iot';
|
|
206
|
+
this.instanceId = `system.adapter.${this.adapterName}.${this.instance}`;
|
|
180
207
|
this.newReact = args.newReact === true; // it is admin5
|
|
181
208
|
|
|
182
209
|
const location = Router.getLocation();
|
|
183
|
-
location.tab =
|
|
210
|
+
location.tab =
|
|
211
|
+
location.tab ||
|
|
212
|
+
((window as any)._localStorage || window.localStorage).getItem(`${this.adapterName}-adapter`) ||
|
|
213
|
+
'';
|
|
184
214
|
|
|
185
215
|
const themeInstance = this.createTheme();
|
|
186
216
|
|
|
187
217
|
this.state = {
|
|
188
218
|
...(this.state || {}), // keep the existing state
|
|
189
|
-
selectedTab:
|
|
219
|
+
selectedTab:
|
|
220
|
+
((window as any)._localStorage || window.localStorage).getItem(`${this.adapterName}-adapter`) || '',
|
|
190
221
|
selectedTabNum: -1,
|
|
191
|
-
native:
|
|
192
|
-
errorText:
|
|
193
|
-
changed:
|
|
194
|
-
connected:
|
|
195
|
-
loaded:
|
|
222
|
+
native: {},
|
|
223
|
+
errorText: '',
|
|
224
|
+
changed: false,
|
|
225
|
+
connected: false,
|
|
226
|
+
loaded: false,
|
|
196
227
|
isConfigurationError: '',
|
|
197
|
-
expertMode:
|
|
198
|
-
toast:
|
|
199
|
-
theme:
|
|
200
|
-
themeName:
|
|
201
|
-
themeType:
|
|
202
|
-
bottomButtons:
|
|
203
|
-
width:
|
|
204
|
-
confirmClose:
|
|
205
|
-
_alert:
|
|
206
|
-
_alertType:
|
|
207
|
-
_alertMessage:
|
|
228
|
+
expertMode: false,
|
|
229
|
+
toast: '',
|
|
230
|
+
theme: themeInstance,
|
|
231
|
+
themeName: this.getThemeName(themeInstance),
|
|
232
|
+
themeType: this.getThemeType(themeInstance),
|
|
233
|
+
bottomButtons: (settings && settings.bottomButtons) === false ? false : props?.bottomButtons !== false,
|
|
234
|
+
width: GenericApp.getWidth(),
|
|
235
|
+
confirmClose: false,
|
|
236
|
+
_alert: false,
|
|
237
|
+
_alertType: 'info',
|
|
238
|
+
_alertMessage: '',
|
|
208
239
|
} satisfies GenericAppState as TState;
|
|
209
240
|
|
|
210
241
|
// init translations
|
|
211
242
|
const translations: Record<ioBroker.Languages, Record<string, string>> = {
|
|
212
|
-
en:
|
|
213
|
-
de:
|
|
214
|
-
ru:
|
|
215
|
-
pt:
|
|
216
|
-
nl:
|
|
217
|
-
fr:
|
|
218
|
-
it:
|
|
219
|
-
es:
|
|
220
|
-
pl:
|
|
221
|
-
uk:
|
|
222
|
-
'zh-cn':
|
|
243
|
+
en: langEn,
|
|
244
|
+
de: langDe,
|
|
245
|
+
ru: langRu,
|
|
246
|
+
pt: langPt,
|
|
247
|
+
nl: langNl,
|
|
248
|
+
fr: langFr,
|
|
249
|
+
it: langIt,
|
|
250
|
+
es: langEs,
|
|
251
|
+
pl: langPl,
|
|
252
|
+
uk: langUk,
|
|
253
|
+
'zh-cn': langZhCn,
|
|
223
254
|
};
|
|
224
255
|
|
|
225
256
|
// merge together
|
|
226
257
|
if (settings && settings.translations) {
|
|
227
258
|
Object.keys(settings.translations).forEach(lang => {
|
|
228
259
|
if (settings.translations) {
|
|
229
|
-
translations[lang as ioBroker.Languages] = Object.assign(
|
|
260
|
+
translations[lang as ioBroker.Languages] = Object.assign(
|
|
261
|
+
translations[lang as ioBroker.Languages],
|
|
262
|
+
settings.translations[lang as ioBroker.Languages] || {},
|
|
263
|
+
);
|
|
230
264
|
}
|
|
231
265
|
});
|
|
232
266
|
} else if (props.translations) {
|
|
233
267
|
Object.keys(props.translations).forEach(lang => {
|
|
234
268
|
if (props.translations) {
|
|
235
|
-
translations[lang as ioBroker.Languages] = Object.assign(
|
|
269
|
+
translations[lang as ioBroker.Languages] = Object.assign(
|
|
270
|
+
translations[lang as ioBroker.Languages],
|
|
271
|
+
props.translations[lang as ioBroker.Languages] || {},
|
|
272
|
+
);
|
|
236
273
|
}
|
|
237
274
|
});
|
|
238
275
|
}
|
|
@@ -288,18 +325,25 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
288
325
|
I18n.setLanguage(this.socket.systemLang);
|
|
289
326
|
|
|
290
327
|
// subscribe because of language and expert mode
|
|
291
|
-
this.socket
|
|
328
|
+
this.socket
|
|
329
|
+
.subscribeObject('system.config', this.onSystemConfigChanged)
|
|
292
330
|
.then(() => this.getSystemConfig())
|
|
293
331
|
.then(obj => {
|
|
294
|
-
this._secret =
|
|
332
|
+
this._secret =
|
|
333
|
+
(typeof obj !== 'undefined' && obj.native && obj.native.secret) || 'Zgfr56gFe87jJOM';
|
|
295
334
|
this._systemConfig = obj?.common || ({} as ioBroker.SystemConfigCommon);
|
|
296
335
|
return this.socket.getObject(this.instanceId);
|
|
297
336
|
})
|
|
298
337
|
.then(async obj => {
|
|
299
338
|
let waitPromise;
|
|
300
|
-
const instanceObj: ioBroker.InstanceObject | null | undefined = obj as
|
|
339
|
+
const instanceObj: ioBroker.InstanceObject | null | undefined = obj as
|
|
340
|
+
| ioBroker.InstanceObject
|
|
341
|
+
| null
|
|
342
|
+
| undefined;
|
|
301
343
|
|
|
302
|
-
const sentryPluginEnabled = (
|
|
344
|
+
const sentryPluginEnabled = (
|
|
345
|
+
await this.socket.getState(`${this.instanceId}.plugins.sentry.enabled`)
|
|
346
|
+
)?.val;
|
|
303
347
|
|
|
304
348
|
const sentryEnabled =
|
|
305
349
|
sentryPluginEnabled !== false &&
|
|
@@ -309,7 +353,7 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
309
353
|
instanceObj.common.version &&
|
|
310
354
|
// @ts-expect-error will be extended in js-controller TODO: (BF: 2024.05.30) this is redundant to state `${this.instanceId}.plugins.sentry.enabled`, remove this in future when admin sets the state correctly
|
|
311
355
|
!instanceObj.common.disableDataReporting &&
|
|
312
|
-
|
|
356
|
+
window.location.host !== 'localhost:3000';
|
|
313
357
|
|
|
314
358
|
// activate sentry plugin
|
|
315
359
|
if (!this.sentryStarted && this.sentryDSN && sentryEnabled) {
|
|
@@ -318,9 +362,7 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
318
362
|
Sentry.init({
|
|
319
363
|
dsn: this.sentryDSN,
|
|
320
364
|
release: `iobroker.${instanceObj.common.name}@${instanceObj.common.version}`,
|
|
321
|
-
integrations: [
|
|
322
|
-
Sentry.dedupeIntegration(),
|
|
323
|
-
],
|
|
365
|
+
integrations: [Sentry.dedupeIntegration()],
|
|
324
366
|
});
|
|
325
367
|
|
|
326
368
|
console.log('Sentry initialized');
|
|
@@ -331,37 +373,37 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
331
373
|
if (!this.sentryInited && sentryEnabled) {
|
|
332
374
|
this.sentryInited = true;
|
|
333
375
|
|
|
334
|
-
waitPromise = this.socket.getObject('system.meta.uuid')
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
});
|
|
376
|
+
waitPromise = this.socket.getObject('system.meta.uuid').then(uuidObj => {
|
|
377
|
+
if (uuidObj && uuidObj.native && uuidObj.native.uuid) {
|
|
378
|
+
const scope = Sentry.getCurrentScope();
|
|
379
|
+
scope.setUser({ id: uuidObj.native.uuid });
|
|
380
|
+
}
|
|
381
|
+
});
|
|
341
382
|
}
|
|
342
383
|
|
|
343
384
|
waitPromise = waitPromise || Promise.resolve();
|
|
344
385
|
|
|
345
|
-
waitPromise
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
)
|
|
363
|
-
|
|
364
|
-
}
|
|
386
|
+
void waitPromise.then(() => {
|
|
387
|
+
if (instanceObj) {
|
|
388
|
+
this.common = instanceObj?.common;
|
|
389
|
+
this.onPrepareLoad(instanceObj.native, instanceObj.encryptedNative); // decode all secrets
|
|
390
|
+
this.savedNative = JSON.parse(JSON.stringify(instanceObj.native));
|
|
391
|
+
this.setState(
|
|
392
|
+
{ native: instanceObj.native, loaded: true, expertMode: this.getExpertMode() },
|
|
393
|
+
() => this.onConnectionReady && this.onConnectionReady(),
|
|
394
|
+
);
|
|
395
|
+
} else {
|
|
396
|
+
console.warn('Cannot load instance settings');
|
|
397
|
+
this.setState(
|
|
398
|
+
{
|
|
399
|
+
native: {},
|
|
400
|
+
loaded: true,
|
|
401
|
+
expertMode: this.getExpertMode(),
|
|
402
|
+
},
|
|
403
|
+
() => this.onConnectionReady && this.onConnectionReady(),
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
});
|
|
365
407
|
})
|
|
366
408
|
.catch(e => window.alert(`Cannot settings: ${e}`));
|
|
367
409
|
},
|
|
@@ -374,13 +416,14 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
374
416
|
|
|
375
417
|
/**
|
|
376
418
|
* Checks if this connection is running in a web adapter and not in an admin.
|
|
419
|
+
*
|
|
377
420
|
* @returns True if running in a web adapter or in a socketio adapter.
|
|
378
421
|
*/
|
|
379
422
|
static isWeb(): boolean {
|
|
380
423
|
return window.socketUrl !== undefined;
|
|
381
424
|
}
|
|
382
425
|
|
|
383
|
-
showAlert(message: string, type?: 'info' | 'warning' | 'error' | 'success') {
|
|
426
|
+
showAlert(message: string, type?: 'info' | 'warning' | 'error' | 'success'): void {
|
|
384
427
|
if (type !== 'error' && type !== 'warning' && type !== 'info' && type !== 'success') {
|
|
385
428
|
type = 'info';
|
|
386
429
|
}
|
|
@@ -392,21 +435,27 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
392
435
|
});
|
|
393
436
|
}
|
|
394
437
|
|
|
395
|
-
renderAlertSnackbar() {
|
|
438
|
+
renderAlertSnackbar(): JSX.Element {
|
|
396
439
|
this.alertDialogRendered = true;
|
|
397
440
|
|
|
398
|
-
return
|
|
399
|
-
|
|
400
|
-
{
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
441
|
+
return (
|
|
442
|
+
<Snackbar
|
|
443
|
+
style={
|
|
444
|
+
this.state._alertType === 'error'
|
|
445
|
+
? { backgroundColor: '#f44336' }
|
|
446
|
+
: this.state._alertType === 'success'
|
|
447
|
+
? { backgroundColor: '#4caf50' }
|
|
448
|
+
: undefined
|
|
449
|
+
}
|
|
450
|
+
open={this.state._alert}
|
|
451
|
+
autoHideDuration={6000}
|
|
452
|
+
onClose={(_e, reason) => reason !== 'clickaway' && this.setState({ _alert: false })}
|
|
453
|
+
message={this.state._alertMessage}
|
|
454
|
+
/>
|
|
455
|
+
);
|
|
407
456
|
}
|
|
408
457
|
|
|
409
|
-
onSystemConfigChanged = (id: string, obj: ioBroker.AnyObject | null | undefined) => {
|
|
458
|
+
onSystemConfigChanged = (id: string, obj: ioBroker.AnyObject | null | undefined): void => {
|
|
410
459
|
if (obj && id === 'system.config') {
|
|
411
460
|
if (this.socket.systemLang !== (obj as ioBroker.SystemConfigObject)?.common.language) {
|
|
412
461
|
this.socket.systemLang = (obj as ioBroker.SystemConfigObject)?.common.language || 'en';
|
|
@@ -414,10 +463,12 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
414
463
|
}
|
|
415
464
|
|
|
416
465
|
if (this._systemConfig?.expertMode !== !!(obj as ioBroker.SystemConfigObject)?.common?.expertMode) {
|
|
417
|
-
this._systemConfig =
|
|
466
|
+
this._systemConfig =
|
|
467
|
+
(obj as ioBroker.SystemConfigObject)?.common || ({} as ioBroker.SystemConfigCommon);
|
|
418
468
|
this.setState({ expertMode: this.getExpertMode() });
|
|
419
469
|
} else {
|
|
420
|
-
this._systemConfig =
|
|
470
|
+
this._systemConfig =
|
|
471
|
+
(obj as ioBroker.SystemConfigObject)?.common || ({} as ioBroker.SystemConfigCommon);
|
|
421
472
|
}
|
|
422
473
|
}
|
|
423
474
|
};
|
|
@@ -425,7 +476,7 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
425
476
|
/**
|
|
426
477
|
* Called immediately after a component is mounted. Setting state here will trigger re-rendering.
|
|
427
478
|
*/
|
|
428
|
-
componentDidMount() {
|
|
479
|
+
componentDidMount(): void {
|
|
429
480
|
window.addEventListener('resize', this.onResize, true);
|
|
430
481
|
window.addEventListener('message', this.onReceiveMessage, false);
|
|
431
482
|
super.componentDidMount();
|
|
@@ -434,13 +485,13 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
434
485
|
/**
|
|
435
486
|
* Called immediately before a component is destroyed.
|
|
436
487
|
*/
|
|
437
|
-
componentWillUnmount() {
|
|
488
|
+
componentWillUnmount(): void {
|
|
438
489
|
window.removeEventListener('resize', this.onResize, true);
|
|
439
490
|
window.removeEventListener('message', this.onReceiveMessage, false);
|
|
440
491
|
super.componentWillUnmount();
|
|
441
492
|
}
|
|
442
493
|
|
|
443
|
-
onReceiveMessage = (message: { data: string } | null) => {
|
|
494
|
+
onReceiveMessage = (message: { data: string } | null): void => {
|
|
444
495
|
if (message?.data) {
|
|
445
496
|
if (message.data === 'updateTheme') {
|
|
446
497
|
const newThemeName = Utils.getThemeName();
|
|
@@ -448,24 +499,29 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
448
499
|
|
|
449
500
|
const newTheme = this.createTheme(newThemeName);
|
|
450
501
|
|
|
451
|
-
this.setState(
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
502
|
+
this.setState(
|
|
503
|
+
{
|
|
504
|
+
theme: newTheme,
|
|
505
|
+
themeName: this.getThemeName(newTheme),
|
|
506
|
+
themeType: this.getThemeType(newTheme),
|
|
507
|
+
},
|
|
508
|
+
() => {
|
|
509
|
+
this.props.onThemeChange && this.props.onThemeChange(newThemeName);
|
|
510
|
+
this.onThemeChanged && this.onThemeChanged(newThemeName);
|
|
511
|
+
},
|
|
512
|
+
);
|
|
459
513
|
} else if (message.data === 'updateExpertMode') {
|
|
460
514
|
this.onToggleExpertMode && this.onToggleExpertMode(this.getExpertMode());
|
|
461
|
-
} else if (message.data !== 'chartReady') {
|
|
462
|
-
//
|
|
463
|
-
console.debug(
|
|
515
|
+
} else if (message.data !== 'chartReady') {
|
|
516
|
+
// if not "echart ready" message
|
|
517
|
+
console.debug(
|
|
518
|
+
`Received unknown message: "${JSON.stringify(message.data)}". May be it will be processed later`,
|
|
519
|
+
);
|
|
464
520
|
}
|
|
465
521
|
}
|
|
466
522
|
};
|
|
467
523
|
|
|
468
|
-
private onResize = () => {
|
|
524
|
+
private onResize = (): void => {
|
|
469
525
|
this.resizeTimer && clearTimeout(this.resizeTimer);
|
|
470
526
|
this.resizeTimer = setTimeout(() => {
|
|
471
527
|
this.resizeTimer = null;
|
|
@@ -475,7 +531,6 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
475
531
|
|
|
476
532
|
/**
|
|
477
533
|
* Gets the width depending on the window inner width.
|
|
478
|
-
* @returns {import('./types').Width}
|
|
479
534
|
*/
|
|
480
535
|
static getWidth(): Width {
|
|
481
536
|
/**
|
|
@@ -500,15 +555,18 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
500
555
|
|
|
501
556
|
/**
|
|
502
557
|
* Get a theme
|
|
558
|
+
*
|
|
503
559
|
* @param name Theme name
|
|
504
560
|
*/
|
|
505
|
-
|
|
561
|
+
// eslint-disable-next-line class-methods-use-this
|
|
562
|
+
createTheme(name?: ThemeName | null): IobTheme {
|
|
506
563
|
return Theme(Utils.getThemeName(name));
|
|
507
564
|
}
|
|
508
565
|
|
|
509
566
|
/**
|
|
510
567
|
* Get the theme name
|
|
511
568
|
*/
|
|
569
|
+
// eslint-disable-next-line class-methods-use-this
|
|
512
570
|
getThemeName(currentTheme: IobTheme): ThemeName {
|
|
513
571
|
return currentTheme.name;
|
|
514
572
|
}
|
|
@@ -516,50 +574,57 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
516
574
|
/**
|
|
517
575
|
* Get the theme type
|
|
518
576
|
*/
|
|
577
|
+
// eslint-disable-next-line class-methods-use-this
|
|
519
578
|
getThemeType(currentTheme: IobTheme): ThemeType {
|
|
520
579
|
return currentTheme.palette.mode;
|
|
521
580
|
}
|
|
522
581
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
onToggleExpertMode(_expertMode: boolean) {
|
|
582
|
+
// eslint-disable-next-line class-methods-use-this
|
|
583
|
+
onThemeChanged(_newThemeName: string): void {}
|
|
528
584
|
|
|
529
|
-
|
|
585
|
+
// eslint-disable-next-line class-methods-use-this
|
|
586
|
+
onToggleExpertMode(_expertMode: boolean): void {}
|
|
530
587
|
|
|
531
588
|
/**
|
|
532
589
|
* Changes the current theme
|
|
533
|
-
|
|
534
|
-
toggleTheme(newThemeName?: ThemeName) {
|
|
590
|
+
*/
|
|
591
|
+
toggleTheme(newThemeName?: ThemeName): void {
|
|
535
592
|
const themeName = this.state.themeName;
|
|
536
593
|
|
|
537
594
|
// dark => blue => colored => light => dark
|
|
538
|
-
newThemeName =
|
|
539
|
-
|
|
540
|
-
|
|
595
|
+
newThemeName =
|
|
596
|
+
newThemeName ||
|
|
597
|
+
(themeName === 'dark'
|
|
598
|
+
? 'light'
|
|
599
|
+
: themeName === 'blue'
|
|
600
|
+
? 'light'
|
|
601
|
+
: themeName === 'colored'
|
|
602
|
+
? 'light'
|
|
603
|
+
: 'dark');
|
|
541
604
|
|
|
542
605
|
if (newThemeName !== themeName) {
|
|
543
606
|
Utils.setThemeName(newThemeName);
|
|
544
607
|
|
|
545
608
|
const newTheme = this.createTheme(newThemeName);
|
|
546
609
|
|
|
547
|
-
this.setState(
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
610
|
+
this.setState(
|
|
611
|
+
{
|
|
612
|
+
theme: newTheme,
|
|
613
|
+
themeName: this.getThemeName(newTheme),
|
|
614
|
+
themeType: this.getThemeType(newTheme),
|
|
615
|
+
},
|
|
616
|
+
() => {
|
|
617
|
+
this.props.onThemeChange && this.props.onThemeChange(newThemeName || 'light');
|
|
618
|
+
this.onThemeChanged && this.onThemeChanged(newThemeName || 'light');
|
|
619
|
+
},
|
|
620
|
+
);
|
|
555
621
|
}
|
|
556
622
|
}
|
|
557
623
|
|
|
558
624
|
/**
|
|
559
625
|
* Gets the system configuration.
|
|
560
|
-
* @returns {Promise<ioBroker.OtherObject>}
|
|
561
626
|
*/
|
|
562
|
-
getSystemConfig() {
|
|
627
|
+
getSystemConfig(): Promise<ioBroker.SystemConfigObject> {
|
|
563
628
|
return this.socket.getSystemConfig();
|
|
564
629
|
}
|
|
565
630
|
|
|
@@ -574,8 +639,8 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
574
639
|
* Gets called when the socket.io connection is ready.
|
|
575
640
|
* You can overload this function to execute own commands.
|
|
576
641
|
*/
|
|
577
|
-
|
|
578
|
-
}
|
|
642
|
+
// eslint-disable-next-line class-methods-use-this
|
|
643
|
+
onConnectionReady(): void {}
|
|
579
644
|
|
|
580
645
|
/**
|
|
581
646
|
* Encrypts a string.
|
|
@@ -584,8 +649,9 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
584
649
|
let result = '';
|
|
585
650
|
if (this._secret) {
|
|
586
651
|
for (let i = 0; i < value.length; i++) {
|
|
587
|
-
|
|
588
|
-
|
|
652
|
+
result += String.fromCharCode(
|
|
653
|
+
this._secret[i % this._secret.length].charCodeAt(0) ^ value.charCodeAt(i),
|
|
654
|
+
);
|
|
589
655
|
}
|
|
590
656
|
}
|
|
591
657
|
return result;
|
|
@@ -598,8 +664,9 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
598
664
|
let result = '';
|
|
599
665
|
if (this._secret) {
|
|
600
666
|
for (let i = 0; i < value.length; i++) {
|
|
601
|
-
|
|
602
|
-
|
|
667
|
+
result += String.fromCharCode(
|
|
668
|
+
this._secret[i % this._secret.length].charCodeAt(0) ^ value.charCodeAt(i),
|
|
669
|
+
);
|
|
603
670
|
}
|
|
604
671
|
}
|
|
605
672
|
return result;
|
|
@@ -609,7 +676,7 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
609
676
|
* Gets called when the navigation hash changes.
|
|
610
677
|
* You may override this if needed.
|
|
611
678
|
*/
|
|
612
|
-
onHashChanged() {
|
|
679
|
+
onHashChanged(): void {
|
|
613
680
|
const location = Router.getLocation();
|
|
614
681
|
if (location.tab !== this.state.selectedTab) {
|
|
615
682
|
this.selectTab(location.tab);
|
|
@@ -619,7 +686,7 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
619
686
|
/**
|
|
620
687
|
* Selects the given tab.
|
|
621
688
|
*/
|
|
622
|
-
selectTab(tab: string, index?: number) {
|
|
689
|
+
selectTab(tab: string, index?: number): void {
|
|
623
690
|
((window as any)._localStorage || window.localStorage).setItem(`${this.adapterName}-adapter`, tab);
|
|
624
691
|
this.setState({ selectedTab: tab, selectedTabNum: index });
|
|
625
692
|
}
|
|
@@ -630,11 +697,12 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
630
697
|
*/
|
|
631
698
|
onPrepareSave(settings: Record<string, any>): boolean {
|
|
632
699
|
// here you can encode values
|
|
633
|
-
this.encryptedFields &&
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
700
|
+
this.encryptedFields &&
|
|
701
|
+
this.encryptedFields.forEach(attr => {
|
|
702
|
+
if (settings[attr]) {
|
|
703
|
+
settings[attr] = this.encrypt(settings[attr]);
|
|
704
|
+
}
|
|
705
|
+
});
|
|
638
706
|
|
|
639
707
|
return true;
|
|
640
708
|
}
|
|
@@ -642,33 +710,40 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
642
710
|
/**
|
|
643
711
|
* Gets called after the settings are loaded.
|
|
644
712
|
* You may override this if needed.
|
|
713
|
+
*
|
|
714
|
+
* @param settings instance settings from native part
|
|
645
715
|
* @param encryptedNative optional list of fields to be decrypted
|
|
646
716
|
*/
|
|
647
|
-
onPrepareLoad(settings: Record<string, any>, encryptedNative?: string[]) {
|
|
717
|
+
onPrepareLoad(settings: Record<string, any>, encryptedNative?: string[]): void {
|
|
648
718
|
// here you can encode values
|
|
649
|
-
this.encryptedFields &&
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
719
|
+
this.encryptedFields &&
|
|
720
|
+
this.encryptedFields.forEach(attr => {
|
|
721
|
+
if (settings[attr]) {
|
|
722
|
+
settings[attr] = this.decrypt(settings[attr]);
|
|
723
|
+
}
|
|
724
|
+
});
|
|
725
|
+
encryptedNative &&
|
|
726
|
+
encryptedNative.forEach(attr => {
|
|
727
|
+
this.encryptedFields = this.encryptedFields || [];
|
|
728
|
+
!this.encryptedFields.includes(attr) && this.encryptedFields.push(attr);
|
|
729
|
+
if (settings[attr]) {
|
|
730
|
+
settings[attr] = this.decrypt(settings[attr]);
|
|
731
|
+
}
|
|
732
|
+
});
|
|
661
733
|
}
|
|
662
734
|
|
|
663
735
|
/**
|
|
664
736
|
* Gets the extendable instances.
|
|
665
|
-
* @returns {Promise<any[]>}
|
|
666
737
|
*/
|
|
667
738
|
async getExtendableInstances(): Promise<ioBroker.InstanceObject[]> {
|
|
668
739
|
try {
|
|
669
|
-
const instances = await this.socket.getObjectViewSystem(
|
|
740
|
+
const instances = await this.socket.getObjectViewSystem(
|
|
741
|
+
'instance',
|
|
742
|
+
'system.adapter.',
|
|
743
|
+
'system.adapter.\u9999',
|
|
744
|
+
);
|
|
670
745
|
return Object.values(instances).filter(instance => !!instance?.common?.webExtendable);
|
|
671
|
-
} catch
|
|
746
|
+
} catch {
|
|
672
747
|
return [];
|
|
673
748
|
}
|
|
674
749
|
}
|
|
@@ -692,16 +767,18 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
692
767
|
|
|
693
768
|
/**
|
|
694
769
|
* Saves the settings to the server.
|
|
770
|
+
*
|
|
695
771
|
* @param isClose True if the user is closing the dialog.
|
|
696
772
|
*/
|
|
697
|
-
onSave(isClose?: boolean) {
|
|
773
|
+
onSave(isClose?: boolean): void {
|
|
698
774
|
let oldObj: ioBroker.InstanceObject;
|
|
699
775
|
if (this.state.isConfigurationError) {
|
|
700
776
|
this.setState({ errorText: this.state.isConfigurationError });
|
|
701
777
|
return;
|
|
702
778
|
}
|
|
703
779
|
|
|
704
|
-
this.socket
|
|
780
|
+
this.socket
|
|
781
|
+
.getObject(this.instanceId)
|
|
705
782
|
.then(_oldObj => {
|
|
706
783
|
oldObj = (_oldObj || {}) as ioBroker.InstanceObject;
|
|
707
784
|
|
|
@@ -722,7 +799,9 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
722
799
|
if (this.state.common[b] === null) {
|
|
723
800
|
(oldObj as Record<string, any>).common[b] = null;
|
|
724
801
|
} else if (this.state.common[b] !== undefined) {
|
|
725
|
-
(oldObj as Record<string, any>).common[b] = JSON.parse(
|
|
802
|
+
(oldObj as Record<string, any>).common[b] = JSON.parse(
|
|
803
|
+
JSON.stringify(this.state.common[b]),
|
|
804
|
+
);
|
|
726
805
|
} else {
|
|
727
806
|
delete (oldObj as Record<string, any>).common[b];
|
|
728
807
|
}
|
|
@@ -740,7 +819,7 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
740
819
|
globalThis.changed = false;
|
|
741
820
|
try {
|
|
742
821
|
window.parent.postMessage('nochange', '*');
|
|
743
|
-
} catch
|
|
822
|
+
} catch {
|
|
744
823
|
// ignore
|
|
745
824
|
}
|
|
746
825
|
|
|
@@ -753,40 +832,42 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
753
832
|
/**
|
|
754
833
|
* Renders the toast.
|
|
755
834
|
*/
|
|
756
|
-
renderToast() {
|
|
835
|
+
renderToast(): JSX.Element | null {
|
|
757
836
|
if (!this.state.toast) {
|
|
758
837
|
return null;
|
|
759
838
|
}
|
|
760
839
|
|
|
761
|
-
return
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
840
|
+
return (
|
|
841
|
+
<Snackbar
|
|
842
|
+
anchorOrigin={{
|
|
843
|
+
vertical: 'bottom',
|
|
844
|
+
horizontal: 'left',
|
|
845
|
+
}}
|
|
846
|
+
open={!0}
|
|
847
|
+
autoHideDuration={6000}
|
|
848
|
+
onClose={() => this.setState({ toast: '' })}
|
|
849
|
+
ContentProps={{ 'aria-describedby': 'message-id' }}
|
|
850
|
+
message={<span id="message-id">{this.state.toast}</span>}
|
|
851
|
+
action={[
|
|
852
|
+
<IconButton
|
|
853
|
+
key="close"
|
|
854
|
+
aria-label="Close"
|
|
855
|
+
color="inherit"
|
|
856
|
+
className={this.props.classes?.close}
|
|
857
|
+
onClick={() => this.setState({ toast: '' })}
|
|
858
|
+
size="large"
|
|
859
|
+
>
|
|
860
|
+
<IconClose />
|
|
861
|
+
</IconButton>,
|
|
862
|
+
]}
|
|
863
|
+
/>
|
|
864
|
+
);
|
|
784
865
|
}
|
|
785
866
|
|
|
786
867
|
/**
|
|
787
868
|
* Closes the dialog.
|
|
788
869
|
*/
|
|
789
|
-
static onClose() {
|
|
870
|
+
static onClose(): void {
|
|
790
871
|
if (typeof window.parent !== 'undefined' && window.parent) {
|
|
791
872
|
try {
|
|
792
873
|
if (window.parent.$iframeDialog && typeof window.parent.$iframeDialog.close === 'function') {
|
|
@@ -794,7 +875,7 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
794
875
|
} else {
|
|
795
876
|
window.parent.postMessage('close', '*');
|
|
796
877
|
}
|
|
797
|
-
} catch
|
|
878
|
+
} catch {
|
|
798
879
|
window.parent.postMessage('close', '*');
|
|
799
880
|
}
|
|
800
881
|
}
|
|
@@ -808,16 +889,22 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
808
889
|
return null;
|
|
809
890
|
}
|
|
810
891
|
|
|
811
|
-
return
|
|
892
|
+
return (
|
|
893
|
+
<DialogError
|
|
894
|
+
text={this.state.errorText}
|
|
895
|
+
onClose={() => this.setState({ errorText: '' })}
|
|
896
|
+
/>
|
|
897
|
+
);
|
|
812
898
|
}
|
|
813
899
|
|
|
814
900
|
/**
|
|
815
901
|
* Checks if the configuration has changed.
|
|
816
|
-
*
|
|
902
|
+
*
|
|
903
|
+
* @param native the new state
|
|
817
904
|
*/
|
|
818
905
|
getIsChanged(native: Record<string, any>): boolean {
|
|
819
906
|
native = native || this.state.native;
|
|
820
|
-
const isChanged =
|
|
907
|
+
const isChanged = JSON.stringify(native) !== JSON.stringify(this.savedNative);
|
|
821
908
|
|
|
822
909
|
globalThis.changed = isChanged;
|
|
823
910
|
|
|
@@ -826,9 +913,10 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
826
913
|
|
|
827
914
|
/**
|
|
828
915
|
* Gets called when loading the configuration.
|
|
916
|
+
*
|
|
829
917
|
* @param newNative The new configuration object.
|
|
830
918
|
*/
|
|
831
|
-
onLoadConfig(newNative: Record<string, any>) {
|
|
919
|
+
onLoadConfig(newNative: Record<string, any>): void {
|
|
832
920
|
if (JSON.stringify(newNative) !== JSON.stringify(this.state.native)) {
|
|
833
921
|
this.setState({ native: newNative, changed: this.getIsChanged(newNative) });
|
|
834
922
|
}
|
|
@@ -837,7 +925,7 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
837
925
|
/**
|
|
838
926
|
* Sets the configuration error.
|
|
839
927
|
*/
|
|
840
|
-
setConfigurationError(errorText: string) {
|
|
928
|
+
setConfigurationError(errorText: string): void {
|
|
841
929
|
if (this.state.isConfigurationError !== errorText) {
|
|
842
930
|
this.setState({ isConfigurationError: errorText });
|
|
843
931
|
}
|
|
@@ -851,31 +939,37 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
851
939
|
return null;
|
|
852
940
|
}
|
|
853
941
|
|
|
854
|
-
return
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
this.
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
942
|
+
return (
|
|
943
|
+
<>
|
|
944
|
+
{this.state.bottomButtons ? (
|
|
945
|
+
<SaveCloseButtons
|
|
946
|
+
theme={this.state.theme}
|
|
947
|
+
newReact={this.newReact}
|
|
948
|
+
noTextOnButtons={
|
|
949
|
+
this.state.width === 'xs' || this.state.width === 'sm' || this.state.width === 'md'
|
|
950
|
+
}
|
|
951
|
+
changed={this.state.changed}
|
|
952
|
+
onSave={isClose => this.onSave(isClose)}
|
|
953
|
+
onClose={() => {
|
|
954
|
+
if (this.state.changed) {
|
|
955
|
+
this.setState({ confirmClose: true });
|
|
956
|
+
} else {
|
|
957
|
+
GenericApp.onClose();
|
|
958
|
+
}
|
|
959
|
+
}}
|
|
960
|
+
/>
|
|
961
|
+
) : null}
|
|
962
|
+
{this.state.confirmClose ? (
|
|
963
|
+
<ConfirmDialog
|
|
964
|
+
title={I18n.t('ra_Please confirm')}
|
|
965
|
+
text={I18n.t('ra_Some data are not stored. Discard?')}
|
|
966
|
+
ok={I18n.t('ra_Discard')}
|
|
967
|
+
cancel={I18n.t('ra_Cancel')}
|
|
968
|
+
onClose={isYes => this.setState({ confirmClose: false }, () => isYes && GenericApp.onClose())}
|
|
969
|
+
/>
|
|
970
|
+
) : null}
|
|
971
|
+
</>
|
|
972
|
+
);
|
|
879
973
|
}
|
|
880
974
|
|
|
881
975
|
private _updateNativeValue(obj: Record<string, any>, attrs: string | string[], value: any): boolean {
|
|
@@ -908,11 +1002,12 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
908
1002
|
|
|
909
1003
|
/**
|
|
910
1004
|
* Update the native value
|
|
1005
|
+
*
|
|
911
1006
|
* @param attr The attribute name with dots as delimiter.
|
|
912
1007
|
* @param value The new value.
|
|
913
1008
|
* @param cb Callback which will be called upon completion.
|
|
914
1009
|
*/
|
|
915
|
-
updateNativeValue(attr: string, value: any, cb?: () => void) {
|
|
1010
|
+
updateNativeValue(attr: string, value: any, cb?: () => void): void {
|
|
916
1011
|
const native = JSON.parse(JSON.stringify(this.state.native));
|
|
917
1012
|
if (this._updateNativeValue(native, attr, value)) {
|
|
918
1013
|
const changed = this.getIsChanged(native);
|
|
@@ -920,7 +1015,7 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
920
1015
|
if (changed !== this.state.changed) {
|
|
921
1016
|
try {
|
|
922
1017
|
window.parent.postMessage(changed ? 'change' : 'nochange', '*');
|
|
923
|
-
} catch
|
|
1018
|
+
} catch {
|
|
924
1019
|
// ignore
|
|
925
1020
|
}
|
|
926
1021
|
}
|
|
@@ -932,13 +1027,14 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
932
1027
|
/**
|
|
933
1028
|
* Set the error text to be shown.
|
|
934
1029
|
*/
|
|
935
|
-
showError(text: string | React.JSX.Element) {
|
|
1030
|
+
showError(text: string | React.JSX.Element): void {
|
|
936
1031
|
this.setState({ errorText: text });
|
|
937
1032
|
}
|
|
938
1033
|
|
|
939
1034
|
/**
|
|
940
1035
|
* Sets the toast to be shown.
|
|
941
|
-
*
|
|
1036
|
+
*
|
|
1037
|
+
* @param toast Text to be shown.
|
|
942
1038
|
*/
|
|
943
1039
|
showToast(toast: string | React.JSX.Element): void {
|
|
944
1040
|
this.setState({ toast });
|
|
@@ -948,12 +1044,14 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
948
1044
|
* Renders helper dialogs
|
|
949
1045
|
*/
|
|
950
1046
|
renderHelperDialogs(): React.JSX.Element {
|
|
951
|
-
return
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
1047
|
+
return (
|
|
1048
|
+
<>
|
|
1049
|
+
{this.renderError()}
|
|
1050
|
+
{this.renderToast()}
|
|
1051
|
+
{this.renderSaveCloseButtons()}
|
|
1052
|
+
{this.renderAlertSnackbar()}
|
|
1053
|
+
</>
|
|
1054
|
+
);
|
|
957
1055
|
}
|
|
958
1056
|
|
|
959
1057
|
/**
|
|
@@ -964,12 +1062,14 @@ class GenericApp<TProps extends GenericAppProps = GenericAppProps, TState extend
|
|
|
964
1062
|
return <Loader themeType={this.state.themeType} />;
|
|
965
1063
|
}
|
|
966
1064
|
|
|
967
|
-
return
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
1065
|
+
return (
|
|
1066
|
+
<div className="App">
|
|
1067
|
+
{this.renderError()}
|
|
1068
|
+
{this.renderToast()}
|
|
1069
|
+
{this.renderSaveCloseButtons()}
|
|
1070
|
+
{this.renderAlertSnackbar()}
|
|
1071
|
+
</div>
|
|
1072
|
+
);
|
|
973
1073
|
}
|
|
974
1074
|
}
|
|
975
1075
|
|