@iobroker/adapter-react-v5 8.2.7 → 8.2.8

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.
@@ -27,6 +27,10 @@ export declare class ObjectBrowserClass extends Component<ObjectBrowserProps, Ob
27
27
  private readonly tableRef;
28
28
  private pausedSubscribes;
29
29
  private selectFirst;
30
+ /** Last navigation that was applied from `navigateTo` or reported via `onNavigateTo` (loop guard). */
31
+ private lastNav;
32
+ /** True while applying `navigateTo`, so the derived-state watcher does not echo it back. */
33
+ private applyingNav;
30
34
  private root;
31
35
  private readonly states;
32
36
  private subscribes;
@@ -244,10 +248,19 @@ export declare class ObjectBrowserClass extends Component<ObjectBrowserProps, Ob
244
248
  renderHandleRight(): JSX.Element;
245
249
  private renderHeader;
246
250
  private renderToast;
251
+ /** Derive the current navigation target from the dialog/selection state. */
252
+ private getStateNav;
253
+ private static navEqual;
254
+ /** Apply a navigation target coming from the parent (`navigateTo`): select + open the dialog. */
255
+ private applyNavigateTo;
256
+ /** Apply the initial `navigateTo` after the tree has loaded (called from componentDidMount). */
257
+ private applyInitialNavigateTo;
258
+ /** Reconcile `navigateTo` (parent/URL) with the browser's selection/dialog state. */
259
+ private reconcileNavigation;
247
260
  /**
248
261
  * Called when component is updated.
249
262
  */
250
- componentDidUpdate(): void;
263
+ componentDidUpdate(prevProps: ObjectBrowserProps): void;
251
264
  scrollToItem(id: string): void;
252
265
  private renderCustomDialog;
253
266
  private onUpdate;
@@ -788,6 +788,10 @@ export class ObjectBrowserClass extends Component {
788
788
  tableRef;
789
789
  pausedSubscribes = false;
790
790
  selectFirst;
791
+ /** Last navigation that was applied from `navigateTo` or reported via `onNavigateTo` (loop guard). */
792
+ lastNav = null;
793
+ /** True while applying `navigateTo`, so the derived-state watcher does not echo it back. */
794
+ applyingNav = false;
791
795
  root = null;
792
796
  states = {};
793
797
  subscribes = [];
@@ -1229,12 +1233,18 @@ export class ObjectBrowserClass extends Component {
1229
1233
  // reset filter
1230
1234
  this.setState({ filter: { ...DEFAULT_FILTER }, columnsForAdmin }, () => {
1231
1235
  this.doFilter();
1232
- this.setState({ loaded: true, updating: false }, () => this.expandAllSelected(() => this.onAfterSelect()));
1236
+ this.setState({ loaded: true, updating: false }, () => this.expandAllSelected(() => {
1237
+ this.onAfterSelect();
1238
+ this.applyInitialNavigateTo();
1239
+ }));
1233
1240
  });
1234
1241
  }
1235
1242
  else {
1236
1243
  this.doFilter();
1237
- this.setState({ loaded: true, updating: false, columnsForAdmin }, () => this.expandAllSelected(() => this.onAfterSelect()));
1244
+ this.setState({ loaded: true, updating: false, columnsForAdmin }, () => this.expandAllSelected(() => {
1245
+ this.onAfterSelect();
1246
+ this.applyInitialNavigateTo();
1247
+ }));
1238
1248
  }
1239
1249
  }
