ydb-embedded-ui 2.4.4 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/components/InfoViewer/formatters/schema.ts +2 -1
  3. package/dist/components/InfoViewer/schemaInfo/CDCStreamInfo.tsx +3 -16
  4. package/dist/components/InfoViewer/schemaInfo/PersQueueGroupInfo.tsx +8 -13
  5. package/dist/components/InfoViewer/schemaInfo/TableIndexInfo.tsx +2 -12
  6. package/dist/components/InfoViewer/schemaOverview/CDCStreamOverview.tsx +3 -16
  7. package/dist/components/InfoViewer/schemaOverview/PersQueueGroupOverview.tsx +8 -13
  8. package/dist/components/InfoViewer/utils.ts +6 -6
  9. package/dist/components/Loader/Loader.scss +6 -3
  10. package/dist/components/Loader/Loader.tsx +7 -5
  11. package/dist/components/Loader/index.ts +1 -0
  12. package/dist/components/UptimeFIlter/UptimeFilter.tsx +21 -0
  13. package/dist/components/UptimeFIlter/index.ts +1 -0
  14. package/dist/containers/Node/Node.scss +1 -0
  15. package/dist/containers/Node/Node.tsx +3 -8
  16. package/dist/containers/Node/NodeStructure/NodeStructure.scss +0 -6
  17. package/dist/containers/Node/NodeStructure/NodeStructure.tsx +1 -1
  18. package/dist/containers/Nodes/Nodes.js +22 -10
  19. package/dist/{components → containers}/NodesViewer/NodesViewer.js +49 -62
  20. package/dist/{components → containers}/NodesViewer/NodesViewer.scss +0 -0
  21. package/dist/containers/Storage/Pdisk/Pdisk.scss +1 -1
  22. package/dist/containers/Storage/Storage.js +35 -10
  23. package/dist/containers/Storage/StorageNodes/StorageNodes.scss +2 -2
  24. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +35 -17
  25. package/dist/containers/Storage/StorageNodes/i18n/en.json +6 -4
  26. package/dist/containers/Storage/StorageNodes/i18n/ru.json +6 -4
  27. package/dist/containers/Storage/UsageFilter/UsageFilter.scss +10 -5
  28. package/dist/containers/Tenant/Acl/Acl.js +1 -7
  29. package/dist/containers/Tenant/Diagnostics/Compute/Compute.js +1 -1
  30. package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +34 -8
  31. package/dist/containers/Tenant/Diagnostics/Describe/Describe.scss +0 -8
  32. package/dist/containers/Tenant/Diagnostics/Describe/Describe.tsx +2 -6
  33. package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +0 -7
  34. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +5 -7
  35. package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.js +21 -13
  36. package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.tsx +1 -5
  37. package/dist/containers/Tenant/QueryEditor/QueryExplain/QueryExplain.js +4 -4
  38. package/dist/containers/Tenant/QueryEditor/SaveQuery/SaveQuery.js +1 -4
  39. package/dist/containers/Tenant/Schema/SchemaInfoViewer/SchemaInfoViewer.js +23 -28
  40. package/dist/containers/Tenant/TenantPages.tsx +1 -1
  41. package/dist/containers/Tenant/utils/schemaActions.ts +9 -20
  42. package/dist/store/reducers/clusterNodes.js +29 -10
  43. package/dist/store/reducers/nodes.js +24 -3
  44. package/dist/store/reducers/{schema.js → schema.ts} +22 -14
  45. package/dist/store/reducers/storage.js +46 -5
  46. package/dist/types/store/schema.ts +46 -0
  47. package/dist/utils/index.js +6 -2
  48. package/dist/utils/nodes.ts +9 -0
  49. package/package.json +1 -1
@@ -1,28 +1,46 @@
1
1
  import React from 'react';
2
2
  import cn from 'bem-cn-lite';
3
3
  import PropTypes from 'prop-types';
4
- import _ from 'lodash';
5
4
  import {connect} from 'react-redux';
6
5
 
7
6
  import {TextInput, Label} from '@gravity-ui/uikit';
8
7
  import DataTable from '@yandex-cloud/react-data-table';
9
8
 
10
- import ProblemFilter, {problemFilterType} from '../ProblemFilter/ProblemFilter';
9
+ import ProblemFilter, {problemFilterType} from '../../components/ProblemFilter/ProblemFilter';
10
+ import {UptimeFilter} from '../../components/UptimeFIlter';
11
+ import {Illustration} from '../../components/Illustration';
11
12
 
