@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.
@@ -21,7 +21,7 @@ import {
21
21
  Fab,
22
22
  FormControl,
23
23
  FormControlLabel,
24
- Grid,
24
+ Grid2,
25
25
  IconButton,
26
26
  Input,
27
27
  List,
@@ -275,6 +275,8 @@ interface TreeInfo {
275
275
  customs: string[];
276
276
  enums: string[];
277
277
  hasSomeCustoms: boolean;
278
+ // List of all aliases that shows to this state
279
+ aliasesMap: { [stateId: string]: string[] };
278
280
  }
279
281
 
280
282
  interface GetValueStyleOptions {
@@ -986,7 +988,7 @@ function walkThroughArray(object: any[], iteratee: (result: any[], value: any, k
986
988
  */
987
989
  function walkThroughObject(
988
990
  object: Record<string, any>,
989
- iteratee: (result: Record<string, any>, value: any, key: string) => void
991
+ iteratee: (result: Record<string, any>, value: any, key: string) => void,
990
992
  ): Record<string, any> {
991
993
  const copiedObject: Record<string, any> = {};
992
994
  for (const key in object) {
@@ -1533,13 +1535,14 @@ function buildTree(
1533
1535
  const info: TreeInfo = {
1534
1536
  funcEnums: [],
1535
1537
  roomEnums: [],
1536
- roles: [],
1537
- ids: [],
1538
- types: [],
1538
+ roles: [],
1539
+ ids: [],
1540
+ types: [],
1539
1541
  objects,
1540
- customs: ['_'],
1541
- enums: [],
1542
+ customs: ['_'],
1543
+ enums: [],
1542
1544
  hasSomeCustoms: false,
1545
+ aliasesMap: {},
1543
1546
  };
1544
1547
 
1545
1548
  let cRoot: TreeItem = root;
@@ -1573,6 +1576,35 @@ function buildTree(
1573
1576
  info.hasSomeCustoms = true;
1574
1577
  info.customs.push(id.substring('system.adapter.'.length));
1575
1578
  }
1579
+
1580
+ // Build a map of aliases
1581
+ if (id.startsWith('alias.') && obj.common.alias?.id) {
1582
+ if (typeof obj.common.alias.id === 'string') {
1583
+ const usedId = obj.common.alias.id;
1584
+ if (!info.aliasesMap[usedId]) {
1585
+ info.aliasesMap[usedId] = [id];
1586
+ } else if (!info.aliasesMap[usedId].includes(id)) {
1587
+ info.aliasesMap[usedId].push(id);
1588
+ }
1589
+ } else {
1590
+ const readId = obj.common.alias.id.read;
1591
+ if (readId) {
1592
+ if (!info.aliasesMap[readId]) {
1593
+ info.aliasesMap[readId] = [id];
1594
+ } else if (!info.aliasesMap[readId].includes(id)) {
1595
+ info.aliasesMap[readId].push(id);
1596
+ }
1597
+ }
1598
+ const writeId = obj.common.alias.id.write;
1599
+ if (writeId) {
1600
+ if (!info.aliasesMap[writeId]) {
1601
+ info.aliasesMap[writeId] = [id];
1602
+ } else if (!info.aliasesMap[writeId].includes(id)) {
1603
+ info.aliasesMap[writeId].push(id);
1604
+ }
1605
+ }
1606
+ }
1607
+ }
1576
1608
  }
1577
1609
 
1578
1610
  info.ids.push(id);
@@ -2016,12 +2048,13 @@ function formatValue(
2016
2048
  * Get CSS style for given state value
2017
2049
  */
2018
2050
  function getValueStyle(options: GetValueStyleOptions): { color: string } {
2019
- const { state, isExpertMode, isButton } = options;
2020
- let color = state?.ack ? (state.q ? '#ffa500' : '') : '#ff2222c9';
2051
+ const { state /* , isExpertMode, isButton */ } = options;
2052
+ const color = state?.ack ? (state.q ? '#ffa500' : '') : '#ff2222c9';
2021
2053
 
2022
- if (!isExpertMode && isButton) {
2023
- color = '';
2024
- }
2054
+ // do not show the color of the button in non-expert mode
2055
+ // if (!isExpertMode && isButton) {
2056
+ // color = '';
2057
+ // }
2025
2058
 
2026
2059
  return { color };
2027
2060
  }
@@ -2448,7 +2481,12 @@ interface ObjectBrowserState {
2448
2481
  showAllExportOptions: boolean;
2449
2482
  linesEnabled: boolean;
2450
2483
  showDescription: boolean;
2451
- showContextMenu: { item: TreeItem; subItem?: string; subAnchor?: HTMLLIElement } | null;
2484
+ showContextMenu: {
2485
+ item: TreeItem;
2486
+ position: { left: number; top: number };
2487
+ subItem?: string;
2488
+ subAnchor?: HTMLLIElement;
2489
+ } | null;
2452
2490
  noStatesByExportImport: boolean;
2453
2491
  beautifyJsonExport: boolean;
2454
2492
  excludeSystemRepositoriesFromExport: boolean;
@@ -2460,6 +2498,8 @@ interface ObjectBrowserState {
2460
2498
  modalEditOfAccessObjData?: TreeItemData;
2461
2499
  updateOpened?: boolean;
2462
2500
  tooltipInfo: null | { el: React.JSX.Element[]; id: string };
2501
+ /** Show the menu with aliases for state */
2502
+ aliasMenu: string;
2463
2503
  }
2464
2504
 
2465
2505
  export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrowserState> {
@@ -2761,6 +2801,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
2761
2801
  excludeSystemRepositoriesFromExport: true,
2762
2802
  excludeTranslations: false,
2763
2803
  tooltipInfo: null,
2804
+ aliasMenu: '',
2764
2805
  };
2765
2806
 
2766
2807
  this.texts = {
@@ -2908,6 +2949,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
2908
2949
  if (typeof props.filterFunc === 'function') {
2909
2950
  this.objects = {};
2910
2951
  const filterFunc: (obj: ioBroker.Object) => boolean = props.filterFunc;
2952
+
2911
2953
  Object.keys(objects).forEach(id => {
2912
2954
  try {
2913
2955
  if (filterFunc(objects[id])) {
@@ -2933,6 +2975,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
2933
2975
  } else if (props.types) {
2934
2976
  this.objects = {};
2935
2977
  const propsTypes = props.types;
2978
+
2936
2979
  Object.keys(objects).forEach(id => {
2937
2980
  const type = objects[id] && objects[id].type;
2938
2981
  // include "folder" types too
@@ -3166,7 +3209,12 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
3166
3209
  // console.log(`CONTEXT MENU: ${this.contextMenu ? Date.now() - this.contextMenu.ts : 'false'}`);
3167
3210
  if (this.contextMenu && Date.now() - this.contextMenu.ts < 2000) {
3168
3211
  e.preventDefault();
3169
- this.setState({ showContextMenu: { item: this.contextMenu.item } });
3212
+ this.setState({
3213
+ showContextMenu: {
3214
+ item: this.contextMenu.item,
3215
+ position: { left: e.clientX + 2, top: e.clientY - 6 },
3216
+ },
3217
+ });
3170
3218
  } else if (this.state.showContextMenu) {
3171
3219
  e.preventDefault();
3172
3220
  this.setState({ showContextMenu: null });
@@ -3667,7 +3715,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
3667
3715
  cColumns = null;
3668
3716
  }
3669
3717
 
3670
- if (cColumns?.length) {
3718
+ if (cColumns && cColumns.length) {
3671
3719
  columnsForAdmin = columnsForAdmin || {};
3672
3720
  columnsForAdmin[obj.common.name] = cColumns.sort((a, b) =>
3673
3721
  (a.path > b.path ? -1 : a.path < b.path ? 1 : 0));
@@ -3734,6 +3782,50 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
3734
3782
  }
3735
3783
  }
3736
3784
 
3785
+ // This function is called when the user changes the alias of an object.
3786
+ // It updates the aliasMap and returns true if the aliasMap has changed.
3787
+ updateAliases(aliasId: string): void {
3788
+ if (!this.objects || !this.info?.aliasesMap || !aliasId?.startsWith('alias.')) {
3789
+ return;
3790
+ }
3791
+ // Rebuild aliases map
3792
+ const aliasesIds = Object.keys(this.objects)
3793
+ .filter(id => id.startsWith('alias.0'));
3794
+
3795
+ this.info.aliasesMap = {};
3796
+
3797
+ for (const id of aliasesIds) {
3798
+ const obj = this.objects[id];
3799
+ if (obj?.common?.alias?.id) {
3800
+ if (typeof obj.common.alias.id === 'string') {
3801
+ const usedId = obj.common.alias.id;
3802
+ if (!this.info.aliasesMap[usedId]) {
3803
+ this.info.aliasesMap[usedId] = [id];
3804
+ } else if (!this.info.aliasesMap[usedId].includes(id)) {
3805
+ this.info.aliasesMap[usedId].push(id);
3806
+ }
3807
+ } else {
3808
+ const readId = obj.common.alias.id.read;
3809
+ if (readId) {
3810
+ if (!this.info.aliasesMap[readId]) {
3811
+ this.info.aliasesMap[readId] = [id];
3812
+ } else if (!this.info.aliasesMap[readId].includes(id)) {
3813
+ this.info.aliasesMap[readId].push(id);
3814
+ }
3815
+ }
3816
+ const writeId = obj.common.alias.id.write;
3817
+ if (writeId) {
3818
+ if (!this.info.aliasesMap[writeId]) {
3819
+ this.info.aliasesMap[writeId] = [id];
3820
+ } else if (!this.info.aliasesMap[writeId].includes(id)) {
3821
+ this.info.aliasesMap[writeId].push(id);
3822
+ }
3823
+ }
3824
+ }
3825
+ }
3826
+ }
3827
+ }
3828
+
3737
3829
  /**
3738
3830
  * Processes a single element in regard to certain filters, columns for admin and updates object dict
3739
3831
  * @returns Returns an object containing the new state (if any) and whether the object was filtered.
@@ -3750,6 +3842,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
3750
3842
  console.log(`> objectChange ${id}`);
3751
3843
  const type = obj?.type;
3752
3844
 
3845
+ // If the object is filtered out, we don't need to update the React state
3753
3846
  if (
3754
3847
  obj &&
3755
3848
  typeof this.props.filterFunc === 'function' &&
@@ -3764,7 +3857,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
3764
3857
  }
3765
3858
 
3766
3859
  let newInnerState = null;
3767
- if (id.startsWith('system.adapter.') && obj && obj.type === 'adapter') {
3860
+ if (id.startsWith('system.adapter.') && obj?.type === 'adapter') {
3768
3861
  const columnsForAdmin: Record<string, CustomAdminColumnStored[]> | null = JSON.parse(JSON.stringify(this.state.columnsForAdmin));
3769
3862
 
3770
3863
  this.parseObjectForAdmins(columnsForAdmin, obj as ioBroker.AdapterObject);
@@ -3773,12 +3866,17 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
3773
3866
  newInnerState = { columnsForAdmin };
3774
3867
  }
3775
3868
  }
3869
+
3776
3870
  this.objects = this.objects || {};
3871
+
3777
3872
  if (obj) {
3778
3873
  this.objects[id] = obj;
3779
3874
  } else if (this.objects[id]) {
3780
3875
  delete this.objects[id];
3781
3876
  }
3877
+
3878
+ this.updateAliases(id);
3879
+
3782
3880
  return { newInnerState, filtered: false };
3783
3881
  }
3784
3882
 
@@ -4650,7 +4748,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
4650
4748
  >
4651
4749
  <Tooltip
4652
4750
  title={this.props.t('ra_Refresh tree')}
4653
- componentsProps={{ popper: { sx: styles.tooltip } }}
4751
+ slotProps={{ popper: { sx: styles.tooltip } }}
4654
4752
  >
4655
4753
  <div>
4656
4754
  <IconButton
@@ -4664,7 +4762,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
4664
4762
  </Tooltip>
4665
4763
  {this.props.showExpertButton && !this.props.expertMode && <Tooltip
4666
4764
  title={this.props.t('ra_expertMode')}
4667
- componentsProps={{ popper: { sx: styles.tooltip } }}
4765
+ slotProps={{ popper: { sx: styles.tooltip } }}
4668
4766
  >
4669
4767
  <IconButton
4670
4768
  key="expertMode"
@@ -4677,7 +4775,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
4677
4775
  </Tooltip>}
4678
4776
  {!this.props.disableColumnSelector && this.props.width !== 'xs' && <Tooltip
4679
4777
  title={this.props.t('ra_Configure')}
4680
- componentsProps={{ popper: { sx: styles.tooltip } }}
4778
+ slotProps={{ popper: { sx: styles.tooltip } }}
4681
4779
  >
4682
4780
  <IconButton
4683
4781
  key="columnSelector"
@@ -4690,7 +4788,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
4690
4788
  </Tooltip>}
4691
4789
  {this.props.width !== 'xs' && this.state.expandAllVisible && <Tooltip
4692
4790
  title={this.props.t('ra_Expand all nodes')}
4693
- componentsProps={{ popper: { sx: styles.tooltip } }}
4791
+ slotProps={{ popper: { sx: styles.tooltip } }}
4694
4792
  >
4695
4793
  <IconButton key="expandAll" onClick={() => this.onExpandAll()} size="large">
4696
4794
  <IconOpen />
@@ -4698,7 +4796,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
4698
4796
  </Tooltip>}
4699
4797
  <Tooltip
4700
4798
  title={this.props.t('ra_Collapse all nodes')}
4701
- componentsProps={{ popper: { sx: styles.tooltip } }}
4799
+ slotProps={{ popper: { sx: styles.tooltip } }}
4702
4800
  >
4703
4801
  <IconButton key="collapseAll" onClick={() => this.onCollapseAll()} size="large">
4704
4802
  <IconClosed />
@@ -4706,7 +4804,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
4706
4804
  </Tooltip>
4707
4805
  {this.props.width !== 'xs' && <Tooltip
4708
4806
  title={this.props.t('ra_Expand one step node')}
4709
- componentsProps={{ popper: { sx: styles.tooltip } }}
4807
+ slotProps={{ popper: { sx: styles.tooltip } }}
4710
4808
  >
4711
4809
  <IconButton
4712
4810
  key="expandVisible"
@@ -4732,7 +4830,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
4732
4830
  </Tooltip>}
4733
4831
  {this.props.width !== 'xs' && <Tooltip
4734
4832
  title={this.props.t('ra_Collapse one step node')}
4735
- componentsProps={{ popper: { sx: styles.tooltip } }}
4833
+ slotProps={{ popper: { sx: styles.tooltip } }}
4736
4834
  >
4737
4835
  <IconButton
4738
4836
  key="collapseVisible"
@@ -4758,7 +4856,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
4758
4856
  </Tooltip>}
4759
4857
  {this.props.objectStatesView && <Tooltip
4760
4858
  title={this.props.t('ra_Toggle the states view')}
4761
- componentsProps={{ popper: { sx: styles.tooltip } }}
4859
+ slotProps={{ popper: { sx: styles.tooltip } }}
4762
4860
  >
4763
4861
  <IconButton onClick={() => this.onStatesViewVisible()} size="large">
4764
4862
  <LooksOneIcon color={this.state.statesView ? 'primary' : 'inherit'} />
@@ -4767,7 +4865,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
4767
4865
 
4768
4866
  <Tooltip
4769
4867
  title={this.props.t('ra_Show/Hide object descriptions')}
4770
- componentsProps={{ popper: { sx: styles.tooltip } }}
4868
+ slotProps={{ popper: { sx: styles.tooltip } }}
4771
4869
  >
4772
4870
  <IconButton
4773
4871
  onClick={() => {
@@ -4785,7 +4883,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
4785
4883
 
4786
4884
  {this.props.objectAddBoolean ? <Tooltip
4787
4885
  title={this.toolTipObjectCreating()}
4788
- componentsProps={{ popper: { sx: styles.tooltip } }}
4886
+ slotProps={{ popper: { sx: styles.tooltip } }}
4789
4887
  >
4790
4888
  <div>
4791
4889
  <IconButton
@@ -4804,7 +4902,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
4804
4902
 
4805
4903
  {this.props.objectImportExport && <Tooltip
4806
4904
  title={this.props.t('ra_Add objects tree from JSON file')}
4807
- componentsProps={{ popper: { sx: styles.tooltip } }}
4905
+ slotProps={{ popper: { sx: styles.tooltip } }}
4808
4906
  >
4809
4907
  <IconButton
4810
4908
  onClick={() => {
@@ -4824,7 +4922,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
4824
4922
  (!!this.state.selected.length || this.state.selectedNonObject) &&
4825
4923
  <Tooltip
4826
4924
  title={this.props.t('ra_Save objects tree as JSON file')}
4827
- componentsProps={{ popper: { sx: styles.tooltip } }}
4925
+ slotProps={{ popper: { sx: styles.tooltip } }}
4828
4926
  >
4829
4927
  <IconButton
4830
4928
  onClick={() =>
@@ -4844,7 +4942,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
4844
4942
  </div>}
4845
4943
  {this.props.objectEditBoolean && <Tooltip
4846
4944
  title={this.props.t('ra_Edit custom config')}
4847
- componentsProps={{ popper: { sx: styles.tooltip } }}
4945
+ slotProps={{ popper: { sx: styles.tooltip } }}
4848
4946
  >
4849
4947
  <IconButton
4850
4948
  onClick={() => {
@@ -5049,7 +5147,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
5049
5147
  this.state.filter.expertMode && this.props.objectEditOfAccessControl ? <Tooltip
5050
5148
  key="acl"
5051
5149
  title={item.data.aclTooltip}
5052
- componentsProps={{ popper: { sx: styles.tooltip } }}
5150
+ slotProps={{ popper: { sx: styles.tooltip } }}
5053
5151
  >
5054
5152
  <IconButton
5055
5153
  sx={{
@@ -5378,7 +5476,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
5378
5476
  return <Tooltip
5379
5477
  key="value"
5380
5478
  title={this.state.tooltipInfo?.el}
5381
- componentsProps={{
5479
+ slotProps={{
5382
5480
  popper: { sx: styles.cellValueTooltipBox },
5383
5481
  tooltip: { sx: styles.cellValueTooltip },
5384
5482
  }}
@@ -5544,6 +5642,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
5544
5642
  }
5545
5643
  this.setState({ enumDialogEnums });
5546
5644
  }}
5645
+ secondaryAction={icon}
5547
5646
  >
5548
5647
  <ListItemIcon sx={{ '&.MuiListItemIcon-root': styles.enumCheckbox }}>
5549
5648
  <Checkbox
@@ -5555,7 +5654,6 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
5555
5654
  />
5556
5655
  </ListItemIcon>
5557
5656
  <ListItemText id={labelId}>{name}</ListItemText>
5558
- {icon ? <ListItemSecondaryAction>{icon}</ListItemSecondaryAction> : null}
5559
5657
  </ListItem>;
5560
5658
  })}
5561
5659
  </List>
@@ -5874,6 +5972,37 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
5874
5972
  return null;
5875
5973
  }
5876
5974
 
5975
+ renderAliasLink(id: string, index?: number, customStyle?: Record<string, any>): React.JSX.Element | null {
5976
+ // read the type of operation
5977
+ const aliasObj = this.objects[this.info.aliasesMap[id][index]].common.alias.id;
5978
+ if (aliasObj) {
5979
+ index = index || 0;
5980
+ return <Box
5981
+ component="div"
5982
+ onClick={e => {
5983
+ e.stopPropagation();
5984
+ e.preventDefault();
5985
+ const aliasId = this.info.aliasesMap[id][index];
5986
+ // if more than one alias, close the menu
5987
+ if (this.info.aliasesMap[id].length > 1) {
5988
+ this.setState({ aliasMenu: '' });
5989
+ }
5990
+ this.onSelect(aliasId);
5991
+ setTimeout(() => this.expandAllSelected(() => this.scrollToItem(aliasId)), 100);
5992
+ }}
5993
+ sx={customStyle || this.styles.aliasAlone}
5994
+ >
5995
+ <span className="admin-browser-arrow">
5996
+ {(typeof aliasObj === 'string' ||
5997
+ (aliasObj.read === id && aliasObj.write === id)) ? '↔' : (aliasObj.read === id ? '→' : '←')}
5998
+ </span>
5999
+ {this.info.aliasesMap[id][index]}
6000
+ </Box>;
6001
+ }
6002
+
6003
+ return null;
6004
+ }
6005
+
5877
6006
  /**
5878
6007
  * Renders a leaf.
5879
6008
  */
@@ -5996,60 +6125,81 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
5996
6125
  }
5997
6126
  }
5998
6127
 
5999
- const readWriteAlias = typeof common?.alias?.id === 'object';
6000
-
6001
- const alias =
6002
- id.startsWith('alias.') && common?.alias?.id ? (
6003
- readWriteAlias ?
6004
- <div style={styles.cellIdAliasReadWriteDiv}>
6005
- {common.alias.id.read ? <Box
6006
- component="div"
6007
- onClick={e => {
6008
- e.stopPropagation();
6009
- e.preventDefault();
6010
- this.onSelect(common.alias.id.read);
6011
- setTimeout(
6012
- () => this.expandAllSelected(() => this.scrollToItem(common.alias.id.read)),
6013
- 100,
6014
- );
6015
- }}
6016
- sx={this.styles.aliasReadWrite}
6017
- >
6018
-
6019
- {common.alias.id.read}
6020
- </Box> : null}
6021
- {common.alias.id.write ? <Box
6022
- component="div"
6023
- onClick={e => {
6024
- e.stopPropagation();
6025
- e.preventDefault();
6026
- this.onSelect(common.alias.id.write);
6027
- setTimeout(
6028
- () => this.expandAllSelected(() => this.scrollToItem(common.alias.id.write)),
6029
- 100,
6030
- );
6031
- }}
6032
- sx={this.styles.aliasReadWrite}
6033
- >
6034
-
6035
- {common.alias.id.write}
6036
- </Box> : null}
6037
- </div>
6038
- :
6039
- <Box
6128
+ let readWriteAlias: boolean = false;
6129
+ let alias: React.JSX.Element | null = null;
6130
+ if (id.startsWith('alias.') && common?.alias?.id) {
6131
+ readWriteAlias = typeof common.alias.id === 'object';
6132
+ if (readWriteAlias) {
6133
+ alias = <div style={styles.cellIdAliasReadWriteDiv}>
6134
+ {common.alias.id.read ? <Box
6040
6135
  component="div"
6041
6136
  onClick={e => {
6042
6137
  e.stopPropagation();
6043
6138
  e.preventDefault();
6044
- this.onSelect(common.alias.id);
6045
- setTimeout(() => this.expandAllSelected(() => this.scrollToItem(common.alias.id)), 100);
6139
+ this.onSelect(common.alias.id.read);
6140
+ setTimeout(
6141
+ () => this.expandAllSelected(() => this.scrollToItem(common.alias.id.read)),
6142
+ 100,
6143
+ );
6046
6144
  }}
6047
- sx={this.styles.aliasAlone}
6145
+ sx={this.styles.aliasReadWrite}
6146
+ >
6147
+
6148
+ {common.alias.id.read}
6149
+ </Box> : null}
6150
+ {common.alias.id.write ? <Box
6151
+ component="div"
6152
+ onClick={e => {
6153
+ e.stopPropagation();
6154
+ e.preventDefault();
6155
+ this.onSelect(common.alias.id.write);
6156
+ setTimeout(
6157
+ () => this.expandAllSelected(() => this.scrollToItem(common.alias.id.write)),
6158
+ 100,
6159
+ );
6160
+ }}
6161
+ sx={this.styles.aliasReadWrite}
6048
6162
  >
6049
6163
 
6050
- {common.alias.id}
6051
- </Box>
6052
- ) : null;
6164
+ {common.alias.id.write}
6165
+ </Box> : null}
6166
+ </div>;
6167
+ } else {
6168
+ alias = <Box
6169
+ component="div"
6170
+ onClick={e => {
6171
+ e.stopPropagation();
6172
+ e.preventDefault();
6173
+ this.onSelect(common.alias.id);
6174
+ setTimeout(() => this.expandAllSelected(() => this.scrollToItem(common.alias.id)), 100);
6175
+ }}
6176
+ sx={this.styles.aliasAlone}
6177
+ >
6178
+
6179
+ {common.alias.id}
6180
+ </Box>;
6181
+ }
6182
+ } else if (this.info.aliasesMap[id]) {
6183
+ // Some alias points to this object. It can be more than one
6184
+ if (this.info.aliasesMap[id].length > 1) {
6185
+ // Show number of aliases and open a menu by click
6186
+ alias = <Box
6187
+ component="div"
6188
+ id={`alias_${id}`}
6189
+ onClick={e => {
6190
+ e.stopPropagation();
6191
+ e.preventDefault();
6192
+ this.setState({ aliasMenu: id });
6193
+ }}
6194
+ sx={this.styles.aliasAlone}
6195
+ >
6196
+ {this.props.t('ra_%s links from aliases', this.info.aliasesMap[id].length)}
6197
+ </Box>;
6198
+ } else {
6199
+ // Show name of alias and open it by click
6200
+ alias = this.renderAliasLink(id, 0);
6201
+ }
6202
+ }
6053
6203
 
6054
6204
  let checkColor = common?.color;
6055
6205
  let invertBackground;
@@ -6209,19 +6359,18 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
6209
6359
 
6210
6360
  const narrowStyleWithDetails = this.props.width === 'xs' && this.state.focused === id;
6211
6361
 
6212
- const colID = <Grid
6362
+ const colID = <Grid2
6213
6363
  container
6214
6364
  wrap="nowrap"
6215
6365
  direction="row"
6216
6366
  sx={styles.cellId}
6217
6367
  style={{ width: this.columnsVisibility.id, paddingLeft }}
6218
6368
  >
6219
- <Grid item container alignItems="center">
6369
+ <Grid2 container alignItems="center">
6220
6370
  {checkbox}
6221
6371
  {iconFolder}
6222
- </Grid>
6223
- <Grid
6224
- item
6372
+ </Grid2>
6373
+ <Grid2
6225
6374
  style={{
6226
6375
  ...styles.cellIdSpan,
6227
6376
  ...(invertBackground ? this.styles.invertedBackground : undefined),
@@ -6231,17 +6380,17 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
6231
6380
  >
6232
6381
  <Tooltip
6233
6382
  title={getIdFieldTooltip(item.data, this.props.lang)}
6234
- componentsProps={{ popper: { sx: styles.tooltip } }}
6383
+ slotProps={{ popper: { sx: styles.tooltip } }}
6235
6384
  >
6236
6385
  <div>{item.data.name}</div>
6237
6386
  </Tooltip>
6238
6387
  {alias}
6239
6388
  {icons}
6240
- </Grid>
6389
+ </Grid2>
6241
6390
  <div style={{ ...styles.grow, ...(invertBackground ? this.styles.invertedBackgroundFlex : {}) }} />
6242
- <Grid item container alignItems="center">
6391
+ <Grid2 container alignItems="center">
6243
6392
  {iconItem}
6244
- </Grid>
6393
+ </Grid2>
6245
6394
  {this.props.width !== 'xs' ? <div>
6246
6395
  <IconCopy
6247
6396
  className={narrowStyleWithDetails ? '' : 'copyButton'}
@@ -6249,7 +6398,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
6249
6398
  onClick={e => this.onCopy(e, id)}
6250
6399
  />
6251
6400
  </div> : null}
6252
- </Grid>;
6401
+ </Grid2>;
6253
6402
 
6254
6403
  let colName = (narrowStyleWithDetails && name) || this.columnsVisibility.name ? <Box
6255
6404
  component="div"
@@ -6595,7 +6744,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
6595
6744
  colButtons = null;
6596
6745
  }
6597
6746
 
6598
- const row = <Grid
6747
+ const row = <Grid2
6599
6748
  container
6600
6749
  direction="row"
6601
6750
  wrap="nowrap"
@@ -6650,7 +6799,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
6650
6799
  {colCustom}
6651
6800
  {colValue}
6652
6801
  {colButtons}
6653
- </Grid>;
6802
+ </Grid2>;
6654
6803
  return { row, details: colDetails };
6655
6804
  }
6656
6805
 
@@ -7470,6 +7619,33 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
7470
7619
  });
7471
7620
  }
7472
7621
 
7622
+ /** Renders the aliases list for one state (if more than 2) */
7623
+ private renderAliasMenu(): React.JSX.Element | null {
7624
+ if (!this.state.aliasMenu) {
7625
+ return null;
7626
+ }
7627
+
7628
+ return <Menu
7629
+ key="aliasmenu"
7630
+ open={!0}
7631
+ anchorEl={window.document.getElementById(`alias_${this.state.aliasMenu}`)}
7632
+ onClose={() => this.setState({ aliasMenu: '' })}
7633
+ >
7634
+ {this.info.aliasesMap[this.state.aliasMenu].map((aliasId, i) => <MenuItem
7635
+ key={aliasId}
7636
+ onClick={() => this.onSelect(aliasId)}
7637
+ >
7638
+ <ListItemText>
7639
+ {this.renderAliasLink(this.state.aliasMenu, i, {
7640
+ '& .admin-browser-arrow': {
7641
+ mr: '8px',
7642
+ },
7643
+ })}
7644
+ </ListItemText>
7645
+ </MenuItem>)}
7646
+ </Menu>;
7647
+ }
7648
+
7473
7649
  /**
7474
7650
  * Renders the right mouse button context menu
7475
7651
  */
@@ -7667,10 +7843,10 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
7667
7843
  ? this.styles.cellButtonsButtonWithCustoms
7668
7844
  : styles.cellButtonsButtonWithoutCustoms}
7669
7845
  />,
7670
- label: this.props.t('ra_Edit alias'),
7846
+ label: this.info.aliasesMap[item.data.id] ? this.props.t('ra_Edit alias') : this.props.t('ra_Create alias'),
7671
7847
  onClick: () => {
7672
7848
  if (obj?.common?.alias) {
7673
- this.setState({ editObjectDialog: item.data.id, showContextMenu: null, editObjectAlias: true });
7849
+ this.setState({ showContextMenu: null, editObjectDialog: item.data.id, editObjectAlias: true });
7674
7850
  } else {
7675
7851
  this.setState({ showContextMenu: null, showAliasEditor: item.data.id });
7676
7852
  }
@@ -7749,9 +7925,11 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
7749
7925
  if (ITEMS[key].subMenu) {
7750
7926
  items.push(<MenuItem
7751
7927
  key={key}
7752
- onClick={(e: React.MouseEvent<HTMLLIElement>) => this.state.showContextMenu && this.setState({
7928
+ href=""
7929
+ onClick={(e: React.MouseEvent<HTMLAnchorElement>) => this.state.showContextMenu && this.setState({
7753
7930
  showContextMenu: {
7754
7931
  item: this.state.showContextMenu.item,
7932
+ position: this.state.showContextMenu.position,
7755
7933
  subItem: key,
7756
7934
  subAnchor: e.target as HTMLLIElement,
7757
7935
  },
@@ -7777,7 +7955,12 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
7777
7955
  anchorEl={this.state.showContextMenu.subAnchor}
7778
7956
  onClose={() => {
7779
7957
  if (this.state.showContextMenu) {
7780
- this.setState({ showContextMenu: { item: this.state.showContextMenu.item } });
7958
+ this.setState({
7959
+ showContextMenu: {
7960
+ item: this.state.showContextMenu.item,
7961
+ position: this.state.showContextMenu.position,
7962
+ },
7963
+ });
7781
7964
  }
7782
7965
  this.contextMenu = null;
7783
7966
  }}
@@ -7819,8 +8002,6 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
7819
8002
  return null;
7820
8003
  }
7821
8004
 
7822
- const el = document.getElementById(id);
7823
-
7824
8005
  return <Menu
7825
8006
  key="contextMenu"
7826
8007
  open={!0}
@@ -7834,7 +8015,8 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
7834
8015
  });
7835
8016
  }
7836
8017
  }}
7837
- anchorEl={el}
8018
+ anchorReference="anchorPosition"
8019
+ anchorPosition={this.state.showContextMenu.position}
7838
8020
  onClose={() => {
7839
8021
  this.setState({ showContextMenu: null });
7840
8022
  this.contextMenu = null;
@@ -8009,6 +8191,7 @@ export class ObjectBrowserClass extends Component<ObjectBrowserProps, ObjectBrow
8009
8191
  </div>
8010
8192
  </TabContent>
8011
8193
  {this.renderContextMenu()}
8194
+ {this.renderAliasMenu()}
8012
8195
  {this.renderToast()}
8013
8196
  {this.renderColumnsEditCustomDialog()}
8014
8197
  {this.renderColumnsSelectorDialog()}