@iobroker/adapter-react-v5 6.1.10 → 7.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,1331 +1,1339 @@
1
- # Help ReactJS classes for adapter config
2
- You can find demo on https://github.com/ioBroker/adapter-react-demo
3
-
4
- ## Getting started
5
- If you want to create the configuration page with ReactJS:
6
- 1. Create github repo for adapter.
7
- 2. execute `npx create-react-app src` . It will take a while.
8
- 3. `cd src`
9
- 4. Modify package.json file in src directory:
10
- - Change `name` from `src` to `ADAPTERNAME-admin` (Of course replace `ADAPTERNAME` with yours)
11
- - Add to devDependencies:
12
- ```
13
- "@iobroker/adapter-react": "^4.0.10",
14
- ```
15
- Versions can be higher.
16
- So your src/package.json should look like:
17
- ```
18
- {
19
- "name": "ADAPTERNAME-admin",
20
- "version": "0.1.0",
21
- "private": true,
22
- "dependencies": {
23
- "react": "^18.2.0",
24
- "react-dom": "^18.2.0",
25
- "react-icons": "^4.6.0",
26
- "react-scripts": "^5.0.1",
27
- "@iobroker/adapter-react-v5": "^3.2.7",
28
- "del": "^6.1.1",
29
- "gulp": "^4.0.2"
30
- },
31
- "scripts": {
32
- "start": "react-scripts start",
33
- "build": "react-scripts build",
34
- "test": "react-scripts test",
35
- "eject": "react-scripts eject"
36
- },
37
- "eslintConfig": {
38
- "extends": "react-app"
39
- },
40
- "homepage": ".",
41
- "browserslist": [
42
- ">0.2%",
43
- "not dead",
44
- "not ie <= 11",
45
- "not op_mini all"
46
- ]
47
- }
48
- ```
49
- 5. Call in `src`: `npm install`
50
- 6. Copy gulpfile.js into `src`: `cp node_modules/@iobroker/adapter-react/gulpfile.js gulpfile.js`
51
- 7. Start your dummy application `npm run start` for developing or build with `npm run build` and
52
- copy files in `build` directory to `www` or to `admin`. In the admin you must rename `index.html` to `index_m.html`.
53
- 8. You can do that with `gulp` tasks: `gulp build`, `gulp copy`, `gulp renameIndex` or `gulp renameTab`
54
-
55
- ## Development
56
- 1. Add `socket.io` to `public/index.html`.
57
- After
58
-
59
- ```
60
- <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
61
- ```
62
-
63
- insert
64
-
65
- ```
66
- <script>
67
- var script = document.createElement('script');
68
- window.registerSocketOnLoad = function (cb) {
69
- window.socketLoadedHandler = cb;
70
- };
71
- const parts = (window.location.search || '').replace(/^\?/, '').split('&');
72
- const query = {};
73
- parts.forEach(item => {
74
- const [name, val] = item.split('=');
75
- query[decodeURIComponent(name)] = val !== undefined ? decodeURIComponent(val) : true;
76
- });
77
- script.onload = function () { typeof window.socketLoadedHandler === 'function' && window.socketLoadedHandler(); };
78
- script.src = window.location.port === '3000' ? window.location.protocol + '//' + (query.host || window.location.hostname) + ':' + (query.port || 8081) + '/lib/js/socket.io.js' : '%PUBLIC_URL%/../../lib/js/socket.io.js';
79
-
80
- document.head.appendChild(script);
81
- </script>
82
- ```
83
-
84
- 3. Add to App.js constructor initialization for I18n:
85
- ```
86
- class App extends GenericApp {
87
- constructor(props) {
88
- const extendedProps = {...props};
89
- extendedProps.encryptedFields = ['pass']; // this parameter will be encrypted and decrypted automatically
90
- extendedProps.translations = {
91
- 'en': require('./i18n/en'),
92
- 'de': require('./i18n/de'),
93
- 'ru': require('./i18n/ru'),
94
- 'pt': require('./i18n/pt'),
95
- 'nl': require('./i18n/nl'),
96
- 'fr': require('./i18n/fr'),
97
- 'it': require('./i18n/it'),
98
- 'es': require('./i18n/es'),
99
- 'pl': require('./i18n/pl'),
100
- 'uk': require('./i18n/uk'),
101
- 'zh-cn': require('./i18n/zh-cn'),
102
- };
103
- // get actual admin port
104
- extendedProps.socket = {port: parseInt(window.location.port, 10)};
105
-
106
- // Only if close, save buttons are not required at the bottom (e.g. if admin tab)
107
- // extendedProps.bottomButtons = false;
108
-
109
- // only for debug purposes
110
- if (extendedProps.socket.port === 3000) {
111
- extendedProps.socket.port = 8081;
112
- }
113
-
114
- // allow to manage GenericApp the sentry initialisation or do not set the sentryDSN if no sentry available
115
- extendedProps.sentryDSN = 'https://yyy@sentry.iobroker.net/xx';
116
-
117
- super(extendedProps);
118
- }
119
- ...
120
- }
121
- ```
122
-
123
- 4. Replace `index.js` with the following code to support themes:
124
- ```
125
- import React from 'react';
126
- import ReactDOM from 'react-dom';
127
- import { MuiThemeProvider} from '@material-ui/core/styles';
128
- import * as serviceWorker from './serviceWorker';
129
-
130
- import './index.css';
131
- import App from './App';
132
- import { version } from '../package.json';
133
-
134
- import theme from '@iobroker/adapter-react/Theme';
135
-
136
- console.log('iobroker.scenes@' + version);
137
- let themeName = window.localStorage ? window.localStorage.getItem('App.theme') || 'light' : 'light';
138
-
139
- function build() {
140
- return ReactDOM.render(<MuiThemeProvider theme={ theme(themeName) }>
141
- <App onThemeChange={_theme => {
142
- themeName = _theme;
143
- build();
144
- }}/>
145
- </MuiThemeProvider>, document.getElementById('root'));
146
- }
147
-
148
- build();
149
-
150
- // If you want your app to work offline and load faster, you can change
151
- // unregister() to register() below. Note this comes with some pitfalls.
152
- // Learn more about service workers: http://bit.ly/CRA-PWA
153
- serviceWorker.unregister();
154
- ```
155
-
156
- 5. Add to App.js encoding and decoding of values:
157
- ```
158
- class App extend GenericApp {
159
- ...
160
- onPrepareLoad(settings) {
161
- settings.pass = this.decode(settings.pass);
162
- }
163
- onPrepareSave(settings) {
164
- settings.pass = this.encode(settings.pass);
165
- }
166
- }
167
- ```
168
-
169
- 6. The optional step is to validate the data to be saved:
170
- ```
171
- onPrepareSave(settings) {
172
- super.onPrepareSave(settings);
173
- if (DATA_INVALID) {
174
- return false; // configuration will not be saved
175
- } else {
176
- return true;
177
- }
178
- }
179
- ```
180
-
181
- ## Components
182
-
183
- ### Connection.tsx
184
- This is a non-react class to provide the communication for socket connection with the server.
185
-
186
- ### GenericApp.tsx
187
-
188
- ### i18n.ts
189
-
190
- ### Theme.tsx
191
-
192
- ### Dialogs
193
- Some dialogs are predefined and could be used out of the box.
194
-
195
- #### Confirm.tsx
196
- <!-- TODO: Provide screenshot here -->
197
-
198
- Usage:
199
- ```
200
- import React from 'react';
201
- import ConfirmDialog from '@iobroker/adapter-react/Dialogs/Confirm'
202
- import I18n from '@iobroker/adapter-react/i18n';
203
-
204
- class ExportImportDialog extends React.Component {
205
- constructor(props) {
206
- super(props);
207
-
208
- this.state = {
209
- confirmDialog: false,
210
- };
211
- }
212
-
213
- renderConfirmDialog() {
214
- if (!this.state.confirmDialog) {
215
- return null;
216
- }
217
- return <ConfirmDialog
218
- title={ I18n.t('Scene will be overwritten.') }
219
- text={ I18n.t('All data will be lost. Confirm?') }
220
- ok={ I18n.t('Yes') }
221
- cancel={ I18n.t('Cancel') }
222
- suppressQuestionMinutes={5}
223
- dialogName="myConfirmDialogThatCouldBeSuppressed"
224
- suppressText={I18n.t('Suppress question for next %s minutes', 5)}
225
- onClose={isYes => {
226
- this.setState({ confirmDialog: false} );
227
- }}
228
- />;
229
- }
230
- render() {
231
- return <div>
232
- <Button onClick={ () => this.setState({confirmDialog: true}) }>Click</Button>
233
- { this.renderConfirmDialog() }
234
- </div>
235
- }
236
- }
237
-
238
- export default ExportImportDialog;
239
- ```
240
-
241
- #### Error.tsx
242
- <!-- TODO: Provide screenshot here -->
243
-
244
- #### Message.tsx
245
- <!-- TODO: Provide screenshot here -->
246
- ```
247
- renderMessage() {
248
- if (this.state.showMessage) {
249
- return <Message
250
- text={this.state.showMessage}
251
- onClose={() => this.setState({showMessage: false})}
252
- />;
253
- } else {
254
- return null;
255
- }
256
- }
257
- ```
258
-
259
- #### SelectID.tsx
260
- ![Logo](img/selectID.png)
261
- ```
262
- import DialogSelectID from '@iobroker/adapter-react/Dialogs/SelectID';
263
-
264
- class MyComponent extends Component {
265
- constructor(props) {
266
- super(props);
267
- this.state = {
268
- showSelectId: false,
269
- };
270
- }
271
-
272
- renderSelectIdDialog() {
273
- if (this.state.showSelectId) {
274
- return <DialogSelectID
275
- key="tableSelect"
276
- imagePrefix="../.."
277
- dialogName={this.props.adapterName}
278
- themeType={this.props.themeType}
279
- socket={this.props.socket}
280
- statesOnly={true}
281
- selected={this.state.selectIdValue}
282
- onClose={() => this.setState({showSelectId: false})}
283
- onOk={(selected, name) => {
284
- this.setState({showSelectId: false, selectIdValue: selected});
285
- }}
286
- />;
287
- } else {
288
- return null;
289
- }
290
- }
291
- render() {
292
- return renderSelectIdDialog();
293
- }
294
- }
295
- ```
296
-
297
- #### Cron
298
- Include `"react-text-mask": "^5.4.3",` in package.json.
299
-
300
- <!-- TODO: Provide screenshot here -->
301
-
302
- ```
303
- function renderCron() {
304
- if (!showCron) {
305
- return null;
306
- } else {
307
- return <DialogCron
308
- key="dialogCron1"
309
- cron={this.state.cronValue || '* * * * *'}
310
- onClose={() => this.setState({ showCron: false })}
311
- onOk={cronValue => {
312
- this.setState({ cronValue })
313
- }}
314
- />;
315
- }
316
- }
317
- ```
318
-
319
- ### Components
320
-
321
- #### Utils.tsx
322
- ##### getObjectNameFromObj
323
- `getObjectNameFromObj(obj, settings, options, isDesc)`
324
-
325
- Get object name from a single object.
326
-
327
- Usage: `Utils.getObjectNameFromObj(this.objects[id], null, {language: I18n.getLanguage()})`
328
-
329
- ##### getObjectIcon
330
- `getObjectIcon(id, obj)`
331
-
332
- Get icon from the object.
333
-
334
- Usage:
335
- ```
336
- const icon = Utils.getObjectIcon(id, this.objects[id]);
337
- return (<img src={icon}/>);
338
- ```
339
-
340
- ##### isUseBright
341
- `isUseBright(color, defaultValue)`
342
-
343
- Usage: `
344
-
345
- #### Loader.tsx
346
- ![Logo](img/loader.png)
347
-
348
- ```
349
- render() {
350
- if (!this.state.loaded) {
351
- return <MuiThemeProvider theme={this.state.theme}>
352
- <Loader theme={this.state.themeType}/>
353
- </MuiThemeProvider>;
354
- }
355
- // render loaded data
356
- }
357
-
358
- ```
359
-
360
- #### Logo.tsx
361
- ![Logo](img/logo.png)
362
-
363
- ```
364
- render() {
365
- return <form className={this.props.classes.tab}>
366
- <Logo
367
- instance={this.props.instance}
368
- common={this.props.common}
369
- native={this.props.native}
370
- onError={text => this.setState({errorText: text})}
371
- onLoad={this.props.onLoad}
372
- />
373
- ...
374
- </form>;
375
- }
376
- ```
377
-
378
- #### Router.tsx
379
-
380
- #### ObjectBrowser.js
381
- It is better to use `Dialog/SelectID`, but if you want:
382
-
383
- ![Logo](img/objectBrowser.png)
384
-
385
- ```
386
- <ObjectBrowser
387
- foldersFirst={this.props.foldersFirst}
388
- imagePrefix={this.props.imagePrefix || this.props.prefix} // prefix is for back compatibility
389
- defaultFilters={this.filters}
390
- dialogName={this.dialogName}
391
- showExpertButton={this.props.showExpertButton !== undefined ? this.props.showExpertButton : true}
392
- style={{ width: '100%', height: '100%' }}
393
- columns={this.props.columns || ['name', 'type', 'role', 'room', 'func', 'val']}
394
- types={this.props.types || ['state']}
395
- t={I18n.t}
396
- lang={this.props.lang || I18n.getLanguage()}
397
- socket={this.props.socket}
398
- selected={this.state.selected}
399
- multiSelect={this.props.multiSelect}
400
- notEditable={this.props.notEditable === undefined ? true : this.props.notEditable}
401
- name={this.state.name}
402
- themeName={this.props.themeName}
403
- themeType={this.props.themeType}
404
- customFilter={this.props.customFilter}
405
- onFilterChanged={filterConfig => {
406
- this.filters = filterConfig;
407
- window.localStorage.setItem(this.dialogName, JSON.stringify(filterConfig));
408
- }}
409
- onSelect={(selected, name, isDouble) => {
410
- if (JSON.stringify(selected) !== JSON.stringify(this.state.selected)) {
411
- this.setState({selected, name}, () =>
412
- isDouble && this.handleOk());
413
- } else if (isDouble) {
414
- this.handleOk();
415
- }
416
- }}
417
- />
418
- ```
419
-
420
- #### TreeTable.ts
421
- ![Logo](img/tableTree.png)
422
-
423
- ```
424
- // STYLES
425
- const styles = theme => ({
426
- tableDiv: {
427
- width: '100%',
428
- overflow: 'hidden',
429
- height: 'calc(100% - 48px)',
430
- },
431
- });
432
- class MyComponent extends Component {
433
- constructor(props) {
434
- super(props);
435
-
436
- this.state = {
437
- data: [
438
- {
439
- id: 'UniqueID1' // required
440
- fieldIdInData: 'Name1',
441
- myType: 'number',
442
- },
443
- {
444
- id: 'UniqueID2' // required
445
- fieldIdInData: 'Name12',
446
- myType: 'string',
447
- },
448
- ],
449
- };
450
-
451
- this.columns = [
452
- {
453
- title: 'Name of field', // required, else it will be "field"
454
- field: 'fieldIdInData', // required
455
- editable: false, // or true [default - true]
456
- cellStyle: { // CSS style - // optional
457
- maxWidth: '12rem',
458
- overflow: 'hidden',
459
- wordBreak: 'break-word',
460
- },
461
- lookup: { // optional => edit will be automatically "SELECT"
462
- 'value1': 'text1',
463
- 'value2': 'text2',
464
- }
465
- },
466
- {
467
- title: 'Type', // required, else it will be "field"
468
- field: 'myType', // required
469
- editable: true, // or true [default - true]
470
- lookup: { // optional => edit will be automatically "SELECT"
471
- 'number': 'Number',
472
- 'string': 'String',
473
- 'boolean': 'Boolean',
474
- },
475
- type: 'number/string/color/oid/icon/boolean', // oid=ObjectID,icon=base64-icon
476
- editComponent: props =>
477
- <div>Prefix&#123; <br/>
478
- <textarea
479
- rows={4}
480
- style={{width: '100%', resize: 'vertical'}}
481
- value={props.value}
482
- onChange={e => props.onChange(e.target.value)}
483
- />
484
- Suffix
485
- </div>,
486
- },
487
- ];
488
- }
489
- // renderTable
490
- render() {
491
- return <div className={this.props.classes.tableDiv}>
492
- <TreeTable
493
- columns={this.columns}
494
- data={this.state.data}
495
- onUpdate={(newData, oldData) => {
496
- const data = JSON.parse(JSON.stringify(this.state.data));
497
-
498
- // Added new line
499
- if (newData === true) {
500
- // find unique ID
501
- let i = 1;
502
- let id = 'line_' + i;
503
-
504
- // eslint-disable-next-line
505
- while(this.state.data.find(item => item.id === id)) {
506
- i++;
507
- id = 'line_' + i;
508
- }
509
-
510
- data.push({
511
- id,
512
- name: I18n.t('New resource') + '_' + i,
513
- color: '',
514
- icon: '',
515
- unit: '',
516
- price: 0,
517
- });
518
- } else {
519
- // existing line was modifed
520
- const pos = this.state.data.indexOf(oldData);
521
- if (pos !== -1) {
522
- Object.keys(newData).forEach(attr => data[pos][attr] = newData[attr]);
523
- }
524
- }
525
-
526
- this.setState({data});
527
- }}
528
- onDelete={oldData => {
529
- console.log('Delete: ' + JSON.stringify(oldData));
530
- const pos = this.state.data.indexOf(oldData);
531
- if (pos !== -1) {
532
- const data = JSON.parse(JSON.stringify(this.state.data));
533
- data.splice(pos, 1);
534
- this.setState({data});
535
- }
536
- }}
537
- />
538
- </div>;
539
- }
540
- }
541
- ```
542
-
543
- #### Toast
544
- <!-- TODO: Provide screenshot here -->
545
-
546
- Toast is not a part of `adapter-react` but it is an example how to use toast in application:
547
-
548
- ```
549
- import Snackbar from '@material-ui/core/Snackbar';
550
-
551
- class MyComponent {
552
- constructor(props) {
553
- super(props);
554
- this.state = {
555
- // ....
556
- toast: '',
557
- };
558
- }
559
- // ...
560
- renderToast() {
561
- if (!this.state.toast) {
562
- return null;
563
- }
564
- return <Snackbar
565
- anchorOrigin={{
566
- vertical: 'bottom',
567
- horizontal: 'left',
568
- }}
569
- open={true}
570
- autoHideDuration={6000}
571
- onClose={() => this.setState({toast: ''})}
572
- ContentProps={{'aria-describedby': 'message-id'}}
573
- message={<span id="message-id">{this.state.toast}</span>}
574
- action={[
575
- <IconButton
576
- key="close"
577
- aria-label="Close"
578
- color="inherit"
579
- className={this.props.classes.close}
580
- onClick={() => this.setState({toast: ''})}
581
- >
582
- <IconClose />
583
- </IconButton>,
584
- ]}
585
- />;
586
- }
587
- render() {
588
- return <div>
589
- {this.renderToast()}
590
- </div>;
591
- }
592
- }
593
- ```
594
-
595
- ## List of adapters that use adapter-react
596
- - Admin
597
- - Backitup
598
- - iot
599
- - echarts
600
- - text2command
601
- - scenes
602
- - javascript
603
- - devices
604
- - eventlist
605
- - cameras
606
- - web
607
- - vis-2
608
- - vis-2-widgets-xxx
609
- - fullcalendar
610
- - openweathermap
611
-
612
- ## Usability
613
- In dialogs, the OK button is first (on the left) and the cancel button is last (on the right)
614
-
615
- ## Used icons
616
- This project uses icons from [Flaticon](https://www.flaticon.com/).
617
-
618
- ioBroker GmbH has a valid license for all the used icons.
619
- The icons may not be reused in other projects without the proper flaticon license or flaticon subscription.
620
-
621
- ## Migration from adapter-react to adapter-react-v5
622
- ### In src/package.json => dependencies
623
- - `"@iobroker/adapter-react": "^2.0.22",` => `"@iobroker/adapter-react-v5": "^3.1.34",`
624
- - `"@material-ui/core": "^4.12.3",` => `"@mui/material": "^5.10.9",`
625
- - `"@material-ui/icons": "^4.11.2",` => `"@mui/icons-material": "^5.10.9",`
626
- - Add `"@mui/styles": "^5.10.9",`
627
- - Add `"babel-eslint": "^10.1.0",`
628
-
629
- ### In Source files
630
- - All `@iobroker/adapter-react/...` => `@iobroker/adapter-react-v5/...`
631
- - All `@material-ui/icons/...` => `@mui/icons-material/...`
632
- - Change `import { withStyles } from '@material-ui/core/styles';` => `import { withStyles } from '@mui/styles';`
633
- - Change `import { makeStyles } from '@mui/material/styles';` => `import { makeStyles } from '@mui/styles';`
634
- - Change `import withWidth from '@material-ui/core/withWidth';` => `import { withWidth } from '@iobroker/adapter-react-v5';`
635
- - All `@material-ui/core...` => `@mui/material...`
636
- - Change `import { MuiThemeProvider } from '@material-ui/core/styles';` => `import { ThemeProvider, StyledEngineProvider } from '@mui/material/styles';`
637
- - Change all `<MuiThemeProvider theme={this.state.theme}>` to `<StyledEngineProvider injectFirst><ThemeProvider theme={this.state.theme}>`
638
- - Rename in styles `theme.palette.type` => `theme.palette.mode`
639
- - Add to all `TextField`, `Select`, `FormControl` the property `variant="standard"`
640
- - Add to all `Button` that do not have `color` property: `color="grey"`
641
- - Replace by `TextField` the `readOnly` attribute (if exists) with `InputProps={{readOnly: true}}`
642
- - Remove px by all `theme.spacing`: `calc(100% - ${theme.spacing(4)}px)` => `calc(100% - ${theme.spacing(4)})`
643
- - Replace `this.selectTab(e.target.parentNode.dataset.name, index)` => `this.selectTab(e.target.dataset.name, index)`
644
-
645
- If you still have questions, try to find an answer [here](https://mui.com/guides/migration-v4/).
646
-
647
- ## Migration from adapter-react-v5@3.x to adapter-react-v5@4.x
648
- - Look for getObjectView socket requests and replace `socket.getObjectView('startKey', 'endKey', 'instance')` to `socket.getObjectViewSystem('instance', 'startKey', 'endKey')`
649
- - Look for calls of custom like
650
- ```
651
- this.props.socket._socket.emit('getObjectView', 'system', 'custom', {startKey: '', endKey:'\u9999'}, (err, objs) => {
652
- (objs?.rows || [])
653
- .forEach(item => console.log(item.id, item.value));
654
- });
655
- ```
656
- to
657
- ```
658
- socket.getObjectViewCustom('custom', 'state', 'startKey', 'endKey')
659
- .then(objects => {
660
- Object.keys(objects).forEach(obj => console.log(obj._id));
661
- });
662
- ```
663
- - Replace all `socket.log.error('text')` to `socket.log('text', 'error')`
664
- - Add to App.js `import { AdminConnection } from '@iobroker/adapter-react-v5';` and `super(props, { Connection: AdminConnection });` if run in admin
665
-
666
- ## Migration from adapter-react-v5@4.x to adapter-react-v5@5.x
667
- - `Theme` is renamed to IobTheme. It is an object with classes inside. `Theme` is still inside and it same as mui `createTheme`.
668
- - adapter-react-v5 has all types exported. So you can use `import { type IobTheme, Theme } from '@iobroker/adapter-react-v5';` and `const theme: IobTheme = Theme('light');`
669
- - Json-Config is now an external package and must be included as dependency separately.
670
- - Use type `Translate` for `t(word: string, ...args: any[]) => string`
671
- - All components for admin JsonConfig must be changed:
672
- Before `adapter-react-v5@5.x`:
673
-
674
- ```
675
- import { ConfigGeneric, I18n } from '@iobroker/adapter-react-v5';
676
- class JsonComponent extends ConfigGeneric {
677
- ...
678
- }
679
- ```
680
-
681
- With `adapter-react-v5@5.x`:
682
-
683
- ```
684
- import { I18n } from '@iobroker/adapter-react-v5';
685
- import { ConfigGeneric } from '@iobroker/json-config';
686
- class JsonComponent extends ConfigGeneric {
687
- ...
688
- }
689
- ```
690
- ## Migration from v5 to v6
691
- The main change is that the `withStyles` was removed. So you have to replace all `withStyles` with `sx` or `style` properties.
692
-
693
- You can read more about sx [here](https://mui.com/system/getting-started/the-sx-prop/).
694
- - Remove at start of the file `import { withStyles } from '@mui/styles';`
695
- - Replace at the very end of the file `export default withStyles(styles)(MyComponent);` with `export default MyComponent;`
696
- - Modify `const styles`:
697
- Before:
698
- ```
699
- const styles: Record<string, any> = (theme: IobTheme) => ({
700
- dialog: {
701
- height: `calc(100% - ${theme.mixins.toolbar.minHeight}px)`,
702
- padding: theme.spacing(1),
703
- margin: theme.spacing(2),
704
- gap: 5,
705
- borderRadius: 5,
706
- marginLeft: 10, // marginTop, marginRight, marginBottom
707
- paddingLeft: 10, // paddingTop, paddingRight, paddingBottom
708
- },
709
- ...
710
- });
711
- ```
712
-
713
- After:
714
- ```
715
- const styles: Record<string, any> = {
716
- dialog: (theme: IobTheme) => ({
717
- height: `calc(100% - ${theme => theme.mixins.toolbar.minHeight}px)`,
718
- p: 1, // or 8px, padding is OK too
719
- m: '16px', // or 2, margin is OK too
720
- gap: '5px',
721
- borderRadius: '5px',
722
- ml: '10px', // mt, mr, mb, but marginLeft, marginRight, marginBottom is OK too
723
- pl: '10px', // pt, pr, pb, but paddingTop, paddingRight, paddingBottom is OK too
724
- }),
725
- };
726
- ```
727
-
728
- - Modify `className`:
729
- Before: `<div className={this.props.classes.box}>`
730
-
731
- After: `<Box sx={styles.box}>`
732
-
733
- Before: `<span className={Utils.clsx(this.props.classes.box1, condition && this.props.classes.box2)}>`
734
-
735
- After: `<Box component="span" sx={Utils.getStyle(this.props.theme, this.props.classes.box1, condition && this.props.classes.box2)}>`
736
- Or if no one style is a function: `<Box component="div" sx={{ ...this.props.classes.box1, ...(condition ? this.props.classes.box2 : undefined) }}>`
737
-
738
- Do not use `sx` if the style is not dynamic (not a function). Use `style` instead.
739
-
740
- Be aware, that all paddings and margins are now in `theme.spacing(1)` format.
741
- So you have to replace all `padding: 8` with `padding: 1` or with `padding: '8px'`.
742
-
743
- The best practice is to replace `padding` with `p` and `margin` with `m`, so you will see immediately that it is a padding or margin for `sx` property.
744
-
745
- - Modify `classes`:
746
- Before: `<Dialog classes={{ scrollPaper: this.props.classes.dialog, paper: this.props.classes.paper }}>`
747
- After: `<Dialog sx={{ '&.MuiDialog-scrollPaper': styles.dialog, '& .MuiDialog-paper': styles.paper }}>`,
748
-
749
- Before: `<Dialog classes={{ scrollPaper: this.props.classes.dialog, paper: this.props.classes.paper }}>`
750
- After: `<Dialog sx={{ '&.MuiDialog-scrollPaper': styles.dialog, '& .MuiDialog-paper': styles.paper }}>`
751
-
752
- Before: `<ListItem classes={{ root: this.props.classes.listItem }} >`,
753
- After: `<ListItem sx={{ '&.MuiListItem-root': styles.listItem }} >`
754
-
755
- Before: `<Typography component="h2" variant="h6" classes={{ root: this.props.classes.typography }}>`,
756
- After: `<Typography component="h2" variant="h6" sx={{ '&.MuiTypography-root': styles.typography }}>`
757
-
758
- Before: `<Badge classes={{ 'badge': this.props.classes.expertBadge }}>`,
759
- After: `<Badge sx={{ '& .MuiBadge-badge': styles.expertBadge }}>`
760
-
761
- Before: `<Tab classes={{ selected: this.props.classes..selected }} />`,
762
- After: `<Tab sx={{ '&.Mui-selected': styles.selected }} />`
763
-
764
- Before: `<Tabs classes={{ indicator: this.props.classes.indicator }} />`,
765
- After: `<Tabs sx={{ '& .MuiTabs-indicator': styles.indicator }} />`
766
-
767
- Before: `<Tooltip title={this.props.t('ra_Refresh tree')} classes={{ popper: this.props.classes.tooltip }}>`,
768
- After: `<Tooltip title={this.props.t('ra_Refresh tree')} componentsProps={{ popper: { sx: { pointerEvents: 'none' } } }}>`,
769
- Or: `<Tooltip title={this.props.t('ra_Refresh tree')} componentsProps={{ popper: { sx: styles.tooltip } }}>`
770
-
771
- Before. `<AccordionSummary classes={{ root: this.props.classes.rootStyle, content: this.props.classes.content }}>`,
772
- After. `<AccordionSummary sx={{ '&.MuiAccordionSummary-root': styles.rootStyle, '& .MuiAccordionSummary-content': styles.content }}>`
773
-
774
- Before. `<Drawer classes={{ paper: this.props.classes.paperStyle }}>`,
775
- After. `<Drawer sx={{ '& .MuiDrawer-paper': styles.paperStyle }}>`
776
-
777
- <!--
778
- Placeholder for the next version (at the beginning of the line):
779
- ### **WORK IN PROGRESS**
780
- -->
781
-
1
+ # Help ReactJS classes for adapter config
2
+ You can find demo on https://github.com/ioBroker/adapter-react-demo
3
+
4
+ ## Getting started
5
+ If you want to create the configuration page with ReactJS:
6
+ 1. Create github repo for adapter.
7
+ 2. execute `npx create-react-app src` . It will take a while.
8
+ 3. `cd src`
9
+ 4. Modify package.json file in src directory:
10
+ - Change `name` from `src` to `ADAPTERNAME-admin` (Of course replace `ADAPTERNAME` with yours)
11
+ - Add to devDependencies:
12
+ ```
13
+ "@iobroker/adapter-react": "^4.0.10",
14
+ ```
15
+ Versions can be higher.
16
+ So your src/package.json should look like:
17
+ ```
18
+ {
19
+ "name": "ADAPTERNAME-admin",
20
+ "version": "0.1.0",
21
+ "private": true,
22
+ "dependencies": {
23
+ "react": "^18.2.0",
24
+ "react-dom": "^18.2.0",
25
+ "react-icons": "^4.6.0",
26
+ "react-scripts": "^5.0.1",
27
+ "@iobroker/adapter-react-v5": "^3.2.7",
28
+ "del": "^6.1.1",
29
+ "gulp": "^4.0.2"
30
+ },
31
+ "scripts": {
32
+ "start": "react-scripts start",
33
+ "build": "react-scripts build",
34
+ "test": "react-scripts test",
35
+ "eject": "react-scripts eject"
36
+ },
37
+ "eslintConfig": {
38
+ "extends": "react-app"
39
+ },
40
+ "homepage": ".",
41
+ "browserslist": [
42
+ ">0.2%",
43
+ "not dead",
44
+ "not ie <= 11",
45
+ "not op_mini all"
46
+ ]
47
+ }
48
+ ```
49
+ 5. Call in `src`: `npm install`
50
+ 6. Copy tasks.js into `src`: `cp node_modules/@iobroker/adapter-react/tasks.js tasks.js`
51
+ 7. Start your dummy application `npm run start` for developing or build with `npm run build` and
52
+ copy files in `build` directory to `www` or to `admin`. In the admin you must rename `index.html` to `index_m.html`.
53
+ 8. You can do that with `gulp` tasks: `gulp build`, `gulp copy`, `gulp renameIndex` or `gulp renameTab`
54
+
55
+ ## Development
56
+ 1. Add `socket.io` to `public/index.html`.
57
+ After
58
+
59
+ ```
60
+ <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
61
+ ```
62
+
63
+ insert
64
+
65
+ ```
66
+ <script>
67
+ var script = document.createElement('script');
68
+ window.registerSocketOnLoad = function (cb) {
69
+ window.socketLoadedHandler = cb;
70
+ };
71
+ const parts = (window.location.search || '').replace(/^\?/, '').split('&');
72
+ const query = {};
73
+ parts.forEach(item => {
74
+ const [name, val] = item.split('=');
75
+ query[decodeURIComponent(name)] = val !== undefined ? decodeURIComponent(val) : true;
76
+ });
77
+ script.onload = function () { typeof window.socketLoadedHandler === 'function' && window.socketLoadedHandler(); };
78
+ script.src = window.location.port === '3000' ? window.location.protocol + '//' + (query.host || window.location.hostname) + ':' + (query.port || 8081) + '/lib/js/socket.io.js' : '%PUBLIC_URL%/../../lib/js/socket.io.js';
79
+
80
+ document.head.appendChild(script);
81
+ </script>
82
+ ```
83
+
84
+ 3. Add to App.js constructor initialization for I18n:
85
+ ```
86
+ class App extends GenericApp {
87
+ constructor(props) {
88
+ const extendedProps = {...props};
89
+ extendedProps.encryptedFields = ['pass']; // this parameter will be encrypted and decrypted automatically
90
+ extendedProps.translations = {
91
+ 'en': require('./i18n/en'),
92
+ 'de': require('./i18n/de'),
93
+ 'ru': require('./i18n/ru'),
94
+ 'pt': require('./i18n/pt'),
95
+ 'nl': require('./i18n/nl'),
96
+ 'fr': require('./i18n/fr'),
97
+ 'it': require('./i18n/it'),
98
+ 'es': require('./i18n/es'),
99
+ 'pl': require('./i18n/pl'),
100
+ 'uk': require('./i18n/uk'),
101
+ 'zh-cn': require('./i18n/zh-cn'),
102
+ };
103
+ // get actual admin port
104
+ extendedProps.socket = {port: parseInt(window.location.port, 10)};
105
+
106
+ // Only if close, save buttons are not required at the bottom (e.g. if admin tab)
107
+ // extendedProps.bottomButtons = false;
108
+
109
+ // only for debug purposes
110
+ if (extendedProps.socket.port === 3000) {
111
+ extendedProps.socket.port = 8081;
112
+ }
113
+
114
+ // allow to manage GenericApp the sentry initialisation or do not set the sentryDSN if no sentry available
115
+ extendedProps.sentryDSN = 'https://yyy@sentry.iobroker.net/xx';
116
+
117
+ super(extendedProps);
118
+ }
119
+ ...
120
+ }
121
+ ```
122
+
123
+ 4. Replace `index.js` with the following code to support themes:
124
+ ```
125
+ import React from 'react';
126
+ import ReactDOM from 'react-dom';
127
+ import { MuiThemeProvider} from '@material-ui/core/styles';
128
+ import * as serviceWorker from './serviceWorker';
129
+
130
+ import './index.css';
131
+ import App from './App';
132
+ import { version } from '../package.json';
133
+
134
+ import theme from '@iobroker/adapter-react/Theme';
135
+
136
+ console.log('iobroker.scenes@' + version);
137
+ let themeName = window.localStorage ? window.localStorage.getItem('App.theme') || 'light' : 'light';
138
+
139
+ function build() {
140
+ return ReactDOM.render(<MuiThemeProvider theme={ theme(themeName) }>
141
+ <App onThemeChange={_theme => {
142
+ themeName = _theme;
143
+ build();
144
+ }}/>
145
+ </MuiThemeProvider>, document.getElementById('root'));
146
+ }
147
+
148
+ build();
149
+
150
+ // If you want your app to work offline and load faster, you can change
151
+ // unregister() to register() below. Note this comes with some pitfalls.
152
+ // Learn more about service workers: http://bit.ly/CRA-PWA
153
+ serviceWorker.unregister();
154
+ ```
155
+
156
+ 5. Add to App.js encoding and decoding of values:
157
+ ```
158
+ class App extend GenericApp {
159
+ ...
160
+ onPrepareLoad(settings) {
161
+ settings.pass = this.decode(settings.pass);
162
+ }
163
+ onPrepareSave(settings) {
164
+ settings.pass = this.encode(settings.pass);
165
+ }
166
+ }
167
+ ```
168
+
169
+ 6. The optional step is to validate the data to be saved:
170
+ ```
171
+ onPrepareSave(settings) {
172
+ super.onPrepareSave(settings);
173
+ if (DATA_INVALID) {
174
+ return false; // configuration will not be saved
175
+ } else {
176
+ return true;
177
+ }
178
+ }
179
+ ```
180
+
181
+ ## Components
182
+
183
+ ### Connection.tsx
184
+ This is a non-react class to provide the communication for socket connection with the server.
185
+
186
+ ### GenericApp.tsx
187
+
188
+ ### i18n.ts
189
+
190
+ ### Theme.tsx
191
+
192
+ ### Dialogs
193
+ Some dialogs are predefined and could be used out of the box.
194
+
195
+ #### Confirm.tsx
196
+ <!-- TODO: Provide screenshot here -->
197
+
198
+ Usage:
199
+ ```
200
+ import React from 'react';
201
+ import ConfirmDialog from '@iobroker/adapter-react/Dialogs/Confirm'
202
+ import I18n from '@iobroker/adapter-react/i18n';
203
+
204
+ class ExportImportDialog extends React.Component {
205
+ constructor(props) {
206
+ super(props);
207
+
208
+ this.state = {
209
+ confirmDialog: false,
210
+ };
211
+ }
212
+
213
+ renderConfirmDialog() {
214
+ if (!this.state.confirmDialog) {
215
+ return null;
216
+ }
217
+ return <ConfirmDialog
218
+ title={ I18n.t('Scene will be overwritten.') }
219
+ text={ I18n.t('All data will be lost. Confirm?') }
220
+ ok={ I18n.t('Yes') }
221
+ cancel={ I18n.t('Cancel') }
222
+ suppressQuestionMinutes={5}
223
+ dialogName="myConfirmDialogThatCouldBeSuppressed"
224
+ suppressText={I18n.t('Suppress question for next %s minutes', 5)}
225
+ onClose={isYes => {
226
+ this.setState({ confirmDialog: false} );
227
+ }}
228
+ />;
229
+ }
230
+ render() {
231
+ return <div>
232
+ <Button onClick={ () => this.setState({confirmDialog: true}) }>Click</Button>
233
+ { this.renderConfirmDialog() }
234
+ </div>
235
+ }
236
+ }
237
+
238
+ export default ExportImportDialog;
239
+ ```
240
+
241
+ #### Error.tsx
242
+ <!-- TODO: Provide screenshot here -->
243
+
244
+ #### Message.tsx
245
+ <!-- TODO: Provide screenshot here -->
246
+ ```
247
+ renderMessage() {
248
+ if (this.state.showMessage) {
249
+ return <Message
250
+ text={this.state.showMessage}
251
+ onClose={() => this.setState({showMessage: false})}
252
+ />;
253
+ } else {
254
+ return null;
255
+ }
256
+ }
257
+ ```
258
+
259
+ #### SelectID.tsx
260
+ ![Logo](img/selectID.png)
261
+ ```
262
+ import DialogSelectID from '@iobroker/adapter-react/Dialogs/SelectID';
263
+
264
+ class MyComponent extends Component {
265
+ constructor(props) {
266
+ super(props);
267
+ this.state = {
268
+ showSelectId: false,
269
+ };
270
+ }
271
+
272
+ renderSelectIdDialog() {
273
+ if (this.state.showSelectId) {
274
+ return <DialogSelectID
275
+ key="tableSelect"
276
+ imagePrefix="../.."
277
+ dialogName={this.props.adapterName}
278
+ themeType={this.props.themeType}
279
+ socket={this.props.socket}
280
+ statesOnly={true}
281
+ selected={this.state.selectIdValue}
282
+ onClose={() => this.setState({showSelectId: false})}
283
+ onOk={(selected, name) => {
284
+ this.setState({showSelectId: false, selectIdValue: selected});
285
+ }}
286
+ />;
287
+ } else {
288
+ return null;
289
+ }
290
+ }
291
+ render() {
292
+ return renderSelectIdDialog();
293
+ }
294
+ }
295
+ ```
296
+
297
+ #### Cron
298
+ Include `"react-text-mask": "^5.4.3",` in package.json.
299
+
300
+ <!-- TODO: Provide screenshot here -->
301
+
302
+ ```
303
+ function renderCron() {
304
+ if (!showCron) {
305
+ return null;
306
+ } else {
307
+ return <DialogCron
308
+ key="dialogCron1"
309
+ cron={this.state.cronValue || '* * * * *'}
310
+ onClose={() => this.setState({ showCron: false })}
311
+ onOk={cronValue => {
312
+ this.setState({ cronValue })
313
+ }}
314
+ />;
315
+ }
316
+ }
317
+ ```
318
+
319
+ ### Components
320
+
321
+ #### Utils.tsx
322
+ ##### getObjectNameFromObj
323
+ `getObjectNameFromObj(obj, settings, options, isDesc)`
324
+
325
+ Get object name from a single object.
326
+
327
+ Usage: `Utils.getObjectNameFromObj(this.objects[id], null, {language: I18n.getLanguage()})`
328
+
329
+ ##### getObjectIcon
330
+ `getObjectIcon(id, obj)`
331
+
332
+ Get icon from the object.
333
+
334
+ Usage:
335
+ ```
336
+ const icon = Utils.getObjectIcon(id, this.objects[id]);
337
+ return (<img src={icon}/>);
338
+ ```
339
+
340
+ ##### isUseBright
341
+ `isUseBright(color, defaultValue)`
342
+
343
+ Usage: `
344
+
345
+ #### Loader.tsx
346
+ ![Logo](img/loader.png)
347
+
348
+ ```
349
+ render() {
350
+ if (!this.state.loaded) {
351
+ return <MuiThemeProvider theme={this.state.theme}>
352
+ <Loader theme={this.state.themeType}/>
353
+ </MuiThemeProvider>;
354
+ }
355
+ // render loaded data
356
+ }
357
+
358
+ ```
359
+
360
+ #### Logo.tsx
361
+ ![Logo](img/logo.png)
362
+
363
+ ```
364
+ render() {
365
+ return <form className={this.props.classes.tab}>
366
+ <Logo
367
+ instance={this.props.instance}
368
+ common={this.props.common}
369
+ native={this.props.native}
370
+ onError={text => this.setState({errorText: text})}
371
+ onLoad={this.props.onLoad}
372
+ />
373
+ ...
374
+ </form>;
375
+ }
376
+ ```
377
+
378
+ #### Router.tsx
379
+
380
+ #### ObjectBrowser.js
381
+ It is better to use `Dialog/SelectID`, but if you want:
382
+
383
+ ![Logo](img/objectBrowser.png)
384
+
385
+ ```
386
+ <ObjectBrowser
387
+ foldersFirst={this.props.foldersFirst}
388
+ imagePrefix={this.props.imagePrefix || this.props.prefix} // prefix is for back compatibility
389
+ defaultFilters={this.filters}
390
+ dialogName={this.dialogName}
391
+ showExpertButton={this.props.showExpertButton !== undefined ? this.props.showExpertButton : true}
392
+ style={{ width: '100%', height: '100%' }}
393
+ columns={this.props.columns || ['name', 'type', 'role', 'room', 'func', 'val']}
394
+ types={this.props.types || ['state']}
395
+ t={I18n.t}
396
+ lang={this.props.lang || I18n.getLanguage()}
397
+ socket={this.props.socket}
398
+ selected={this.state.selected}
399
+ multiSelect={this.props.multiSelect}
400
+ notEditable={this.props.notEditable === undefined ? true : this.props.notEditable}
401
+ name={this.state.name}
402
+ themeName={this.props.themeName}
403
+ themeType={this.props.themeType}
404
+ customFilter={this.props.customFilter}
405
+ onFilterChanged={filterConfig => {
406
+ this.filters = filterConfig;
407
+ window.localStorage.setItem(this.dialogName, JSON.stringify(filterConfig));
408
+ }}
409
+ onSelect={(selected, name, isDouble) => {
410
+ if (JSON.stringify(selected) !== JSON.stringify(this.state.selected)) {
411
+ this.setState({selected, name}, () =>
412
+ isDouble && this.handleOk());
413
+ } else if (isDouble) {
414
+ this.handleOk();
415
+ }
416
+ }}
417
+ />
418
+ ```
419
+
420
+ #### TreeTable.ts
421
+ ![Logo](img/tableTree.png)
422
+
423
+ ```
424
+ // STYLES
425
+ const styles = theme => ({
426
+ tableDiv: {
427
+ width: '100%',
428
+ overflow: 'hidden',
429
+ height: 'calc(100% - 48px)',
430
+ },
431
+ });
432
+ class MyComponent extends Component {
433
+ constructor(props) {
434
+ super(props);
435
+
436
+ this.state = {
437
+ data: [
438
+ {
439
+ id: 'UniqueID1' // required
440
+ fieldIdInData: 'Name1',
441
+ myType: 'number',
442
+ },
443
+ {
444
+ id: 'UniqueID2' // required
445
+ fieldIdInData: 'Name12',
446
+ myType: 'string',
447
+ },
448
+ ],
449
+ };
450
+
451
+ this.columns = [
452
+ {
453
+ title: 'Name of field', // required, else it will be "field"
454
+ field: 'fieldIdInData', // required
455
+ editable: false, // or true [default - true]
456
+ cellStyle: { // CSS style - // optional
457
+ maxWidth: '12rem',
458
+ overflow: 'hidden',
459
+ wordBreak: 'break-word',
460
+ },
461
+ lookup: { // optional => edit will be automatically "SELECT"
462
+ 'value1': 'text1',
463
+ 'value2': 'text2',
464
+ }
465
+ },
466
+ {
467
+ title: 'Type', // required, else it will be "field"
468
+ field: 'myType', // required
469
+ editable: true, // or true [default - true]
470
+ lookup: { // optional => edit will be automatically "SELECT"
471
+ 'number': 'Number',
472
+ 'string': 'String',
473
+ 'boolean': 'Boolean',
474
+ },
475
+ type: 'number/string/color/oid/icon/boolean', // oid=ObjectID,icon=base64-icon
476
+ editComponent: props =>
477
+ <div>Prefix&#123; <br/>
478
+ <textarea
479
+ rows={4}
480
+ style={{width: '100%', resize: 'vertical'}}
481
+ value={props.value}
482
+ onChange={e => props.onChange(e.target.value)}
483
+ />
484
+ Suffix
485
+ </div>,
486
+ },
487
+ ];
488
+ }
489
+ // renderTable
490
+ render() {
491
+ return <div className={this.props.classes.tableDiv}>
492
+ <TreeTable
493
+ columns={this.columns}
494
+ data={this.state.data}
495
+ onUpdate={(newData, oldData) => {
496
+ const data = JSON.parse(JSON.stringify(this.state.data));
497
+
498
+ // Added new line
499
+ if (newData === true) {
500
+ // find unique ID
501
+ let i = 1;
502
+ let id = 'line_' + i;
503
+
504
+ // eslint-disable-next-line
505
+ while(this.state.data.find(item => item.id === id)) {
506
+ i++;
507
+ id = 'line_' + i;
508
+ }
509
+
510
+ data.push({
511
+ id,
512
+ name: I18n.t('New resource') + '_' + i,
513
+ color: '',
514
+ icon: '',
515
+ unit: '',
516
+ price: 0,
517
+ });
518
+ } else {
519
+ // existing line was modifed
520
+ const pos = this.state.data.indexOf(oldData);
521
+ if (pos !== -1) {
522
+ Object.keys(newData).forEach(attr => data[pos][attr] = newData[attr]);
523
+ }
524
+ }
525
+
526
+ this.setState({data});
527
+ }}
528
+ onDelete={oldData => {
529
+ console.log('Delete: ' + JSON.stringify(oldData));
530
+ const pos = this.state.data.indexOf(oldData);
531
+ if (pos !== -1) {
532
+ const data = JSON.parse(JSON.stringify(this.state.data));
533
+ data.splice(pos, 1);
534
+ this.setState({data});
535
+ }
536
+ }}
537
+ />
538
+ </div>;
539
+ }
540
+ }
541
+ ```
542
+
543
+ #### Toast
544
+ <!-- TODO: Provide screenshot here -->
545
+
546
+ Toast is not a part of `adapter-react` but it is an example how to use toast in application:
547
+
548
+ ```
549
+ import Snackbar from '@material-ui/core/Snackbar';
550
+
551
+ class MyComponent {
552
+ constructor(props) {
553
+ super(props);
554
+ this.state = {
555
+ // ....
556
+ toast: '',
557
+ };
558
+ }
559
+ // ...
560
+ renderToast() {
561
+ if (!this.state.toast) {
562
+ return null;
563
+ }
564
+ return <Snackbar
565
+ anchorOrigin={{
566
+ vertical: 'bottom',
567
+ horizontal: 'left',
568
+ }}
569
+ open={true}
570
+ autoHideDuration={6000}
571
+ onClose={() => this.setState({toast: ''})}
572
+ ContentProps={{'aria-describedby': 'message-id'}}
573
+ message={<span id="message-id">{this.state.toast}</span>}
574
+ action={[
575
+ <IconButton
576
+ key="close"
577
+ aria-label="Close"
578
+ color="inherit"
579
+ className={this.props.classes.close}
580
+ onClick={() => this.setState({toast: ''})}
581
+ >
582
+ <IconClose />
583
+ </IconButton>,
584
+ ]}
585
+ />;
586
+ }
587
+ render() {
588
+ return <div>
589
+ {this.renderToast()}
590
+ </div>;
591
+ }
592
+ }
593
+ ```
594
+
595
+ ## List of adapters that use adapter-react
596
+ - Admin
597
+ - Backitup
598
+ - iot
599
+ - echarts
600
+ - text2command
601
+ - scenes
602
+ - javascript
603
+ - devices
604
+ - eventlist
605
+ - cameras
606
+ - web
607
+ - vis-2
608
+ - vis-2-widgets-xxx
609
+ - fullcalendar
610
+ - openweathermap
611
+
612
+ ## Usability
613
+ In dialogs, the OK button is first (on the left) and the cancel button is last (on the right)
614
+
615
+ ## Used icons
616
+ This project uses icons from [Flaticon](https://www.flaticon.com/).
617
+
618
+ ioBroker GmbH has a valid license for all the used icons.
619
+ The icons may not be reused in other projects without the proper flaticon license or flaticon subscription.
620
+
621
+ ## Migration from adapter-react to adapter-react-v5
622
+ ### In src/package.json => dependencies
623
+ - `"@iobroker/adapter-react": "^2.0.22",` => `"@iobroker/adapter-react-v5": "^3.1.34",`
624
+ - `"@material-ui/core": "^4.12.3",` => `"@mui/material": "^5.10.9",`
625
+ - `"@material-ui/icons": "^4.11.2",` => `"@mui/icons-material": "^5.10.9",`
626
+ - Add `"@mui/styles": "^5.10.9",`
627
+ - Add `"babel-eslint": "^10.1.0",`
628
+
629
+ ### In Source files
630
+ - All `@iobroker/adapter-react/...` => `@iobroker/adapter-react-v5/...`
631
+ - All `@material-ui/icons/...` => `@mui/icons-material/...`
632
+ - Change `import { withStyles } from '@material-ui/core/styles';` => `import { withStyles } from '@mui/styles';`
633
+ - Change `import { makeStyles } from '@mui/material/styles';` => `import { makeStyles } from '@mui/styles';`
634
+ - Change `import withWidth from '@material-ui/core/withWidth';` => `import { withWidth } from '@iobroker/adapter-react-v5';`
635
+ - All `@material-ui/core...` => `@mui/material...`
636
+ - Change `import { MuiThemeProvider } from '@material-ui/core/styles';` => `import { ThemeProvider, StyledEngineProvider } from '@mui/material/styles';`
637
+ - Change all `<MuiThemeProvider theme={this.state.theme}>` to `<StyledEngineProvider injectFirst><ThemeProvider theme={this.state.theme}>`
638
+ - Rename in styles `theme.palette.type` => `theme.palette.mode`
639
+ - Add to all `TextField`, `Select`, `FormControl` the property `variant="standard"`
640
+ - Add to all `Button` that do not have `color` property: `color="grey"`
641
+ - Replace by `TextField` the `readOnly` attribute (if exists) with `InputProps={{readOnly: true}}`
642
+ - Remove px by all `theme.spacing`: `calc(100% - ${theme.spacing(4)}px)` => `calc(100% - ${theme.spacing(4)})`
643
+ - Replace `this.selectTab(e.target.parentNode.dataset.name, index)` => `this.selectTab(e.target.dataset.name, index)`
644
+
645
+ If you still have questions, try to find an answer [here](https://mui.com/guides/migration-v4/).
646
+
647
+ ## Migration from adapter-react-v5@3.x to adapter-react-v5@4.x
648
+ - Look for getObjectView socket requests and replace `socket.getObjectView('startKey', 'endKey', 'instance')` to `socket.getObjectViewSystem('instance', 'startKey', 'endKey')`
649
+ - Look for calls of custom like
650
+ ```
651
+ this.props.socket._socket.emit('getObjectView', 'system', 'custom', {startKey: '', endKey:'\u9999'}, (err, objs) => {
652
+ (objs?.rows || [])
653
+ .forEach(item => console.log(item.id, item.value));
654
+ });
655
+ ```
656
+ to
657
+ ```
658
+ socket.getObjectViewCustom('custom', 'state', 'startKey', 'endKey')
659
+ .then(objects => {
660
+ Object.keys(objects).forEach(obj => console.log(obj._id));
661
+ });
662
+ ```
663
+ - Replace all `socket.log.error('text')` to `socket.log('text', 'error')`
664
+ - Add to App.js `import { AdminConnection } from '@iobroker/adapter-react-v5';` and `super(props, { Connection: AdminConnection });` if run in admin
665
+
666
+ ## Migration from adapter-react-v5@4.x to adapter-react-v5@5.x
667
+ - `Theme` is renamed to IobTheme. It is an object with classes inside. `Theme` is still inside and it same as mui `createTheme`.
668
+ - adapter-react-v5 has all types exported. So you can use `import { type IobTheme, Theme } from '@iobroker/adapter-react-v5';` and `const theme: IobTheme = Theme('light');`
669
+ - Json-Config is now an external package and must be included as dependency separately.
670
+ - Use type `Translate` for `t(word: string, ...args: any[]) => string`
671
+ - All components for admin JsonConfig must be changed:
672
+ Before `adapter-react-v5@5.x`:
673
+
674
+ ```
675
+ import { ConfigGeneric, I18n } from '@iobroker/adapter-react-v5';
676
+ class JsonComponent extends ConfigGeneric {
677
+ ...
678
+ }
679
+ ```
680
+
681
+ With `adapter-react-v5@5.x`:
682
+
683
+ ```
684
+ import { I18n } from '@iobroker/adapter-react-v5';
685
+ import { ConfigGeneric } from '@iobroker/json-config';
686
+ class JsonComponent extends ConfigGeneric {
687
+ ...
688
+ }
689
+ ```
690
+ ## Migration from v5 to v6
691
+ The main change is that the `withStyles` was removed. So you have to replace all `withStyles` with `sx` or `style` properties.
692
+
693
+ You can read more about sx [here](https://mui.com/system/getting-started/the-sx-prop/).
694
+ - Remove at start of the file `import { withStyles } from '@mui/styles';`
695
+ - Replace it at the very end of the file `export default withStyles(styles)(MyComponent);` with `export default MyComponent;`
696
+ - Modify `const styles`:
697
+ Before:
698
+ ```
699
+ const styles: Record<string, any> = (theme: IobTheme) => ({
700
+ dialog: {
701
+ height: `calc(100% - ${theme.mixins.toolbar.minHeight}px)`,
702
+ padding: theme.spacing(1),
703
+ margin: theme.spacing(2),
704
+ gap: 5,
705
+ borderRadius: 5,
706
+ marginLeft: 10, // marginTop, marginRight, marginBottom
707
+ paddingLeft: 10, // paddingTop, paddingRight, paddingBottom
708
+ },
709
+ ...
710
+ });
711
+ ```
712
+
713
+ After:
714
+ ```
715
+ const styles: Record<string, any> = {
716
+ dialog: (theme: IobTheme) => ({
717
+ height: `calc(100% - ${theme => theme.mixins.toolbar.minHeight}px)`,
718
+ p: 1, // or 8px, padding is OK too
719
+ m: '16px', // or 2, margin is OK too
720
+ gap: '5px',
721
+ borderRadius: '5px',
722
+ ml: '10px', // mt, mr, mb, but marginLeft, marginRight, marginBottom is OK too
723
+ pl: '10px', // pt, pr, pb, but paddingTop, paddingRight, paddingBottom is OK too
724
+ }),
725
+ };
726
+ ```
727
+
728
+ - Modify `className`:
729
+ Before: `<div className={this.props.classes.box}>`
730
+
731
+ After: `<Box sx={styles.box}>`
732
+
733
+ Before: `<span className={Utils.clsx(this.props.classes.box1, condition && this.props.classes.box2)}>`
734
+
735
+ After: `<Box component="span" sx={Utils.getStyle(this.props.theme, this.props.classes.box1, condition && this.props.classes.box2)}>`
736
+ Or if no one style is a function: `<Box component="div" sx={{ ...this.props.classes.box1, ...(condition ? this.props.classes.box2 : undefined) }}>`
737
+
738
+ Do not use `sx` if the style is not dynamic (not a function). Use `style` instead.
739
+
740
+ Be aware, that all paddings and margins are now in `theme.spacing(1)` format.
741
+ So you have to replace all `padding: 8` with `padding: 1` or with `padding: '8px'`.
742
+
743
+ The best practice is to replace `padding` with `p` and `margin` with `m`, so you will see immediately that it is a padding or margin for `sx` property.
744
+
745
+ - Modify `classes`:
746
+ Before: `<Dialog classes={{ scrollPaper: this.props.classes.dialog, paper: this.props.classes.paper }}>`
747
+ After: `<Dialog sx={{ '&.MuiDialog-scrollPaper': styles.dialog, '& .MuiDialog-paper': styles.paper }}>`,
748
+
749
+ Before: `<Dialog classes={{ scrollPaper: this.props.classes.dialog, paper: this.props.classes.paper }}>`
750
+ After: `<Dialog sx={{ '&.MuiDialog-scrollPaper': styles.dialog, '& .MuiDialog-paper': styles.paper }}>`
751
+
752
+ Before: `<ListItem classes={{ root: this.props.classes.listItem }} >`,
753
+ After: `<ListItem sx={{ '&.MuiListItem-root': styles.listItem }} >`
754
+
755
+ Before: `<Typography component="h2" variant="h6" classes={{ root: this.props.classes.typography }}>`,
756
+ After: `<Typography component="h2" variant="h6" sx={{ '&.MuiTypography-root': styles.typography }}>`
757
+
758
+ Before: `<Badge classes={{ 'badge': this.props.classes.expertBadge }}>`,
759
+ After: `<Badge sx={{ '& .MuiBadge-badge': styles.expertBadge }}>`
760
+
761
+ Before: `<Tab classes={{ selected: this.props.classes..selected }} />`,
762
+ After: `<Tab sx={{ '&.Mui-selected': styles.selected }} />`
763
+
764
+ Before: `<Tabs classes={{ indicator: this.props.classes.indicator }} />`,
765
+ After: `<Tabs sx={{ '& .MuiTabs-indicator': styles.indicator }} />`
766
+
767
+ Before: `<Tooltip title={this.props.t('ra_Refresh tree')} classes={{ popper: this.props.classes.tooltip }}>`,
768
+ After: `<Tooltip title={this.props.t('ra_Refresh tree')} componentsProps={{ popper: { sx: { pointerEvents: 'none' } } }}>`,
769
+ Or: `<Tooltip title={this.props.t('ra_Refresh tree')} componentsProps={{ popper: { sx: styles.tooltip } }}>`
770
+
771
+ Before. `<AccordionSummary classes={{ root: this.props.classes.rootStyle, content: this.props.classes.content }}>`,
772
+ After. `<AccordionSummary sx={{ '&.MuiAccordionSummary-root': styles.rootStyle, '& .MuiAccordionSummary-content': styles.content }}>`
773
+
774
+ Before. `<Drawer classes={{ paper: this.props.classes.paperStyle }}>`,
775
+ After. `<Drawer sx={{ '& .MuiDrawer-paper': styles.paperStyle }}>`
776
+
777
+ <!--
778
+ Placeholder for the next version (at the beginning of the line):
779
+ ### **WORK IN PROGRESS**
780
+ -->
781
+
782
782
  ## Changelog
783
- ### 6.1.10 (2024-08-30)
783
+ ### 7.0.2 (2024-09-10)
784
+ * (bluefox) Showed the context menu under cursor position in the object browser
785
+ * (bluefox) Added links to aliases in the object browser
786
+
787
+ ### 7.0.1 (2024-08-29)
788
+ * (bluefox) Updated the object browser
789
+ * (bluefox) Used MUI Library 6.0
790
+
791
+ ### 6.1.10 (2024-08-30)
784
792
  * (bluefox) Updated the object browser
785
793
 
786
- ### 6.1.9 (2024-08-14)
794
+ ### 6.1.9 (2024-08-14)
787
795
  * (bluefox) Updated JSON schema
788
796
 
789
- ### 6.1.8 (2024-08-03)
797
+ ### 6.1.8 (2024-08-03)
790
798
  * (bluefox) Added translations
791
799
 
792
- ### 6.1.6 (2024-07-23)
800
+ ### 6.1.6 (2024-07-23)
793
801
  * (bluefox) Optimize package
794
802
 
795
- ### 6.1.5 (2024-07-20)
803
+ ### 6.1.5 (2024-07-20)
796
804
  * (bluefox) Added sources to package
797
805
 
798
- ### 6.1.3 (2024-07-20)
806
+ ### 6.1.3 (2024-07-20)
799
807
  * (bluefox) Better typing of legacy connection
800
808
 
801
- ### 6.1.1 (2024-07-16)
809
+ ### 6.1.1 (2024-07-16)
802
810
  * (bluefox) Added translations
803
811
 
804
- ### 6.1.0 (2024-07-15)
812
+ ### 6.1.0 (2024-07-15)
805
813
  * (bluefox) Replace by CRON to text the package to `cronstrue`
806
814
 
807
- ### 6.0.19 (2024-07-14)
815
+ ### 6.0.19 (2024-07-14)
808
816
  * (bluefox) added some packages for federation
809
817
 
810
- ### 6.0.17 (2024-07-14)
811
- * (bluefox) Allowed playing mp3 files in the file browser
818
+ ### 6.0.17 (2024-07-14)
819
+ * (bluefox) Allowed playing mp3 files in the file browser
812
820
  * (bluefox) Corrected jump by object selection
813
821
 
814
- ### 6.0.14 (2024-07-07)
822
+ ### 6.0.14 (2024-07-07)
815
823
  * (bluefox) Corrected theme type selection
816
824
 
817
- ### 6.0.13 (2024-06-30)
825
+ ### 6.0.13 (2024-06-30)
818
826
  * (bluefox) Corrected color picker
819
827
 
820
- ### 6.0.12 (2024-06-29)
828
+ ### 6.0.12 (2024-06-29)
821
829
  * (bluefox) Added support for the overrides in the theme
822
830
 
823
- ### 6.0.10 (2024-06-27)
824
- * (bluefox) Added translation
831
+ ### 6.0.10 (2024-06-27)
832
+ * (bluefox) Added translation
825
833
  * (bluefox) Mobile object browser improved
826
834
 
827
- ### 6.0.9 (2024-06-26)
835
+ ### 6.0.9 (2024-06-26)
828
836
  * (bluefox) Corrected Icons
829
837
 
830
- ### 6.0.8 (2024-06-26)
831
- * (bluefox) Corrected types of the select ID dialog
838
+ ### 6.0.8 (2024-06-26)
839
+ * (bluefox) Corrected types of the select ID dialog
832
840
  * (bluefox) Made the tooltips neutral to the pointer events
833
841
 
834
- ### 6.0.6 (2024-06-24)
835
- * (bluefox) Synchronised with admin
842
+ ### 6.0.6 (2024-06-24)
843
+ * (bluefox) Synchronised with admin
836
844
  * (bluefox) Added translations for time scheduler
837
845
 
838
- ### 6.0.4 (2024-06-21)
839
- * (bluefox) Removed the usage of `withStyles` in favor of `sx` and `style` properties (see [Migration from v5 to v6](#migration-from-v5-to-v6)
846
+ ### 6.0.4 (2024-06-21)
847
+ * (bluefox) Removed the usage of `withStyles` in favor of `sx` and `style` properties (see [Migration from v5 to v6](#migration-from-v5-to-v6)
840
848
  * (bluefox) (BREAKING) Higher version of `@mui/material` (5.15.20) is used
841
849
 
842
- ### 5.0.8 (2024-06-15)
850
+ ### 5.0.8 (2024-06-15)
843
851
  * (bluefox) Added `modulefederation.admin.config.js` for module federation
844
852
 
845
- ### 5.0.5 (2024-06-10)
853
+ ### 5.0.5 (2024-06-10)
846
854
  * (bluefox) Sources were synchronized with admin
847
855
 
848
- ### 5.0.4 (2024-06-07)
856
+ ### 5.0.4 (2024-06-07)
849
857
  * (bluefox) Added better typing
850
858
 
851
- ### 5.0.2 (2024-05-30)
852
- * (bluefox) Added better typing
859
+ ### 5.0.2 (2024-05-30)
860
+ * (bluefox) Added better typing
853
861
  * (bluefox) Json-Config is now a separate package and must be installed additionally
854
862
 
855
- ### 5.0.0 (2024-05-29)
856
- * (bluefox) Types are now exported
857
- * (bluefox) Translator renamed to Translate
863
+ ### 5.0.0 (2024-05-29)
864
+ * (bluefox) Types are now exported
865
+ * (bluefox) Translator renamed to Translate
858
866
  * (bluefox) Breaking: Theme renamed to IobTheme because of the naming conflict
859
867
 
860
- ### 4.13.24 (2024-05-25)
861
- * (bluefox) Updated packages
862
-
863
- * ### 4.13.22 (2024-05-23)
868
+ ### 4.13.24 (2024-05-25)
869
+ * (bluefox) Updated packages
870
+
871
+ * ### 4.13.22 (2024-05-23)
864
872
  * (bluefox) Updated packages
865
873
 
866
- ### 4.13.20 (2024-05-22)
867
- * (bluefox) Better types added
868
- * (bluefox) updated theme definitions
874
+ ### 4.13.20 (2024-05-22)
875
+ * (bluefox) Better types added
876
+ * (bluefox) updated theme definitions
869
877
  * (bluefox) corrected dates in cron dialog
870
878
 
871
- ### 4.13.14 (2024-05-19)
879
+ ### 4.13.14 (2024-05-19)
872
880
  * (bluefox) Updated packages
873
881
 
874
- ### 4.13.13 (2024-05-09)
882
+ ### 4.13.13 (2024-05-09)
875
883
  * (bluefox) Updated ioBroker types
876
884
 
877
- ### 4.13.12 (2024-05-06)
885
+ ### 4.13.12 (2024-05-06)
878
886
  * (bluefox) All files are migrated to Typescript
879
887
 
880
- ### 4.13.11 (2024-04-23)
888
+ ### 4.13.11 (2024-04-23)
881
889
  * (bluefox) Corrected the size of icons
882
890
 
883
- ### 4.13.10 (2024-04-22)
891
+ ### 4.13.10 (2024-04-22)
884
892
  * (bluefox) Migrated all icons to Typescript
885
893
 
886
- ### 4.13.9 (2024-04-20)
894
+ ### 4.13.9 (2024-04-20)
887
895
  * (bluefox) Updated socket-client package
888
896
 
889
- ### 4.13.8 (2024-04-19)
897
+ ### 4.13.8 (2024-04-19)
890
898
  * (bluefox) Corrected CRON selector
891
899
 
892
- ### 4.13.7 (2024-04-19)
900
+ ### 4.13.7 (2024-04-19)
893
901
  * (bluefox) Migrated ColorPicker to typescript
894
902
 
895
- ### 4.13.6 (2024-04-11)
896
- * (bluefox) Migrated TreeTable to typescript
903
+ ### 4.13.6 (2024-04-11)
904
+ * (bluefox) Migrated TreeTable to typescript
897
905
  * (bluefox) corrected the object subscription
898
906
 
899
- ### 4.13.5 (2024-04-02)
900
- * (bluefox) used new connection classes
907
+ ### 4.13.5 (2024-04-02)
908
+ * (bluefox) used new connection classes
901
909
  * (bluefox) Improved the `SelectID` dialog
902
910
 
903
- ### 4.13.3 (2024-04-01)
911
+ ### 4.13.3 (2024-04-01)
904
912
  * (bluefox) used new connection classes
905
913
 
906
- ### 4.12.3 (2024-03-30)
914
+ ### 4.12.3 (2024-03-30)
907
915
  * (bluefox) Migrated legacy connection to typescript
908
916
 
909
- ### 4.12.2 (2024-03-25)
917
+ ### 4.12.2 (2024-03-25)
910
918
  * (bluefox) Added support for remote cloud
911
919
 
912
- ### 4.11.6 (2024-03-19)
920
+ ### 4.11.6 (2024-03-19)
913
921
  * (bluefox) Corrected rendering of LoaderMV
914
922
 
915
- ### 4.11.4 (2024-03-18)
923
+ ### 4.11.4 (2024-03-18)
916
924
  * (bluefox) Corrected types of IconPicker
917
925
 
918
- ### 4.11.3 (2024-03-17)
926
+ ### 4.11.3 (2024-03-17)
919
927
  * (bluefox) Made filters for the file selector dialog optional
920
928
 
921
- ### 4.11.2 (2024-03-16)
929
+ ### 4.11.2 (2024-03-16)
922
930
  * (bluefox) Migrated GenericApp to typescript
923
931
 
924
- ### 4.10.4 (2024-03-16)
932
+ ### 4.10.4 (2024-03-16)
925
933
  * (bluefox) Migrated some components to typescript
926
934
 
927
- ### 4.10.1 (2024-03-11)
935
+ ### 4.10.1 (2024-03-11)
928
936
  * (bluefox) Migrated some components to typescript
929
937
 
930
- ### 4.9.11 (2024-03-08)
938
+ ### 4.9.11 (2024-03-08)
931
939
  * (foxriver76) type GenericApp socket correctly
932
940
 
933
- ### 4.9.10 (2024-02-21)
934
- * (bluefox) translations
941
+ ### 4.9.10 (2024-02-21)
942
+ * (bluefox) translations
935
943
  * (bluefox) updated json config
936
944
 
937
- ### 4.9.9 (2024-02-16)
945
+ ### 4.9.9 (2024-02-16)
938
946
  * (foxriver76) also check plugin state of instance to see if Sentry is explicitly disabled
939
947
 
940
- ### 4.9.8 (2024-02-13)
948
+ ### 4.9.8 (2024-02-13)
941
949
  * (bluefox) allowed hiding wizard in cron dialog
942
950
 
943
- ### 4.9.7 (2024-02-03)
951
+ ### 4.9.7 (2024-02-03)
944
952
  * (foxriver76) allow passing down the instance number do avoid determining from url
945
953
 
946
- ### 4.9.5 (2024-01-01)
954
+ ### 4.9.5 (2024-01-01)
947
955
  * (foxriver76) make `copyToClipboard` event parameter optional
948
956
 
949
- ### 4.9.4 (2024-01-01)
957
+ ### 4.9.4 (2024-01-01)
950
958
  * (foxriver76) try to fix `SelectID` scrolling
951
959
 
952
- ### 4.9.2 (2023-12-30)
960
+ ### 4.9.2 (2023-12-30)
953
961
  * (foxriver76) bump version of `@iobroker/json-config`
954
962
 
955
- ### 4.9.1 (2023-12-22)
963
+ ### 4.9.1 (2023-12-22)
956
964
  * (foxriver76) `@iobroker/json-config` moved to real dependencies
957
965
 
958
- ### 4.9.0 (2023-12-22)
959
- * (foxriver76) migrate to `@iobroker/json-config` module to have a single point of truth
966
+ ### 4.9.0 (2023-12-22)
967
+ * (foxriver76) migrate to `@iobroker/json-config` module to have a single point of truth
960
968
  * (bluefox) Allowed using of `filterFunc` as string
961
969
 
962
- ### 4.8.1 (2023-12-14)
970
+ ### 4.8.1 (2023-12-14)
963
971
  * (bluefox) Added Device manager to JSON Config
964
972
 
965
- ### 4.7.15 (2023-12-12)
973
+ ### 4.7.15 (2023-12-12)
966
974
  * (bluefox) Corrected parsing of a text
967
975
 
968
- ### 4.7.13 (2023-12-10)
976
+ ### 4.7.13 (2023-12-10)
969
977
  * (bluefox) Added possibility to define the root style and embedded property
970
978
 
971
- ### 4.7.11 (2023-12-06)
979
+ ### 4.7.11 (2023-12-06)
972
980
  * (bluefox) Extended color picker with "noInputField" option
973
981
 
974
- ### 4.7.9 (2023-12-04)
982
+ ### 4.7.9 (2023-12-04)
975
983
  * (bluefox) Corrected the icon picker
976
984
 
977
- ### 4.7.8 (2023-12-04)
985
+ ### 4.7.8 (2023-12-04)
978
986
  * (foxriver76) port to `@iobroker/types`
979
987
 
980
- ### 4.7.6 (2023-11-29)
988
+ ### 4.7.6 (2023-11-29)
981
989
  * (bluefox) Added translations
982
990
 
983
- ### 4.7.5 (2023-11-28)
991
+ ### 4.7.5 (2023-11-28)
984
992
  * (bluefox) Corrected subscribe on objects in the legacy connection
985
993
 
986
- ### 4.7.4 (2023-11-23)
987
- * (bluefox) Updated packages
994
+ ### 4.7.4 (2023-11-23)
995
+ * (bluefox) Updated packages
988
996
  * (bluefox) Made getStates method in legacy connection compatible with new one
989
997
 
990
- ### 4.7.3 (2023-11-08)
998
+ ### 4.7.3 (2023-11-08)
991
999
  * (bluefox) Updated packages
992
1000
 
993
- ### 4.7.2 (2023-11-03)
994
- * (foxriver76) fixed problem with color picker, where editing TextField was buggy
1001
+ ### 4.7.2 (2023-11-03)
1002
+ * (foxriver76) fixed problem with color picker, where editing TextField was buggy
995
1003
  * (foxriver76) fixed light mode color of a path in FileBrowser
996
1004
 
997
- ### 4.7.0 (2023-10-31)
998
- * (bluefox) Synced with admin
1005
+ ### 4.7.0 (2023-10-31)
1006
+ * (bluefox) Synced with admin
999
1007
  * (bluefox) Added GIF to image files
1000
1008
 
1001
- ### 4.6.7 (2023-10-19)
1009
+ ### 4.6.7 (2023-10-19)
1002
1010
  * (bluefox) Added return value for `subscribeOnInstance` for Connection class
1003
1011
 
1004
- ### 4.6.6 (2023-10-13)
1012
+ ### 4.6.6 (2023-10-13)
1005
1013
  * (bluefox) Fixed the legacy connection
1006
1014
 
1007
- ### 4.6.5 (2023-10-12)
1015
+ ### 4.6.5 (2023-10-12)
1008
1016
  * (foxriver76) fixed object browser with date
1009
1017
 
1010
- ### 4.6.4 (2023-10-11)
1018
+ ### 4.6.4 (2023-10-11)
1011
1019
  * (bluefox) Updated the packages
1012
1020
 
1013
- ### 4.6.3 (2023-10-09)
1014
- * (bluefox) Just updated the packages
1021
+ ### 4.6.3 (2023-10-09)
1022
+ * (bluefox) Just updated the packages
1015
1023
  * (bluefox) Synced with admin
1016
1024
 
1017
- ### 4.6.2 (2023-09-29)
1025
+ ### 4.6.2 (2023-09-29)
1018
1026
  * (bluefox) Experimental feature added: update states on re-subscribe
1019
1027
 
1020
- ### 4.5.5 (2023-09-27)
1028
+ ### 4.5.5 (2023-09-27)
1021
1029
  * (bluefox) Added export for IconNoIcon
1022
1030
 
1023
- ### 4.5.4 (2023-09-17)
1031
+ ### 4.5.4 (2023-09-17)
1024
1032
  * (bluefox) Added the restricting to folder property for select file dialog
1025
1033
 
1026
- ### 4.5.3 (2023-08-20)
1034
+ ### 4.5.3 (2023-08-20)
1027
1035
  * (foxriver76) fixed css classes of TableResize, see https://github.com/ioBroker/ioBroker.admin/issues/1860
1028
1036
 
1029
- ### 4.5.2 (2023-08-20)
1037
+ ### 4.5.2 (2023-08-20)
1030
1038
  * (foxriver76) added missing export of TableResize
1031
1039
 
1032
- ### 4.5.1 (2023-08-19)
1040
+ ### 4.5.1 (2023-08-19)
1033
1041
  * (foxriver76) fix dialog TextInput
1034
1042
 
1035
- ### 4.5.0 (2023-08-18)
1043
+ ### 4.5.0 (2023-08-18)
1036
1044
  * (bluefox) Synchronize components with admin
1037
1045
 
1038
- ### 4.4.8 (2023-08-17)
1046
+ ### 4.4.8 (2023-08-17)
1039
1047
  * (bluefox) Added translations
1040
1048
 
1041
- ### 4.4.7 (2023-08-10)
1042
- * (bluefox) Added `subscribeStateAsync` method to wait for answer
1049
+ ### 4.4.7 (2023-08-10)
1050
+ * (bluefox) Added `subscribeStateAsync` method to wait for answer
1043
1051
  * (bluefox) Added support for arrays for un/subscriptions
1044
1052
 
1045
- ### 4.4.5 (2023-08-01)
1053
+ ### 4.4.5 (2023-08-01)
1046
1054
  * (bluefox) Updated packages
1047
1055
 
1048
- ### 4.3.3 (2023-07-28)
1056
+ ### 4.3.3 (2023-07-28)
1049
1057
  * (bluefox) Added translations
1050
1058
 
1051
- ### 4.3.0 (2023-07-19)
1052
- * (bluefox) Updated packages
1053
- * (bluefox) Added translations
1054
- * (bluefox) Synced object browser
1059
+ ### 4.3.0 (2023-07-19)
1060
+ * (bluefox) Updated packages
1061
+ * (bluefox) Added translations
1062
+ * (bluefox) Synced object browser
1055
1063
  * (bluefox) formatting
1056
1064
 
1057
- ### 4.2.1 (2023-07-17)
1058
- * (bluefox) Updated packages
1065
+ ### 4.2.1 (2023-07-17)
1066
+ * (bluefox) Updated packages
1059
1067
  * (bluefox) Added translations
1060
1068
 
1061
- ### 4.2.0 (2023-07-07)
1062
- * (bluefox) Updated packages
1069
+ ### 4.2.0 (2023-07-07)
1070
+ * (bluefox) Updated packages
1063
1071
  * (bluefox) Added new method `getObjectsById` to the socket communication
1064
1072
 
1065
- ### 4.1.2 (2023-06-20)
1073
+ ### 4.1.2 (2023-06-20)
1066
1074
  * (bluefox) Allowed setting theme name directly by theme toggle
1067
1075
 
1068
- ### 4.1.0 (2023-05-10)
1076
+ ### 4.1.0 (2023-05-10)
1069
1077
  * (bluefox) `craco-module-federation.js` was added. For node 16
1070
1078
 
1071
- ### 4.0.27 (2023-05-09)
1079
+ ### 4.0.27 (2023-05-09)
1072
1080
  * (bluefox) Allowed showing only specific root in SelectIDDialog
1073
1081
 
1074
- ### 4.0.26 (2023-05-08)
1082
+ ### 4.0.26 (2023-05-08)
1075
1083
  * (bluefox) Added IDs to the buttons in the dialog for GUI tests
1076
1084
 
1077
- ### 4.0.25 (2023-04-23)
1085
+ ### 4.0.25 (2023-04-23)
1078
1086
  * (bluefox) Extended `TextWithIcon` with defined color and icon
1079
1087
 
1080
- ### 4.0.24 (2023-04-03)
1088
+ ### 4.0.24 (2023-04-03)
1081
1089
  * (bluefox) Updated the file selector in tile mode
1082
1090
 
1083
- ### 4.0.23 (2023-03-27)
1091
+ ### 4.0.23 (2023-03-27)
1084
1092
  * (bluefox) Added translations
1085
1093
 
1086
- ### 4.0.22 (2023-03-22)
1094
+ ### 4.0.22 (2023-03-22)
1087
1095
  * (bluefox) Re-Activate legacy connection
1088
1096
 
1089
- ### 4.0.21 (2023-03-22)
1097
+ ### 4.0.21 (2023-03-22)
1090
1098
  * (bluefox) Added translations
1091
1099
 
1092
- ### 4.0.20 (2023-03-21)
1100
+ ### 4.0.20 (2023-03-21)
1093
1101
  * (bluefox) Color picker was improved
1094
1102
 
1095
- ### 4.0.19 (2023-03-20)
1096
- * (bluefox) Packages were updated
1103
+ ### 4.0.19 (2023-03-20)
1104
+ * (bluefox) Packages were updated
1097
1105
  * (bluefox) Added new translations
1098
1106
 
1099
- ### 4.0.18 (2023-03-16)
1107
+ ### 4.0.18 (2023-03-16)
1100
1108
  * (bluefox) Packages were updated
1101
1109
 
1102
- ### 4.0.17 (2023-03-15)
1103
- * (bluefox) Added translations
1110
+ ### 4.0.17 (2023-03-15)
1111
+ * (bluefox) Added translations
1104
1112
  * (bluefox) Added port controller to JSON config
1105
1113
 
1106
- ### 4.0.15 (2023-03-12)
1114
+ ### 4.0.15 (2023-03-12)
1107
1115
  * (bluefox) Updated the object browser and file browser
1108
1116
 
1109
- ### 4.0.14 (2023-03-03)
1117
+ ### 4.0.14 (2023-03-03)
1110
1118
  * (bluefox) added handler of alert messages
1111
1119
 
1112
- ### 4.0.13 (2023-02-15)
1120
+ ### 4.0.13 (2023-02-15)
1113
1121
  * (bluefox) Corrected the theme button
1114
1122
 
1115
- ### 4.0.12 (2023-02-15)
1123
+ ### 4.0.12 (2023-02-15)
1116
1124
  * (bluefox) made the fix for `echarts`
1117
1125
 
1118
- ### 4.0.11 (2023-02-14)
1119
- * (bluefox) Updated packages
1126
+ ### 4.0.11 (2023-02-14)
1127
+ * (bluefox) Updated packages
1120
1128
  * (bluefox) The `chartReady` event was omitted
1121
1129
 
1122
- ### 4.0.10 (2023-02-10)
1123
- * (bluefox) Updated packages
1130
+ ### 4.0.10 (2023-02-10)
1131
+ * (bluefox) Updated packages
1124
1132
  * (bluefox) made the fix for `material`
1125
1133
 
1126
- ### 4.0.9 (2023-02-02)
1134
+ ### 4.0.9 (2023-02-02)
1127
1135
  * (bluefox) Updated packages
1128
1136
 
1129
- ### 4.0.8 (2022-12-19)
1137
+ ### 4.0.8 (2022-12-19)
1130
1138
  * (bluefox) Extended socket with `log` command
1131
1139
 
1132
- ### 4.0.6 (2022-12-19)
1140
+ ### 4.0.6 (2022-12-19)
1133
1141
  * (bluefox) Corrected URL for the connection
1134
1142
 
1135
- ### 4.0.5 (2022-12-14)
1143
+ ### 4.0.5 (2022-12-14)
1136
1144
  * (bluefox) Added support of custom palette for color picker
1137
1145
 
1138
- ### 4.0.2 (2022-12-01)
1146
+ ### 4.0.2 (2022-12-01)
1139
1147
  * (bluefox) use `@iobroker/socket-client` instead of `Connection.tsx`
1140
1148
 
1141
- ### 3.5.3 (2022-11-30)
1149
+ ### 3.5.3 (2022-11-30)
1142
1150
  * (bluefox) Improved `renderTextWithA` function to support `<b>` and `<i>` tags
1143
1151
 
1144
- ### 3.5.2 (2022-11-30)
1152
+ ### 3.5.2 (2022-11-30)
1145
1153
  * (bluefox) updated json config component
1146
1154
 
1147
- ### 3.4.1 (2022-11-29)
1155
+ ### 3.4.1 (2022-11-29)
1148
1156
  * (bluefox) Added button text for message dialog
1149
1157
 
1150
- ### 3.4.0 (2022-11-29)
1158
+ ### 3.4.0 (2022-11-29)
1151
1159
  * (bluefox) Added file selector
1152
1160
 
1153
- ### 3.3.0 (2022-11-26)
1161
+ ### 3.3.0 (2022-11-26)
1154
1162
  * (bluefox) Added subscribe on files
1155
1163
 
1156
- ### 3.2.7 (2022-11-13)
1164
+ ### 3.2.7 (2022-11-13)
1157
1165
  * (bluefox) Added `fullWidth` property to `Dialog`
1158
1166
 
1159
- ### 3.2.6 (2022-11-08)
1167
+ ### 3.2.6 (2022-11-08)
1160
1168
  * (xXBJXx) Improved TreeTable component
1161
1169
 
1162
- ### 3.2.5 (2022-11-08)
1170
+ ### 3.2.5 (2022-11-08)
1163
1171
  * (bluefox) Added the role filter for the object browser
1164
1172
 
1165
- ### 3.2.4 (2022-11-03)
1173
+ ### 3.2.4 (2022-11-03)
1166
1174
  * (bluefox) Added support for alfa channel for `invertColor`
1167
1175
 
1168
- ### 3.2.3 (2022-10-26)
1176
+ ### 3.2.3 (2022-10-26)
1169
1177
  * (bluefox) Corrected expert mode for object browser
1170
1178
 
1171
- ### 3.2.2 (2022-10-25)
1179
+ ### 3.2.2 (2022-10-25)
1172
1180
  * (bluefox) Added support for prefixes for translations
1173
1181
 
1174
- ### 3.2.1 (2022-10-24)
1182
+ ### 3.2.1 (2022-10-24)
1175
1183
  * (bluefox) Corrected color inversion
1176
1184
 
1177
- ### 3.2.0 (2022-10-19)
1185
+ ### 3.2.0 (2022-10-19)
1178
1186
  * (bluefox) Added ukrainian translation
1179
1187
 
1180
- ### 3.1.35 (2022-10-17)
1188
+ ### 3.1.35 (2022-10-17)
1181
1189
  * (bluefox) small changes for material
1182
1190
 
1183
- ### 3.1.34 (2022-08-24)
1191
+ ### 3.1.34 (2022-08-24)
1184
1192
  * (bluefox) Implemented fallback to english by translations
1185
1193
 
1186
- ### 3.1.33 (2022-08-24)
1194
+ ### 3.1.33 (2022-08-24)
1187
1195
  * (bluefox) Added support for onchange flag
1188
1196
 
1189
- ### 3.1.30 (2022-08-23)
1190
- * (bluefox) Added method `getCompactSystemRepositories`
1197
+ ### 3.1.30 (2022-08-23)
1198
+ * (bluefox) Added method `getCompactSystemRepositories`
1191
1199
  * (bluefox) corrected error in `ObjectBrowser`
1192
1200
 
1193
- ### 3.1.27 (2022-08-01)
1201
+ ### 3.1.27 (2022-08-01)
1194
1202
  * (bluefox) Disable file editing in FileViewer
1195
1203
 
1196
- ### 3.1.26 (2022-08-01)
1197
- * (bluefox) Added translations
1204
+ ### 3.1.26 (2022-08-01)
1205
+ * (bluefox) Added translations
1198
1206
  * (bluefox) JSON schema was extended with missing definitions
1199
1207
 
1200
- ### 3.1.24 (2022-07-28)
1208
+ ### 3.1.24 (2022-07-28)
1201
1209
  * (bluefox) Updated file browser and object browser
1202
1210
 
1203
- ### 3.1.23 (2022-07-25)
1211
+ ### 3.1.23 (2022-07-25)
1204
1212
  * (bluefox) Extend custom filter for object selector
1205
1213
 
1206
- ### 3.1.22 (2022-07-22)
1214
+ ### 3.1.22 (2022-07-22)
1207
1215
  * (bluefox) Added i18n tools for development
1208
1216
 
1209
- ### 3.1.20 (2022-07-14)
1217
+ ### 3.1.20 (2022-07-14)
1210
1218
  * (bluefox) Allowed to show select dialog with the expert mode enabled
1211
1219
 
1212
- ### 3.1.19 (2022-07-08)
1220
+ ### 3.1.19 (2022-07-08)
1213
1221
  * (bluefox) Allowed extending translations for all languages together
1214
1222
 
1215
- ### 3.1.18 (2022-07-06)
1223
+ ### 3.1.18 (2022-07-06)
1216
1224
  * (bluefox) Added translation
1217
1225
 
1218
- ### 3.1.17 (2022-07-05)
1226
+ ### 3.1.17 (2022-07-05)
1219
1227
  * (bluefox) Deactivate JSON editor for JSONConfig because of space
1220
1228
 
1221
- ### 3.1.16 (2022-06-27)
1229
+ ### 3.1.16 (2022-06-27)
1222
1230
  * (bluefox) Update object browser
1223
1231
 
1224
- ### 3.1.15 (2022-06-27)
1232
+ ### 3.1.15 (2022-06-27)
1225
1233
  * (bluefox) Allowed using of spaces in name
1226
1234
 
1227
- ### 3.1.14 (2022-06-23)
1235
+ ### 3.1.14 (2022-06-23)
1228
1236
  * (bluefox) Added translations
1229
1237
 
1230
- ### 3.1.11 (2022-06-22)
1238
+ ### 3.1.11 (2022-06-22)
1231
1239
  * (bluefox) Added preparations for iobroker cloud
1232
1240
 
1233
- ### 3.1.10 (2022-06-22)
1241
+ ### 3.1.10 (2022-06-22)
1234
1242
  * (bluefox) Added translations
1235
1243
 
1236
- ### 3.1.9 (2022-06-20)
1244
+ ### 3.1.9 (2022-06-20)
1237
1245
  * (bluefox) Allowed working behind reverse proxy
1238
1246
 
1239
- ### 3.1.7 (2022-06-19)
1247
+ ### 3.1.7 (2022-06-19)
1240
1248
  * (bluefox) Added file select dialog
1241
1249
 
1242
- ### 3.1.3 (2022-06-13)
1250
+ ### 3.1.3 (2022-06-13)
1243
1251
  * (bluefox) Added table with resized headers
1244
1252
 
1245
- ### 3.1.2 (2022-06-09)
1253
+ ### 3.1.2 (2022-06-09)
1246
1254
  * (bluefox) Added new document icon (read only)
1247
1255
 
1248
- ### 3.1.1 (2022-06-09)
1256
+ ### 3.1.1 (2022-06-09)
1249
1257
  * (bluefox) Allowed working behind reverse proxy
1250
1258
 
1251
- ### 3.1.0 (2022-06-07)
1259
+ ### 3.1.0 (2022-06-07)
1252
1260
  * (bluefox) Some german texts were corrected
1253
1261
 
1254
- ### 3.0.17 (2022-06-03)
1262
+ ### 3.0.17 (2022-06-03)
1255
1263
  * (bluefox) Allowed calling getAdapterInstances not for admin too
1256
1264
 
1257
- ### 3.0.15 (2022-06-01)
1265
+ ### 3.0.15 (2022-06-01)
1258
1266
  * (bluefox) Updated JsonConfigComponent: password, table
1259
1267
 
1260
- ### 3.0.14 (2022-05-25)
1268
+ ### 3.0.14 (2022-05-25)
1261
1269
  * (bluefox) Added ConfigGeneric to import
1262
1270
 
1263
- ### 3.0.7 (2022-05-25)
1271
+ ### 3.0.7 (2022-05-25)
1264
1272
  * (bluefox) Made the module definitions
1265
1273
 
1266
- ### 3.0.6 (2022-05-25)
1274
+ ### 3.0.6 (2022-05-25)
1267
1275
  * (bluefox) Added JsonConfigComponent
1268
1276
 
1269
- ### 2.1.11 (2022-05-24)
1277
+ ### 2.1.11 (2022-05-24)
1270
1278
  * (bluefox) Update file browser. It supports now the file changed events.
1271
1279
 
1272
- ### 2.1.10 (2022-05-24)
1280
+ ### 2.1.10 (2022-05-24)
1273
1281
  * (bluefox) Corrected object browser
1274
1282
 
1275
- ### 2.1.9 (2022-05-16)
1283
+ ### 2.1.9 (2022-05-16)
1276
1284
  * (bluefox) Corrected expert mode in object browser
1277
1285
 
1278
- ### 2.1.7 (2022-05-09)
1279
- * (bluefox) Changes were synchronized with adapter-react-v5
1286
+ ### 2.1.7 (2022-05-09)
1287
+ * (bluefox) Changes were synchronized with adapter-react-v5
1280
1288
  * (bluefox) Added `I18n.disableWarning` method
1281
1289
 
1282
- ### 2.1.6 (2022-03-28)
1283
- * (bluefox) Added `log` method to connection
1290
+ ### 2.1.6 (2022-03-28)
1291
+ * (bluefox) Added `log` method to connection
1284
1292
  * (bluefox) Corrected translations
1285
1293
 
1286
- ### 2.1.1 (2022-03-27)
1294
+ ### 2.1.1 (2022-03-27)
1287
1295
  * (bluefox) Corrected error in TreeTable
1288
1296
 
1289
- ### 2.1.0 (2022-03-26)
1297
+ ### 2.1.0 (2022-03-26)
1290
1298
  * (bluefox) BREAKING_CHANGE: Corrected error with readFile(base64=false)
1291
1299
 
1292
- ### 2.0.0 (2022-03-26)
1300
+ ### 2.0.0 (2022-03-26)
1293
1301
  * (bluefox) Initial version
1294
1302
 
1295
- ### 0.1.0 (2022-03-23)
1303
+ ### 0.1.0 (2022-03-23)
1296
1304
  * (bluefox) Fixed theme errors
1297
1305
 
1298
- ### 0.0.4 (2022-03-22)
1306
+ ### 0.0.4 (2022-03-22)
1299
1307
  * (bluefox) Fixed eslint warnings
1300
1308
 
1301
- ### 0.0.3 (2022-03-19)
1309
+ ### 0.0.3 (2022-03-19)
1302
1310
  * (bluefox) beta version
1303
1311
 
1304
- ### 0.0.2 (2022-02-24)
1312
+ ### 0.0.2 (2022-02-24)
1305
1313
  * (bluefox) try to publish a first version
1306
1314
 
1307
- ### 0.0.1 (2022-02-24)
1315
+ ### 0.0.1 (2022-02-24)
1308
1316
  * initial commit
1309
1317
 
1310
- ## License
1311
- The MIT License (MIT)
1312
-
1313
- Copyright (c) 2019-2024 bluefox <dogafox@gmail.com>
1314
-
1315
- Permission is hereby granted, free of charge, to any person obtaining a copy
1316
- of this software and associated documentation files (the "Software"), to deal
1317
- in the Software without restriction, including without limitation the rights
1318
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1319
- copies of the Software, and to permit persons to whom the Software is
1320
- furnished to do so, subject to the following conditions:
1321
-
1322
- The above copyright notice and this permission notice shall be included in all
1323
- copies or substantial portions of the Software.
1324
-
1325
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1326
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1327
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1328
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1329
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1330
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1318
+ ## License
1319
+ The MIT License (MIT)
1320
+
1321
+ Copyright (c) 2019-2024 bluefox <dogafox@gmail.com>
1322
+
1323
+ Permission is hereby granted, free of charge, to any person obtaining a copy
1324
+ of this software and associated documentation files (the "Software"), to deal
1325
+ in the Software without restriction, including without limitation the rights
1326
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1327
+ copies of the Software, and to permit persons to whom the Software is
1328
+ furnished to do so, subject to the following conditions:
1329
+
1330
+ The above copyright notice and this permission notice shall be included in all
1331
+ copies or substantial portions of the Software.
1332
+
1333
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1334
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1335
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1336
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1337
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1338
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1331
1339
  SOFTWARE.