12
13
  import {withSearch} from '../../HOCS';
13
14
  import {calcUptime} from '../../utils';
14
- import {ALL, DEFAULT_TABLE_SETTINGS} from '../../utils/constants';
15
+ import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants';
15
16
  import {changeFilter} from '../../store/reducers/settings';
17
+ import {filterNodesByStatusAndUptime} from '../../store/reducers/clusterNodes';
18
+ import {setNodesUptimeFilter} from '../../store/reducers/nodes';
16
19
  import {hideTooltip, showTooltip} from '../../store/reducers/tooltip';
17
20
  import {getNodesColumns} from '../../utils/getNodesColumns';
18
21
 
19
- import {Illustration} from '../Illustration';
20
-
21
22
  import './NodesViewer.scss';
22
23
 
23
24
  const b = cn('nodes-viewer');
24
25
 
25
26
  class NodesViewer extends React.PureComponent {
27
+ static selectNodesToShow(nodes, searchQuery) {
28
+ let preparedNodes = nodes;
29
+ if (nodes && Array.isArray(nodes)) {
30
+ preparedNodes = nodes
31
+ .map((node) => {
32
+ node.uptime = calcUptime(node.StartTime);
33
+ return node;
34
+ })
35
+ /* Filter by nodes with the Host field.
36
+ If a node does not have a Host field it is also
37
+ included in the filter and displayed with a dash in the corresponding column
38
+ */
39
+ .filter((node) => (node.Host ? node.Host.includes(searchQuery) : true));
40
+ }
41
+ return preparedNodes;
42
+ }
43
+
26
44
  static propTypes = {
27
45
  nodes: PropTypes.array.isRequired,
28
46
  className: PropTypes.string,
@@ -30,7 +48,9 @@ class NodesViewer extends React.PureComponent {
30
48
  handleSearchQuery: PropTypes.func,
31
49
  showTooltip: PropTypes.func,
32
50
  hideTooltip: PropTypes.func,
33
- filter: problemFilterType,
51
+ problemFilter: problemFilterType,
52
+ nodesUptimeFilter: PropTypes.string,
53
+ setNodesUptimeFilter: PropTypes.func,
34
54
  changeFilter: PropTypes.func,
35
55
  showControls: PropTypes.bool,
36
56
  additionalNodesInfo: PropTypes.object,
@@ -42,60 +62,18 @@ class NodesViewer extends React.PureComponent {
42
62
  showControls: true,
43
63
  };
44
64
 
45
- state = {
46
- filteredNodes: [],
47
- nodesToShow: [],
65
+ handleProblemFilterChange = (value) => {
66
+ this.props.changeFilter(value);
48
67
  };
49
68
 
50
- static getDerivedStateFromProps(props, state) {
51
- const {nodes, filter} = props;
52
- if (!_.isEqual(nodes, state.nodes)) {
53
- return {
54
- nodes,
55
- filteredNodes: NodesViewer.filterNodes(nodes, filter),
56
- };
57
- }
58
- return null;
59
- }
60
-
61
- static filterNodes(nodes, filter) {
62
- if (filter === ALL) {
63
- return nodes;
64
- }
65
-
66
- return _.filter(nodes, (node) => {
67
- return node.Overall && node.Overall !== 'Green';
68
- });
69
- }
70
-
71
- static selectNodesToShow(nodes, searchQuery) {
72
- let preparedNodes = nodes;
73
- if (nodes && Array.isArray(nodes)) {
74
- preparedNodes = nodes
75
- .map((node) => {
76
- node.uptime = calcUptime(node.StartTime);
77
- return node;
78
- })
79
- /* Filter by nodes with the Host field.
80
- If a node does not have a Host field it is also
81
- included in the filter and displayed with a dash in the corresponding column
82
- */
83
- .filter((node) => (node.Host ? node.Host.includes(searchQuery) : true));
84
- }
85
- return preparedNodes;
86
- }
87
-
88
- onChangeProblemFilter = (filter) => {
89
- const {nodes, changeFilter} = this.props;
90
- const filteredNodes = NodesViewer.filterNodes(nodes, filter);
91
-
92
- changeFilter(filter);
93
- this.setState({filteredNodes});
69
+ handleUptimeFilterChange = (value) => {
70
+ this.props.setNodesUptimeFilter(value);
94
71
  };
95
72
 
96
73
  renderControls() {
97
- const {searchQuery, handleSearchQuery, filter} = this.props;
98
- const nodesToShow = NodesViewer.selectNodesToShow(this.state.filteredNodes, searchQuery);
74
+ const {nodes, searchQuery, handleSearchQuery, nodesUptimeFilter, problemFilter} =
75
+ this.props;
76
+ const nodesToShow = NodesViewer.selectNodesToShow(nodes, searchQuery);
99
77
 
100
78
  return (
101
79
  <div className={b('controls')}>
@@ -108,7 +86,8 @@ class NodesViewer extends React.PureComponent {
108
86
  hasClear
109
87
  autoFocus
110
88
  />
111
- <ProblemFilter value={filter} onChange={this.onChangeProblemFilter} />
89
+ <ProblemFilter value={problemFilter} onChange={this.handleProblemFilterChange} />
90
+ <UptimeFilter value={nodesUptimeFilter} onChange={this.handleUptimeFilterChange} />
112
91
  <Label theme="info" size="m">{`Nodes: ${nodesToShow.length}`}</Label>
113
92
  </div>
114
93
  );
@@ -119,13 +98,13 @@ class NodesViewer extends React.PureComponent {
119
98
  className,
120
99
  searchQuery,
121
100
  path,
122
- filter,
101
+ problemFilter,
123
102
  showControls,
124
103
  hideTooltip,
125
104
  showTooltip,
126
105
  additionalNodesInfo = {},
106
+ nodes,
127
107
  } = this.props;
128
- const {filteredNodes = []} = this.state;
129
108
 
130
109
  const columns = getNodesColumns({
131
110
  tabletsPath: path,
@@ -134,7 +113,7 @@ class NodesViewer extends React.PureComponent {
134
113
  getNodeRef: additionalNodesInfo.getNodeRef,
135
114
  });
136
115
 
137
- const nodesToShow = NodesViewer.selectNodesToShow(filteredNodes, searchQuery);
116
+ const nodesToShow = NodesViewer.selectNodesToShow(nodes, searchQuery);
138
117
 
139
118
  return (
140
119
  <div className={`${b()} ${className}`}>
@@ -146,7 +125,7 @@ class NodesViewer extends React.PureComponent {
146
125
  <div className={b('table-content')}>
147
126
  <DataTable
148
127
  theme="yandex-cloud"
149
- key={filter}
128
+ key={problemFilter}
150
129
  data={nodesToShow}
151
130
  columns={columns}
152
131
  settings={DEFAULT_TABLE_SETTINGS}
@@ -160,9 +139,16 @@ class NodesViewer extends React.PureComponent {
160
139
  }
161
140
  }
162
141
 
163
- const mapStateToProps = (state) => {
142
+ const mapStateToProps = (state, ownProps) => {
143
+ const {nodesUptimeFilter} = state.nodes;
144
+ const {problemFilter} = state.settings;
145
+
146
+ const nodes = filterNodesByStatusAndUptime(ownProps.nodes, problemFilter, nodesUptimeFilter);
147
+
164
148
  return {
165
- filter: state.settings.problemFilter,
149
+ problemFilter,
150
+ nodesUptimeFilter,
151
+ nodes,
166
152
  };
167
153
  };
168
154
 
@@ -170,6 +156,7 @@ const mapDispatchToProps = {
170
156
  changeFilter,
171
157
  hideTooltip,
172
158
  showTooltip,
159
+ setNodesUptimeFilter,
173
160
  };
174
161
 
175
162
  const ConnectedNodesViewer = connect(mapStateToProps, mapDispatchToProps)(NodesViewer);
@@ -1,7 +1,7 @@
1
1
  .pdisk-storage {
2
2
  position: relative;
3
3
 
4
- min-width: 120px;
4
+ width: 120px;
5
5
 
6
6
  border-radius: 4px; // to match interactive area with disk shape
7
7
 
@@ -8,7 +8,9 @@ import {RadioButton, Label} from '@gravity-ui/uikit';
8
8
  import {Search} from '../../components/Search';
9
9
  import {UsageFilter} from './UsageFilter';
10
10
  import {AutoFetcher} from '../../utils/autofetcher';
11
+ import {NodesUptimeFilterValues} from '../../utils/nodes';
11
12
  import {TableSkeleton} from '../../components/TableSkeleton/TableSkeleton';
13
+ import {UptimeFilter} from '../../components/UptimeFIlter';
12
14
  import {AccessDenied} from '../../components/Errors/403';
13
15
 
14
16
  import {
@@ -22,6 +24,7 @@ import {
22
24
  getNodesObject,
23
25
  StorageTypes,
24
26
  setStorageType,
27
+ setNodesUptimeFilter,
25
28
  VisibleEntitiesTitles,
26
29
  getStoragePoolsGroupsCount,
27
30
  getStorageNodesCount,
@@ -66,6 +69,8 @@ class Storage extends React.Component {
66
69
  setHeader: PropTypes.func,
67
70
  tenant: PropTypes.string,
68
71
  nodeId: PropTypes.string,
72
+ nodesUptimeFilter: PropTypes.string,
73
+ setNodesUptimeFilter: PropTypes.func,
69
74
  };
70
75
 
71
76
  componentDidMount() {
@@ -166,7 +171,8 @@ class Storage extends React.Component {
166
171
  }
167
172
 
168
173
  renderDataTable() {
169
- const {flatListStorageEntities, visibleEntities, nodes, storageType} = this.props;
174
+ const {flatListStorageEntities, visibleEntities, nodesUptimeFilter, nodes, storageType} =
175
+ this.props;
170
176
 
171
177
  return (
172
178
  <div className={b('table-wrapper')}>
@@ -182,9 +188,10 @@ class Storage extends React.Component {
182
188
  {storageType === StorageTypes.nodes && (
183
189
  <StorageNodes
184
190
  visibleEntities={visibleEntities}
191
+ nodesUptimeFilter={nodesUptimeFilter}
185
192
  data={flatListStorageEntities}
186
193
  tableSettings={tableSettings}
187
- onShowAll={() => this.onGroupVisibilityChange(VisibleEntities.All)}
194
+ onShowAll={this.onShowAllNodes}
188
195
  />
189
196
  )}
190
197
  </div>
@@ -201,6 +208,15 @@ class Storage extends React.Component {
201
208
  setStorageType(value);
202
209
  };
203
210
 
211
+ onUptimeFilterChange = (value) => {
212
+ this.props.setNodesUptimeFilter(value);
213
+ };
214
+
215
+ onShowAllNodes = () => {
216
+ this.onGroupVisibilityChange(VisibleEntities.All);
217
+ this.onUptimeFilterChange(NodesUptimeFilterValues.All);
218
+ };
219
+
204
220
  renderEntitiesCount() {
205
221
  const {storageType, groupsCount, nodesCount, flatListStorageEntities, loading, wasLoaded} =
206
222
  this.props;
@@ -230,6 +246,7 @@ class Storage extends React.Component {
230
246
  visibleEntities,
231
247
  storageType,
232
248
  usageFilter,
249
+ nodesUptimeFilter,
233
250
  setUsageFilter,
234
251
  usageFilterOptions,
235
252
  } = this.props;
@@ -247,6 +264,16 @@ class Storage extends React.Component {
247
264
  value={filter}
248
265
  />
249
266
  </div>
267
+
268
+ <RadioButton value={storageType} onUpdate={this.onStorageTypeChange}>
269
+ <RadioButton.Option value={StorageTypes.groups}>
270
+ {StorageTypes.groups}
271
+ </RadioButton.Option>
272
+ <RadioButton.Option value={StorageTypes.nodes}>
273
+ {StorageTypes.nodes}
274
+ </RadioButton.Option>
275
+ </RadioButton>
276
+
250
277
  <RadioButton value={visibleEntities} onUpdate={this.onGroupVisibilityChange}>
251
278
  <RadioButton.Option value={VisibleEntities.Missing}>
252
279
  {VisibleEntitiesTitles[VisibleEntities.Missing]}
@@ -259,14 +286,9 @@ class Storage extends React.Component {
259
286
  </RadioButton.Option>
260
287
  </RadioButton>
261
288
 
262
- <RadioButton value={storageType} onUpdate={this.onStorageTypeChange}>
263
- <RadioButton.Option value={StorageTypes.groups}>
264
- {StorageTypes.groups}
265
- </RadioButton.Option>
266
- <RadioButton.Option value={StorageTypes.nodes}>
267
- {StorageTypes.nodes}
268
- </RadioButton.Option>
269
- </RadioButton>
289
+ {storageType === StorageTypes.nodes && (
290
+ <UptimeFilter value={nodesUptimeFilter} onChange={this.onUptimeFilterChange} />
291
+ )}
270
292
 
271
293
  {storageType === StorageTypes.groups && (
272
294
  <UsageFilter
@@ -314,6 +336,7 @@ function mapStateToProps(state) {
314
336
  type: storageType,
315
337
  filter,
316
338
  usageFilter,
339
+ nodesUptimeFilter,
317
340
  } = state.storage;
318
341
 
319
342
  return {
@@ -329,6 +352,7 @@ function mapStateToProps(state) {
329
352
  storageType,
330
353
  filter,
331
354
  usageFilter,
355
+ nodesUptimeFilter,
332
356
  usageFilterOptions: getUsageFilterOptions(state),
333
357
  };
334
358
  }
@@ -339,6 +363,7 @@ const mapDispatchToProps = {
339
363
  setStorageFilter,
340
364
  setUsageFilter,
341
365
  setVisibleEntities: setVisibleEntities,
366
+ setNodesUptimeFilter,
342
367
  getNodesList,
343
368
  setStorageType,
344
369
  setHeader,
@@ -3,9 +3,9 @@
3
3
  display: flex;
4
4
  overflow-x: auto;
5
5
  overflow-y: hidden;
6
- justify-content: center;
6
+ justify-content: left;
7
7
 
8
- min-width: 500px;
8
+ width: max-content;
9
9
  }
10
10
  &__pdisks-item {
11
11
  flex-grow: 1;
@@ -5,6 +5,7 @@ import DataTable, {Column, Settings, SortOrder} from '@yandex-cloud/react-data-t
5
5
  import {Popover, PopoverBehavior} from '@gravity-ui/uikit';
6
6
 
7
7
  import {VisibleEntities} from '../../../store/reducers/storage';
8
+ import {NodesUptimeFilterValues} from '../../../utils/nodes';
8
9
 
9
10
  import {EmptyFilter} from '../EmptyFilter/EmptyFilter';
10
11
  import Pdisk from '../Pdisk/Pdisk';
@@ -28,6 +29,7 @@ interface StorageNodesProps {
28
29
  nodes: any;
29
30
  tableSettings: Settings;
30
31
  visibleEntities: keyof typeof VisibleEntities;
32
+ nodesUptimeFilter: keyof typeof NodesUptimeFilterValues;
31
33
  onShowAll?: VoidFunction;
32
34
  }
33
35
 
@@ -61,7 +63,13 @@ function setSortOrder(visibleEntities: keyof typeof VisibleEntities): SortOrder
61
63
  }
62
64
  }
63
65
 
64
- function StorageNodes({data, tableSettings, visibleEntities, onShowAll}: StorageNodesProps) {
66
+ function StorageNodes({
67
+ data,
68
+ tableSettings,
69
+ visibleEntities,
70
+ onShowAll,
71
+ nodesUptimeFilter,
72
+ }: StorageNodesProps) {
65
73
  const allColumns: Column<any>[] = [
66
74
  {
67
75
  name: TableColumnsIds.NodeId,
@@ -124,23 +132,33 @@ function StorageNodes({data, tableSettings, visibleEntities, onShowAll}: Storage
124
132
 
125
133
  if (visibleEntities === VisibleEntities.Space) {
126
134
  columns = allColumns.filter((col) => col.name !== TableColumnsIds.Missing);
127
-
128
- return (
129
- <EmptyFilter
130
- title={i18n('empty.out_of_space')}
131
- showAll={i18n('show_all')}
132
- onShowAll={onShowAll}
133
- />
134
- );
135
135
  }
136
- if (visibleEntities === VisibleEntities.Missing) {
137
- return (
138
- <EmptyFilter
139
- title={i18n('empty.degraded')}
140
- showAll={i18n('show_all')}
141
- onShowAll={onShowAll}
142
- />
143
- );
136
+
137
+ if (!data.length) {
138
+ let message;
139
+
140
+ if (visibleEntities === VisibleEntities.Space) {
141
+ message = i18n('empty.out_of_space');
142
+ }
143
+
144
+ if (visibleEntities === VisibleEntities.Missing) {
145
+ message = i18n('empty.degraded');
146
+ }
147
+
148
+ if (nodesUptimeFilter === NodesUptimeFilterValues.SmallUptime) {
149
+ message = i18n('empty.small_uptime');
150
+ }
151
+
152
+ if (
153
+ visibleEntities !== VisibleEntities.All &&
154
+ nodesUptimeFilter !== NodesUptimeFilterValues.All
155
+ ) {
156
+ message = i18n('empty.several_filters');
157
+ }
158
+
159
+ if (message) {
160
+ return <EmptyFilter title={message} showAll={i18n('show_all')} onShowAll={onShowAll} />;
161
+ }
144
162
  }
145
163
 
146
164
  return data ? (
@@ -1,6 +1,8 @@
1
1
  {
2
- "empty.default": "No such nodes",
3
- "empty.out_of_space": "No nodes with out of space errors",
4
- "empty.degraded": "No degraded nodes",
5
- "show_all": "Show all nodes"
2
+ "empty.default": "No such nodes",
3
+ "empty.out_of_space": "No nodes with out of space errors",
4
+ "empty.degraded": "No degraded nodes",
5
+ "empty.small_uptime": "No nodes with uptime < 1h",
6
+ "empty.several_filters": "No nodes match current filters combination",
7
+ "show_all": "Show all nodes"
6
8
  }
@@ -1,6 +1,8 @@
1
1
  {
2
- "empty.default": "Нет узлов",
3
- "empty.out_of_space": "Нет узлов, в которых кончается место",
4
- "empty.degraded": "Нет деградировавших узлов",
5
- "show_all": "Показать все узлы"
2
+ "empty.default": "Нет узлов",
3
+ "empty.out_of_space": "Нет узлов, в которых кончается место",
4
+ "empty.degraded": "Нет деградировавших узлов",
5
+ "empty.small_uptime": "Нет узлов с uptime < 1h",
6
+ "empty.several_filters": "Нет узлов, подходящих под текущие фильтры",
7
+ "show_all": "Показать все узлы"
6
8
  }
@@ -1,4 +1,6 @@
1
1
  .usage-filter {
2
+ min-width: 100px;
3
+
2
4
  &__option {
3
5
  flex-grow: 1;
4
6
 
@@ -10,22 +12,25 @@
10
12
  }
11
13
 
12
14
  &-meta {
13
- padding: 0 5px;
14
15
  position: relative;
15
- border-radius: 3px;
16
+
17
+ padding: 0 5px;
18
+
16
19
  font-size: var(--yc-text-caption-2-font-size);
17
20
  line-height: var(--yc-text-caption-2-line-height);
21
+
22
+ border-radius: 3px;
18
23
  }
19
24
 
20
25
  &-bar {
21
26
  position: absolute;
22
- left: 0;
27
+ z-index: -1;
23
28
  top: 0;
24
29
  bottom: 0;
25
- z-index: -1;
30
+ left: 0;
26
31
 
27
- background-color: var(--yc-color-infographics-info-medium);
28
32
  border-radius: 3px;
33
+ background-color: var(--yc-color-infographics-info-medium);
29
34
  }
30
35
  }
31
36
  }
@@ -83,13 +83,7 @@ class Acl extends React.Component {
83
83
  return null;
84
84
  }
85
85
 
86
- return (
87
- <DataTable
88
- columns={this.COLUMNS}
89
- data={acl}
90
- settings={TABLE_SETTINGS}
91
- />
92
- );
86
+ return <DataTable columns={this.COLUMNS} data={acl} settings={TABLE_SETTINGS} />;
93
87
  };
94
88
 
95
89
  renderOwner = () => {
@@ -7,7 +7,7 @@ import qs from 'qs';
7
7
 
8
8
  import {Loader} from '@gravity-ui/uikit';
9
9
 
10
- import NodesViewer from '../../../../components/NodesViewer/NodesViewer';
10
+ import NodesViewer from '../../../NodesViewer/NodesViewer';
11
11
 
12
12
  import {backend} from '../../../../store';
13
13
  import {hideTooltip, showTooltip} from '../../../../store/reducers/tooltip';
@@ -1,13 +1,20 @@
1
- import {useEffect, useState} from 'react';
1
+ import {useCallback, useEffect, useState} from 'react';
2
2
  import {useDispatch} from 'react-redux';
3
3
  import block from 'bem-cn-lite';
4
4
 
5
5
  import DataTable, {Column} from '@yandex-cloud/react-data-table';
6
6
 
7
+ import { Loader } from '../../../../components/Loader';
8
+ import {prepareQueryError} from '../../../../utils/query';
7
9
  import {DEFAULT_TABLE_SETTINGS} from '../../../../utils/constants';
8
10
  import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
9
11
  import {Search} from '../../../../components/Search';
10
- import {getDescribe, selectConsumers} from '../../../../store/reducers/describe';
12
+ import {
13
+ getDescribe,
14
+ selectConsumers,
15
+ setCurrentDescribePath,
16
+ setDataWasNotLoaded,
17
+ } from '../../../../store/reducers/describe';
11
18
 
12
19
  import i18n from './i18n';
13
20
 
@@ -20,14 +27,25 @@ interface ConsumersProps {
20
27
  }
21
28
 
22
29
  export const Consumers = ({path}: ConsumersProps) => {
23
- const dispath = useDispatch();
30
+ const dispatch = useDispatch();
31
+
32
+ const fetchData = useCallback(
33
+ (isBackground: boolean) => {
34
+ if (!isBackground) {
35
+ dispatch(setDataWasNotLoaded());
36
+ }
37
+ dispatch(setCurrentDescribePath(path));
38
+ dispatch(getDescribe({path}));
39
+ },
24
40
 
25
- const fetchData = () => {
26
- dispath(getDescribe({path}));
27
- };
41
+ [path, dispatch],
42
+ );
43
+
44
+ const {autorefresh} = useTypedSelector((state) => state.schema);
28
45
 
29
- useAutofetcher(fetchData, [path]);
46
+ useAutofetcher(fetchData, [fetchData], autorefresh);
30
47
 
48
+ const {loading, wasLoaded, error} = useTypedSelector((state) => state.describe);
31
49
  const consumers = useTypedSelector((state) => selectConsumers(state, path));
32
50
 
33
51
  const [consumersToRender, setConsumersToRender] = useState(consumers);
@@ -59,8 +77,16 @@ export const Consumers = ({path}: ConsumersProps) => {
59
77
  },
60
78
  ];
61
79
 
80
+ if (loading && !wasLoaded) {
81
+ return <Loader size="m" />;
82
+ }
83
+
84
+ if (!loading && error) {
85
+ return <div className={b('message', 'error')}>{prepareQueryError(error)}</div>;
86
+ }
87
+
62
88
  if (consumers.length === 0) {
63
- return <div>{i18n('noConsumersMessage')}</div>;
89
+ return <div className={b('message')}>{i18n('noConsumersMessage')}</div>;
64
90
  }
65
91
 
66
92
  return (
@@ -13,14 +13,6 @@
13
13
  padding: 10px 20px 20px 0;
14
14
  }
15
15
 
16
- &__loader-container {
17
- display: flex;
18
- justify-content: center;
19
- align-items: center;
20
-
21
- height: 100%;
22
- }
23
-
24
16
  &__tree {
25
17
  @include json-tree-styles();
26
18
  }
@@ -5,7 +5,7 @@ import cn from 'bem-cn-lite';
5
5
  import JSONTree from 'react-json-inspector';
6
6
  import 'react-json-inspector/json-inspector.css';
7
7
 
8
- import {Loader} from '@gravity-ui/uikit';
8
+ import {Loader} from '../../../../components/Loader';
9
9
 
10
10
  import {prepareQueryError} from '../../../../utils/query';
11
11
  import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
@@ -51,11 +51,7 @@ const Describe = ({tenant}: IDescribeProps) => {
51
51
  useAutofetcher(fetchData, [fetchData], autorefresh);
52
52
 
53
53
  if (loading && !wasLoaded) {
54
- return (
55
- <div className={b('loader-container')}>
56
- <Loader size="m" />
57
- </div>
58
- );
54
+ return <Loader size="m" />;
59
55
  }
60
56
 
61
57
  if (error) {
@@ -5,13 +5,6 @@
5
5
 
6
6
  height: 100%;
7
7
 
8
- &__loader {
9
- display: flex;
10
- flex-grow: 1;
11
- justify-content: center;
12
- align-items: center;
13
- }
14
-
15
8
  &__header-wrapper {
16
9
  padding: 13px 20px 16px;
17
10