1240
1250
  catch (error) {
@@ -4407,10 +4417,109 @@ export class ObjectBrowserClass extends Component {
4407
4417
  return (React.createElement(Snackbar, { open: !!this.state.toast, autoHideDuration: 3000, onClick: () => this.setState({ toast: '' }), onClose: () => this.setState({ toast: '' }), message: this.state.toast, action: React.createElement(IconButton, { size: "small", "aria-label": "close", color: "inherit", onClick: () => this.setState({ toast: '' }) },
4408
4418
  React.createElement(IconClose, { fontSize: "small" })) }));
4409
4419
  }
4420
+ // --- Routing (navigateTo / onNavigateTo) ---
4421
+ // The browser never reads the URL itself; the parent drives it via `navigateTo` and is informed
4422
+ // of user navigation via `onNavigateTo`. All URL parsing/writing lives in the parent component.
4423
+ /** Derive the current navigation target from the dialog/selection state. */
4424
+ getStateNav() {
4425
+ if (this.state.editObjectDialog) {
4426
+ return { mode: 'edit', id: this.state.editObjectDialog };
4427
+ }
4428
+ if (this.state.customDialog && this.state.customDialog.length === 1 && !this.state.customDialogAll) {
4429
+ return { mode: 'settings', id: this.state.customDialog[0] };
4430
+ }
4431
+ if (this.state.viewFileDialog) {
4432
+ return { mode: 'viewFile', id: this.state.viewFileDialog };
4433
+ }
4434
+ if (this.state.selected.length === 1 && this.state.selected[0]) {
4435
+ return { mode: 'select', id: this.state.selected[0] };
4436
+ }
4437
+ return null;
4438
+ }
4439
+ static navEqual(a, b) {
4440
+ if (!a || !b) {
4441
+ return !a && !b;
4442
+ }
4443
+ return a.mode === b.mode && a.id === b.id;
4444
+ }
4445
+ /** Apply a navigation target coming from the parent (`navigateTo`): select + open the dialog. */
4446
+ applyNavigateTo(nav) {
4447
+ this.applyingNav = true;
4448
+ const done = () => {
4449
+ this.applyingNav = false;
4450
+ };
4451
+ if (!nav?.id) {
4452
+ // No target: just close any open dialog (keep the current selection).
4453
+ this.setState({ editObjectDialog: '', customDialog: null, viewFileDialog: '' }, done);
4454
+ return;
4455
+ }
4456
+ const { id } = nav;
4457
+ const open = () => {
4458
+ if (nav.mode === 'edit') {
4459
+ this.setState({ editObjectDialog: id, editObjectAlias: false, customDialog: null, viewFileDialog: '' }, done);
4460
+ }
4461
+ else if (nav.mode === 'settings') {
4462
+ this.setState({ customDialog: [id], customDialogAll: false, editObjectDialog: '', viewFileDialog: '' }, done);
4463
+ }
4464
+ else if (nav.mode === 'viewFile') {
4465
+ this.setState({ viewFileDialog: id, editObjectDialog: '', customDialog: null }, done);
4466
+ }
4467
+ else {
4468
+ this.setState({ editObjectDialog: '', customDialog: null, viewFileDialog: '' }, done);
4469
+ }
4470
+ };
4471
+ // Select the target (if needed), expand to it and scroll into view, then open the dialog.
4472
+ if (this.state.selected.length === 1 && this.state.selected[0] === id) {
4473
+ open();
4474
+ }
4475
+ else {
4476
+ this.onSelect(id, false, () => this.expandAllSelected(() => {
4477
+ this.scrollToItem(id);
4478
+ open();
4479
+ }));
4480
+ }
4481
+ }
4482
+ /** Apply the initial `navigateTo` after the tree has loaded (called from componentDidMount). */
4483
+ applyInitialNavigateTo() {
4484
+ const nav = this.props.navigateTo ?? null;
4485
+ if (nav?.id) {
4486
+ this.lastNav = nav;
4487
+ this.applyNavigateTo(nav);
4488
+ }
4489
+ else {
4490
+ // Don't push the restored-from-localStorage selection into the URL on load.
4491
+ this.lastNav = this.getStateNav();
4492
+ }
4493
+ }
4494
+ /** Reconcile `navigateTo` (parent/URL) with the browser's selection/dialog state. */
4495
+ reconcileNavigation(prevProps) {
4496
+ if (this.props.navigateTo === undefined && !this.props.onNavigateTo) {
4497
+ return; // routing not used by this consumer
4498
+ }
4499
+ if (this.applyingNav) {
4500
+ return; // currently applying a target; ignore the intermediate state
4501
+ }
4502
+ const propNav = this.props.navigateTo ?? null;
4503
+ const stateNav = this.getStateNav();
4504
+ if (ObjectBrowserClass.navEqual(propNav, stateNav)) {
4505
+ this.lastNav = stateNav;
4506
+ return;
4507
+ }
4508
+ if (!ObjectBrowserClass.navEqual(propNav, prevProps.navigateTo ?? null)) {
4509
+ // The parent (URL) drove a change → apply it to the browser.
4510
+ this.lastNav = propNav;
4511
+ this.applyNavigateTo(propNav);
4512
+ }
4513
+ else if (!ObjectBrowserClass.navEqual(stateNav, this.lastNav)) {
4514
+ // The user changed selection/dialog → report it so the parent can update the URL.
4515
+ this.lastNav = stateNav;
4516
+ this.props.onNavigateTo?.(stateNav);
4517
+ }
4518
+ }
4410
4519
  /**
4411
4520
  * Called when component is updated.
4412
4521
  */
4413
- componentDidUpdate() {
4522
+ componentDidUpdate(prevProps) {
4414
4523
  if (this.tableRef.current) {
4415
4524
  const scrollBarWidth = this.tableRef.current.offsetWidth - this.tableRef.current.clientWidth;
4416
4525
  if (this.state.scrollBarWidth !== scrollBarWidth) {
@@ -4420,6 +4529,7 @@ export class ObjectBrowserClass extends Component {
4420
4529
  this.scrollToItem(this.selectFirst);
4421
4530
  }
4422
4531
  }
4532
+ this.reconcileNavigation(prevProps);
4423
4533
  }
4424
4534
  scrollToItem(id) {
4425
4535
  this.selectFirst = '';