@iobroker/gui-components 10.3.5 → 10.3.6
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 +7 -1
- package/build/Components/ObjectBrowser/ObjectBrowserClass.d.ts +10 -0
- package/build/Components/ObjectBrowser/ObjectBrowserClass.js +31 -4
- package/build/Components/ObjectBrowser/ObjectBrowserClass.js.map +1 -1
- package/build/Components/ObjectBrowser/contextMenu.js +3 -1
- package/build/Components/ObjectBrowser/contextMenu.js.map +1 -1
- package/build/Components/ObjectBrowser/renderLeaf.js +4 -2
- package/build/Components/ObjectBrowser/renderLeaf.js.map +1 -1
- package/build/Components/Router.d.ts +14 -0
- package/build/Components/Router.js +21 -2
- package/build/Components/Router.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -36,7 +36,7 @@ npm create vite@latest src -- --template react-ts
|
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@emotion/react": "^11.14.0",
|
|
38
38
|
"@emotion/styled": "^11.14.1",
|
|
39
|
-
"@iobroker/gui-components": "^10.3.
|
|
39
|
+
"@iobroker/gui-components": "^10.3.6",
|
|
40
40
|
"@mui/icons-material": "^9.0.1",
|
|
41
41
|
"@mui/material": "^9.0.1",
|
|
42
42
|
"react": "^19.2.5",
|
|
@@ -877,6 +877,12 @@ You can find the migration instructions:
|
|
|
877
877
|
-->
|
|
878
878
|
|
|
879
879
|
## Changelog
|
|
880
|
+
### 10.3.6 (2026-09-26)
|
|
881
|
+
|
|
882
|
+
- (@GermanBluefox) Fixed: `Router.doNavigate` wrote the ID into the URL hash as it was, while `Router.getLocation` reads the hash by splitting it at "/" and decoding every part. An ID that contains a "/" - e.g. `ocpp.0./TACW1142021G1543.1.meterValues.Power_Active_Import` - was therefore cut off at its first slash on the way back, and its remainder landed in `arg`. The ID segment is URL-encoded now, so it survives the round trip, including the one a dialog makes when it only changes its tab (ioBroker.admin#3634). **Callers must pass the raw ID**: one that is already encoded is now encoded twice
|
|
883
|
+
- (@GermanBluefox) Changed: without the expert mode, the object browser no longer offers to delete an object of an adapter - neither the button in the row nor the entry in the context menu nor the `Delete` key. Deleting such an object can stop the adapter from working, and it is created again on the next start anyway. What a user creates themselves (`0_userdata.*`, `alias.*`) can still be deleted without the expert mode, and with the expert mode everything can be deleted as before (ioBroker.admin#3639)
|
|
884
|
+
- (@GermanBluefox) Fixed: the object browser threw `can't access property "<id>", this.objects is undefined` when a navigation target reached it before the object tree was read - which is what a route in the URL does. Such a target now waits for the tree instead of crashing the browser (ioBroker.admin#3634)
|
|
885
|
+
|
|
880
886
|
### 10.3.5 (2026-09-25)
|
|
881
887
|
|
|
882
888
|
- (@GermanBluefox) Added function `findObjectIcon`
|
|
@@ -218,6 +218,16 @@ export declare class ObjectBrowserClass extends Component<ObjectBrowserProps, Ob
|
|
|
218
218
|
* Called when component is unmounted.
|
|
219
219
|
*/
|
|
220
220
|
componentWillUnmount(): void;
|
|
221
|
+
/**
|
|
222
|
+
* May this object be deleted without the expert mode?
|
|
223
|
+
*
|
|
224
|
+
* Deleting an object of an adapter can stop that adapter from working, and the adapter creates it
|
|
225
|
+
* again on the next start anyway. So outside the expert mode only the objects a user makes
|
|
226
|
+
* themselves can be deleted - those in `0_userdata.*` and `alias.*` (ioBroker.admin#3639).
|
|
227
|
+
*
|
|
228
|
+
* @param id ID of the object
|
|
229
|
+
*/
|
|
230
|
+
isDeleteAllowed(id: string): boolean;
|
|
221
231
|
/**
|
|
222
232
|
* Show the deletion dialog for a given object
|
|
223
233
|
*/
|
|
@@ -27,6 +27,11 @@ import * as contextMenu from './contextMenu';
|
|
|
27
27
|
import { DEFAULT_DATE_FORMAT, DEFAULT_FILTER, ITEM_LEVEL, MIN_COLUMN_WIDTHS, SCREEN_WIDTHS, } from './constants';
|
|
28
28
|
export { getSelectIdIconFromObjects };
|
|
29
29
|
let objectsAlreadyLoaded = false;
|
|
30
|
+
/**
|
|
31
|
+
* The namespaces whose objects a user creates themselves. Only these may be deleted without the
|
|
32
|
+
* expert mode; see {@link ObjectBrowserClass.isDeleteAllowed}.
|
|
33
|
+
*/
|
|
34
|
+
const USER_OWNED_NAMESPACES = ['0_userdata.', 'alias.'];
|
|
30
35
|
export class ObjectBrowserClass extends Component {
|
|
31
36
|
// do not define the type as null to save the performance, so we must check it every time
|
|
32
37
|
info = {
|
|
@@ -787,11 +792,26 @@ export class ObjectBrowserClass extends Component {
|
|
|
787
792
|
this.subscribes.clear();
|
|
788
793
|
this.objects = {};
|
|
789
794
|
}
|
|
795
|
+
/**
|
|
796
|
+
* May this object be deleted without the expert mode?
|
|
797
|
+
*
|
|
798
|
+
* Deleting an object of an adapter can stop that adapter from working, and the adapter creates it
|
|
799
|
+
* again on the next start anyway. So outside the expert mode only the objects a user makes
|
|
800
|
+
* themselves can be deleted - those in `0_userdata.*` and `alias.*` (ioBroker.admin#3639).
|
|
801
|
+
*
|
|
802
|
+
* @param id ID of the object
|
|
803
|
+
*/
|
|
804
|
+
isDeleteAllowed(id) {
|
|
805
|
+
return this.state.filter.expertMode || USER_OWNED_NAMESPACES.some(prefix => id.startsWith(prefix));
|
|
806
|
+
}
|
|
790
807
|
/**
|
|
791
808
|
* Show the deletion dialog for a given object
|
|
792
809
|
*/
|
|
793
810
|
showDeleteDialog(options) {
|
|
794
811
|
const { id, obj, item } = options;
|
|
812
|
+
if (!this.isDeleteAllowed(id)) {
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
795
815
|
// calculate the number of children
|
|
796
816
|
const keys = Object.keys(this.objects);
|
|
797
817
|
keys.sort();
|
|
@@ -864,9 +884,12 @@ export class ObjectBrowserClass extends Component {
|
|
|
864
884
|
*/
|
|
865
885
|
onSelect(toggleItem, isDouble, cb) {
|
|
866
886
|
this.localStorage.setItem(`${this.props.dialogName || 'App'}.focused`, toggleItem);
|
|
887
|
+
// `objects` only exists once the tree has been read. A selection can arrive before that -
|
|
888
|
+
// from the URL, through `navigateTo` - and must not throw; such an ID is treated like one
|
|
889
|
+
// that is not in the tree, and `applyInitialNavigateTo` selects it properly after the load.
|
|
890
|
+
const obj = this.objects?.[toggleItem];
|
|
867
891
|
if (!this.props.multiSelect) {
|
|
868
|
-
if (this.
|
|
869
|
-
(!this.props.types || this.props.types.includes(this.objects[toggleItem].type))) {
|
|
892
|
+
if (obj && (!this.props.types || this.props.types.includes(obj.type))) {
|
|
870
893
|
this.localStorage.removeItem(`${this.props.dialogName || 'App'}.selectedNonObject`);
|
|
871
894
|
if (this.state.selected[0] !== toggleItem) {
|
|
872
895
|
this.setState({ selected: [toggleItem], selectedNonObject: '', focused: toggleItem }, () => {
|
|
@@ -890,8 +913,7 @@ export class ObjectBrowserClass extends Component {
|
|
|
890
913
|
});
|
|
891
914
|
}
|
|
892
915
|
}
|
|
893
|
-
else if (this.
|
|
894
|
-
(!this.props.types || this.props.types.includes(this.objects[toggleItem].type))) {
|
|
916
|
+
else if (obj && (!this.props.types || this.props.types.includes(obj.type))) {
|
|
895
917
|
this.localStorage.removeItem(`${this.props.dialogName || 'App'}.selectedNonObject`);
|
|
896
918
|
const selected = [...this.state.selected];
|
|
897
919
|
const pos = selected.indexOf(toggleItem);
|
|
@@ -2493,6 +2515,11 @@ export class ObjectBrowserClass extends Component {
|
|
|
2493
2515
|
}
|
|
2494
2516
|
/** Apply a navigation target coming from the parent (`navigateTo`): select + open the dialog. */
|
|
2495
2517
|
applyNavigateTo(nav) {
|
|
2518
|
+
if (!this.objects) {
|
|
2519
|
+
// The tree is still being read. `applyInitialNavigateTo` runs once it is there and takes
|
|
2520
|
+
// the target from the props again, so nothing is lost by waiting here.
|
|
2521
|
+
return;
|
|
2522
|
+
}
|
|
2496
2523
|
this.applyingNav = true;
|
|
2497
2524
|
const done = () => {
|
|
2498
2525
|
this.applyingNav = false;
|