ydb-embedded-ui 3.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/components/ClusterInfo/ClusterInfo.tsx +1 -1
  3. package/dist/components/InfoViewer/InfoViewer.tsx +1 -1
  4. package/dist/components/InfoViewer/schemaInfo/CDCStreamInfo.tsx +5 -2
  5. package/dist/components/InfoViewer/schemaInfo/PersQueueGroupInfo.tsx +6 -5
  6. package/dist/components/InfoViewer/schemaInfo/TableIndexInfo.tsx +5 -2
  7. package/dist/components/ProblemFilter/ProblemFilter.tsx +18 -0
  8. package/dist/components/ProblemFilter/index.ts +1 -0
  9. package/dist/components/UptimeFIlter/UptimeFilter.tsx +4 -3
  10. package/dist/containers/Nodes/Nodes.js +2 -2
  11. package/dist/containers/NodesViewer/NodesViewer.js +2 -2
  12. package/dist/containers/Pool/Pool.js +2 -2
  13. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +2 -3
  14. package/dist/containers/Tenant/Diagnostics/Network/Network.js +2 -2
  15. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +11 -9
  16. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +6 -3
  17. package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.scss +0 -4
  18. package/dist/containers/Tenant/Diagnostics/TopShards/{TopShards.js → TopShards.tsx} +95 -119
  19. package/dist/containers/Tenant/Diagnostics/TopShards/index.ts +1 -0
  20. package/dist/containers/Tenant/Schema/SchemaInfoViewer/SchemaInfoViewer.js +35 -22
  21. package/dist/containers/Tenant/Schema/SchemaInfoViewer/SchemaInfoViewer.scss +8 -0
  22. package/dist/containers/Tenant/Tenant.tsx +1 -1
  23. package/dist/containers/Tenant/utils/index.ts +8 -0
  24. package/dist/containers/Tenant/utils/schema.ts +45 -0
  25. package/dist/containers/Tenants/Tenants.js +2 -2
  26. package/dist/services/api.d.ts +3 -0
  27. package/dist/services/api.js +1 -1
  28. package/dist/store/reducers/{nodes.js → nodes.ts} +20 -14
  29. package/dist/store/reducers/{shardsWorkload.js → shardsWorkload.ts} +28 -13
  30. package/dist/store/reducers/{tooltip.js → tooltip.ts} +28 -11
  31. package/dist/types/api/nodes.ts +3 -3
  32. package/dist/types/api/schema.ts +1 -1
  33. package/dist/types/api/tenant.ts +131 -0
  34. package/dist/types/store/nodes.ts +32 -0
  35. package/dist/types/store/shardsWorkload.ts +19 -0
  36. package/dist/types/store/tooltip.ts +25 -0
  37. package/dist/utils/constants.ts +2 -0
  38. package/dist/utils/nodes.ts +4 -4
  39. package/dist/utils/tooltip.js +8 -6
  40. package/package.json +2 -2
  41. package/dist/components/ProblemFilter/ProblemFilter.js +0 -24
  42. package/dist/utils/actionsConstants.js +0 -4
@@ -1,27 +1,34 @@
1
1
  import {useState, useContext, useEffect, useMemo} from 'react';
2
+ import {useDispatch} from 'react-redux';
2
3
  import cn from 'bem-cn-lite';
3
- import {connect} from 'react-redux';
4
+
5
+ import DataTable, {Column, Settings, SortOrder} from '@yandex-cloud/react-data-table';
4
6
  import {Loader} from '@gravity-ui/uikit';
5
- import DataTable from '@yandex-cloud/react-data-table';
6
7
 
7
8
  import InternalLink from '../../../../components/InternalLink/InternalLink';
8
9
 
10
+ import HistoryContext from '../../../../contexts/HistoryContext';
11
+
9
12
  import routes, {createHref} from '../../../../routes';
13
+
10
14
  import {sendShardQuery, setShardQueryOptions} from '../../../../store/reducers/shardsWorkload';
11
15
  import {setCurrentSchemaPath, getSchema} from '../../../../store/reducers/schema';
12
- import {AutoFetcher} from '../../../../utils/autofetcher';
13
- import HistoryContext from '../../../../contexts/HistoryContext';
16
+
17
+ import type {EPathType} from '../../../../types/api/schema';
18
+
14
19
  import {DEFAULT_TABLE_SETTINGS} from '../../../../utils/constants';
15
- import {isColumnEntityType} from '../../utils/schema';
16
- import {prepareQueryError} from '../../../../utils/query';
20
+ import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
17
21
  import {i18n} from '../../../../utils/i18n';
22
+ import {prepareQueryError} from '../../../../utils/query';
23
+
24
+ import {isColumnEntityType} from '../../utils/schema';
18
25
 
19
26
  import './TopShards.scss';
20
27
 
21
28
  const b = cn('top-shards');
22
29
  const bLink = cn('yc-link');
23
30
 
24
- const TABLE_SETTINGS = {
31
+ const TABLE_SETTINGS: Settings = {
25
32
  ...DEFAULT_TABLE_SETTINGS,
26
33
  dynamicRender: false, // no more than 20 rows
27
34
  externalSort: true,
@@ -36,121 +43,108 @@ const tableColumnsNames = {
36
43
  Path: 'Path',
37
44
  };
38
45
 
39
- const autofetcher = new AutoFetcher();
40
-
41
- function prepareCPUWorkloadValue(value) {
42
- return `${(value * 100).toFixed(2)}%`;
46
+ function prepareCPUWorkloadValue(value: string) {
47
+ return `${(Number(value) * 100).toFixed(2)}%`;
43
48
  }
44
49
 
45
- function prepareDateSizeValue(value) {
50
+ function prepareDateSizeValue(value: number) {
46
51
  return new Intl.NumberFormat(i18n.lang).format(value);
47
52
  }
48
53
 
49
- function stringToDataTableSortOrder(value) {
50
- return (
51
- value &&
52
- value.split(',').map((columnId) => ({
53
- columnId,
54
- order: DataTable.DESCENDING,
55
- }))
56
- );
54
+ function stringToDataTableSortOrder(value: string): SortOrder[] | undefined {
55
+ return value
56
+ ? value.split(',').map((columnId) => ({
57
+ columnId,
58
+ order: DataTable.DESCENDING,
59
+ }))
60
+ : undefined;
57
61
  }
58
62
 
59
- function stringToQuerySortOrder(value) {
60
- return (
61
- value &&
62
- value.split(',').map((columnId) => ({
63
- columnId,
64
- order: 'DESC',
65
- }))
66
- );
63
+ function stringToQuerySortOrder(value: string) {
64
+ return value
65
+ ? value.split(',').map((columnId) => ({
66
+ columnId,
67
+ order: 'DESC',
68
+ }))
69
+ : undefined;
67
70
  }
68
71
 
69
- function dataTableToStringSortOrder(value = []) {
70
- return value.map(({columnId}) => columnId).join(',');
72
+ function dataTableToStringSortOrder(value: SortOrder | SortOrder[] = []) {
73
+ const sortOrders = Array.isArray(value) ? value : [value];
74
+ return sortOrders.map(({columnId}) => columnId).join(',');
71
75
  }
72
76
 
73
- function TopShards({
74
- sendShardQuery,
75
- currentSchemaPath,
76
- path,
77
- loading,
78
- data,
79
- error,
80
- setCurrentSchemaPath,
81
- getSchema,
82
- autorefresh,
83
- wasLoaded,
84
- setShardQueryOptions,
85
- type,
86
- }) {
87
- const [sortOrder, setSortOrder] = useState(tableColumnsNames.CPUCores);
77
+ interface TopShardsProps {
78
+ tenantPath: string;
79
+ type?: EPathType;
80
+ }
88
81
 
89
- useEffect(() => {
90
- autofetcher.stop();
82
+ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
83
+ const dispatch = useDispatch();
84
+
85
+ const {autorefresh, currentSchemaPath} = useTypedSelector((state) => state.schema);
86
+
87
+ const {
88
+ loading,
89
+ data: {result: data = undefined} = {},
90
+ error,
91
+ wasLoaded,
92
+ } = useTypedSelector((state) => state.shardsWorkload);
91
93
 
92
- if (autorefresh) {
93
- autofetcher.start();
94
- autofetcher.fetch(() =>
94
+ const [sortOrder, setSortOrder] = useState(tableColumnsNames.CPUCores);
95
+
96
+ useAutofetcher(
97
+ () => {
98
+ dispatch(
95
99
  sendShardQuery({
96
- database: path,
100
+ database: tenantPath,
97
101
  path: currentSchemaPath,
98
102
  sortOrder: stringToQuerySortOrder(sortOrder),
99
103
  }),
100
104
  );
101
- }
102
-
103
- return () => {
104
- autofetcher.stop();
105
- };
106
- }, [autorefresh, currentSchemaPath, path, sendShardQuery, sortOrder]);
105
+ },
106
+ [dispatch, currentSchemaPath, tenantPath, sortOrder],
107
+ autorefresh,
108
+ );
107
109
 
108
110
  // don't show loader for requests triggered by table sort, only for path change
109
111
  useEffect(() => {
110
- setShardQueryOptions({
111
- wasLoaded: false,
112
- data: undefined,
113
- });
114
- }, [currentSchemaPath, path, setShardQueryOptions]);
115
-
116
- useEffect(() => {
117
- sendShardQuery({
118
- database: path,
119
- path: currentSchemaPath,
120
- sortOrder: stringToQuerySortOrder(sortOrder),
121
- });
122
- }, [currentSchemaPath, path, sendShardQuery, sortOrder]);
112
+ dispatch(
113
+ setShardQueryOptions({
114
+ wasLoaded: false,
115
+ data: undefined,
116
+ }),
117
+ );
118
+ }, [dispatch, currentSchemaPath, tenantPath]);
123
119
 
124
120
  const history = useContext(HistoryContext);
125
121
 
126
- const onSchemaClick = (schemaPath) => {
127
- return () => {
128
- setCurrentSchemaPath(schemaPath);
129
- getSchema({path: schemaPath});
130
- history.go(0);
131
- };
132
- };
133
-
134
- const onSort = (newSortOrder) => {
122
+ const onSort = (newSortOrder?: SortOrder | SortOrder[]) => {
135
123
  // omit information about sort order to disable ASC order, only DESC makes sense for top shards
136
124
  // use a string (and not the DataTable default format) to prevent reference change,
137
125
  // which would cause an excess state change, to avoid repeating requests
138
126
  setSortOrder(dataTableToStringSortOrder(newSortOrder));
139
127
  };
140
128
 
141
- const tableColumns = useMemo(() => {
129
+ const tableColumns: Column<any>[] = useMemo(() => {
130
+ const onSchemaClick = (schemaPath: string) => {
131
+ return () => {
132
+ dispatch(setCurrentSchemaPath(schemaPath));
133
+ dispatch(getSchema({path: schemaPath}));
134
+ history.go(0);
135
+ };
136
+ };
137
+
142
138
  return [
143
139
  {
144
140
  name: tableColumnsNames.Path,
145
- // eslint-disable-next-line
146
- render: ({value}) => {
141
+ render: ({value: relativeNodePath}) => {
147
142
  return (
148
143
  <span
149
- // tenant name is substringed out in sql query but is needed here
150
- onClick={onSchemaClick(path + value)}
144
+ onClick={onSchemaClick(tenantPath + relativeNodePath)}
151
145
  className={bLink({view: 'normal'})}
152
146
  >
153
- {value}
147
+ {relativeNodePath as string}
154
148
  </span>
155
149
  );
156
150
  },
@@ -158,9 +152,8 @@ function TopShards({
158
152
  },
159
153
  {
160
154
  name: tableColumnsNames.CPUCores,
161
- // eslint-disable-next-line
162
155
  render: ({value}) => {
163
- return prepareCPUWorkloadValue(value);
156
+ return prepareCPUWorkloadValue(value as string);
164
157
  },
165
158
  align: DataTable.RIGHT,
166
159
  },
@@ -168,24 +161,23 @@ function TopShards({
168
161
  name: tableColumnsNames.DataSize,
169
162
  header: 'DataSize (B)',
170
163
  render: ({value}) => {
171
- return prepareDateSizeValue(value);
164
+ return prepareDateSizeValue(value as number);
172
165
  },
173
166
  align: DataTable.RIGHT,
174
167
  },
175
168
  {
176
169
  name: tableColumnsNames.TabletId,
177
- // eslint-disable-next-line
178
170
  render: ({value}) => {
179
171
  return (
180
172
  <InternalLink to={createHref(routes.tablet, {id: value})}>
181
- {value}
173
+ {value as string}
182
174
  </InternalLink>
183
175
  );
184
176
  },
185
177
  sortable: false,
186
178
  },
187
179
  ];
188
- }, []);
180
+ }, [dispatch, history, tenantPath]);
189
181
 
190
182
  const renderLoader = () => {
191
183
  return (
@@ -196,51 +188,35 @@ function TopShards({
196
188
  };
197
189
 
198
190
  const renderContent = () => {
199
- if (isColumnEntityType(type)) {
191
+ if (loading && !wasLoaded) {
192
+ return renderLoader();
193
+ }
194
+
195
+ if (!data || data.length === 0 || isColumnEntityType(type)) {
200
196
  return 'No data';
201
197
  }
198
+
202
199
  if (error && !error.isCancelled) {
203
200
  return prepareQueryError(error);
204
201
  }
205
202
 
206
- return data && data.length > 0 ? (
203
+ return (
207
204
  <div className={b('table')}>
208
205
  <DataTable
209
206
  columns={tableColumns}
210
207
  data={data}
211
208
  settings={TABLE_SETTINGS}
212
- className={b('table')}
213
209
  theme="yandex-cloud"
214
210
  onSort={onSort}
215
211
  sortOrder={stringToDataTableSortOrder(sortOrder)}
216
212
  />
217
213
  </div>
218
- ) : (
219
- data
220
214
  );
221
215
  };
222
216
 
223
- return loading && !wasLoaded ? renderLoader() : <div className={b()}>{renderContent()}</div>;
224
- }
225
-
226
- const mapStateToProps = (state) => {
227
- const {loading, data = {}, error, wasLoaded} = state.shardsWorkload;
228
- const {autorefresh} = state.schema;
229
- return {
230
- loading,
231
- data: data.result,
232
- error,
233
- currentSchemaPath: state.schema?.currentSchema?.Path,
234
- autorefresh,
235
- wasLoaded,
236
- };
237
- };
238
-
239
- const mapDispatchToProps = {
240
- sendShardQuery,
241
- setCurrentSchemaPath,
242
- getSchema,
243
- setShardQueryOptions,
217
+ return (
218
+ <div className={b()}>
219
+ {renderContent()}
220
+ </div>
221
+ );
244
222
  };
245
-
246
- export default connect(mapStateToProps, mapDispatchToProps)(TopShards);
@@ -0,0 +1 @@
1
+ export * from './TopShards';
@@ -1,12 +1,15 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import cn from 'bem-cn-lite';
4
- import './SchemaInfoViewer.scss';
5
4
 
6
5
  import {formatCPU, formatBytes, formatNumber, formatBps, formatDateTime} from '../../../../utils';
7
6
 
8
7
  import {InfoViewer, createInfoFormatter} from '../../../../components/InfoViewer';
9
8
 
9
+ import {getEntityName} from '../../utils';
10
+
11
+ import './SchemaInfoViewer.scss';
12
+
10
13
  const b = cn('schema-info-viewer');
11
14
 
12
15
  const formatTabletMetricsItem = createInfoFormatter({
@@ -68,6 +71,8 @@ class SchemaInfoViewer extends React.Component {
68
71
 
69
72
  renderContent(data) {
70
73
  const {PathDescription = {}} = data;
74
+ const entityName = getEntityName(PathDescription);
75
+
71
76
  const {
72
77
  TableStats = {},
73
78
  TabletMetrics = {},
@@ -99,13 +104,15 @@ class SchemaInfoViewer extends React.Component {
99
104
  } = TableStats;
100
105
  const {FollowerGroups, FollowerCount, CrossDataCenterFollowerCount} = PartitionConfig;
101
106
 
107
+ const generalTableInfo = formatTableStats({
108
+ PartCount,
109
+ RowCount,
110
+ DataSize,
111
+ IndexSize,
112
+ ...restTableStats,
113
+ });
114
+
102
115
  const tableStatsInfo = [
103
- formatTableStats({
104
- PartCount,
105
- RowCount,
106
- DataSize,
107
- IndexSize,
108
- }),
109
116
  formatTableStats({
110
117
  LastAccessTime,
111
118
  LastUpdateTime,
@@ -125,7 +132,6 @@ class SchemaInfoViewer extends React.Component {
125
132
  RangeReads,
126
133
  RangeReadRows,
127
134
  }),
128
- formatTableStats(restTableStats),
129
135
  ];
130
136
 
131
137
  const tabletMetricsInfo = Object.keys(TabletMetrics).map((key) =>
@@ -151,24 +157,30 @@ class SchemaInfoViewer extends React.Component {
151
157
  );
152
158
  }
153
159
 
154
- if ([tabletMetricsInfo, partitionConfigInfo, tableStatsInfo.flat()].flat().length === 0) {
155
- return <div className={b('item')}>Empty</div>;
160
+ if (
161
+ [generalTableInfo, tabletMetricsInfo, partitionConfigInfo, tableStatsInfo.flat()].flat()
162
+ .length === 0
163
+ ) {
164
+ return <div className={b('title')}>{entityName}</div>;
156
165
  }
157
166
 
158
167
  return (
159
- <div className={b('row')}>
160
- {tabletMetricsInfo.length > 0 || partitionConfigInfo.length > 0 ? (
168
+ <div>
169
+ <div>{this.renderItem(generalTableInfo, entityName)}</div>
170
+ <div className={b('row')}>
171
+ {tabletMetricsInfo.length > 0 || partitionConfigInfo.length > 0 ? (
172
+ <div className={b('col')}>
173
+ {this.renderItem(tabletMetricsInfo, 'Tablet Metrics')}
174
+ {this.renderItem(partitionConfigInfo, 'Partition Config')}
175
+ </div>
176
+ ) : null}
161
177
  <div className={b('col')}>
162
- {this.renderItem(tabletMetricsInfo, 'Tablet Metrics')}
163
- {this.renderItem(partitionConfigInfo, 'Partition Config')}
178
+ {tableStatsInfo.map((info, index) => (
179
+ <React.Fragment key={index}>
180
+ {this.renderItem(info, index === 0 ? 'Table Stats' : undefined)}
181
+ </React.Fragment>
182
+ ))}
164
183
  </div>
165
- ) : null}
166
- <div className={b('col')}>
167
- {tableStatsInfo.map((info, index) => (
168
- <React.Fragment key={index}>
169
- {this.renderItem(info, index === 0 ? 'Table Stats' : undefined)}
170
- </React.Fragment>
171
- ))}
172
184
  </div>
173
185
  </div>
174
186
  );
@@ -176,11 +188,12 @@ class SchemaInfoViewer extends React.Component {
176
188
 
177
189
  render() {
178
190
  const {data} = this.props;
191
+ const entityName = getEntityName(data?.PathDescription);
179
192
 
180
193
  if (data) {
181
194
  return <div className={b()}>{this.renderContent(data)}</div>;
182
195
  } else {
183
- return <div className="error">no schema data</div>;
196
+ return <div className="error">No {entityName} data</div>;
184
197
  }
185
198
  }
186
199
  }
@@ -26,4 +26,12 @@
26
26
  grid-template-columns: minmax(max-content, 280px);
27
27
  }
28
28
  }
29
+
30
+ &__title {
31
+ margin: 15px 0 10px;
32
+
33
+ font-size: var(--yc-text-body-2-font-size);
34
+ font-weight: 600;
35
+ line-height: var(--yc-text-body-2-line-height);
36
+ }
29
37
  }
@@ -90,7 +90,7 @@ function Tenant(props: TenantProps) {
90
90
 
91
91
  useEffect(() => {
92
92
  dispatch(disableAutorefresh());
93
- }, [currentSchemaPath, tenantName]);
93
+ }, [currentSchemaPath, tenantName, dispatch]);
94
94
 
95
95
  useEffect(() => {
96
96
  if (tenantName) {
@@ -0,0 +1,8 @@
1
+ import {TPathDescription} from '../../../types/api/schema';
2
+ import {mapPathTypeToEntityName} from './schema';
3
+
4
+ export const getEntityName = (pathDescription?: TPathDescription) => {
5
+ const {PathType, PathSubType} = pathDescription?.Self || {};
6
+
7
+ return mapPathTypeToEntityName(PathType, PathSubType);
8
+ };
@@ -1,5 +1,7 @@
1
1
  import type {NavigationTreeNodeType} from 'ydb-ui-components';
2
+
2
3
  import {EPathSubType, EPathType} from '../../../types/api/schema';
4
+ import {ETenantType} from '../../../types/api/tenant';
3
5
 
4
6
  // this file contains verbose mappings that are typed in a way that ensures
5
7
  // correctness when a new node type or a new path type is added
@@ -41,6 +43,49 @@ export const mapPathTypeToNavigationTreeType = (
41
43
 
42
44
  // ====================
43
45
 
46
+ const pathSubTypeToEntityName: Record<EPathSubType, string | undefined> = {
47
+ [EPathSubType.EPathSubTypeSyncIndexImplTable]: 'Secondary Index Table',
48
+ [EPathSubType.EPathSubTypeAsyncIndexImplTable]: 'Secondary Index Table',
49
+
50
+ [EPathSubType.EPathSubTypeStreamImpl]: undefined,
51
+ [EPathSubType.EPathSubTypeEmpty]: undefined,
52
+ };
53
+
54
+ const pathTypeToEntityName: Record<EPathType, string | undefined> = {
55
+ [EPathType.EPathTypeInvalid]: undefined,
56
+
57
+ [EPathType.EPathTypeSubDomain]: 'Database',
58
+ [EPathType.EPathTypeExtSubDomain]: 'Database',
59
+
60
+ [EPathType.EPathTypeDir]: 'Directory',
61
+ [EPathType.EPathTypeTable]: 'Table',
62
+ [EPathType.EPathTypeTableIndex]: 'Secondary Index',
63
+ [EPathType.EPathTypeColumnStore]: 'Tablestore',
64
+ [EPathType.EPathTypeColumnTable]: 'Columntable',
65
+ [EPathType.EPathTypeCdcStream]: 'Changefeed',
66
+ [EPathType.EPathTypePersQueueGroup]: 'Topic',
67
+ };
68
+
69
+ export const mapPathTypeToEntityName = (
70
+ type?: EPathType,
71
+ subType?: EPathSubType,
72
+ ): string | undefined =>
73
+ (subType && pathSubTypeToEntityName[subType]) || (type && pathTypeToEntityName[type]);
74
+
75
+ // ====================
76
+
77
+ const databaseTypeToDBName: Record<ETenantType, string | undefined> = {
78
+ [ETenantType.UnknownTenantType]: 'Database',
79
+ [ETenantType.Domain]: 'Cluster Root',
80
+ [ETenantType.Dedicated]: 'Dedicated Database',
81
+ [ETenantType.Shared]: 'Shared Database',
82
+ [ETenantType.Serverless]: 'Serverless Database',
83
+ };
84
+
85
+ export const mapDatabaseTypeToDBName = (type?: ETenantType) => type && databaseTypeToDBName[type];
86
+
87
+ // ====================
88
+
44
89
  const pathTypeToIsTable: Record<EPathType, boolean> = {
45
90
  [EPathType.EPathTypeTable]: true,
46
91
  [EPathType.EPathTypeColumnTable]: true,
@@ -10,7 +10,7 @@ import {Loader, TextInput, Button} from '@gravity-ui/uikit';
10
10
  import EntityStatus from '../../components/EntityStatus/EntityStatus';
11
11
  import PoolsGraph from '../../components/PoolsGraph/PoolsGraph';
12
12
  import TabletsStatistic from '../../components/TabletsStatistic/TabletsStatistic';
13
- import ProblemFilter, {problemFilterType} from '../../components/ProblemFilter/ProblemFilter';
13
+ import {ProblemFilter} from '../../components/ProblemFilter';
14
14
  import {Illustration} from '../../components/Illustration';
15
15
  import {AutoFetcher} from '../../utils/autofetcher';
16
16
 
@@ -50,7 +50,7 @@ class Tenants extends React.Component {
50
50
  searchQuery: PropTypes.string,
51
51
  handleSearchQuery: PropTypes.func,
52
52
  setHeader: PropTypes.func,
53
- filter: problemFilterType,
53
+ filter: PropTypes.string,
54
54
  changeFilter: PropTypes.func,
55
55
  cluster: PropTypes.object,
56
56
  singleClusterMode: PropTypes.bool,
@@ -45,6 +45,9 @@ interface Window {
45
45
  getHealthcheckInfo: (
46
46
  database: string,
47
47
  ) => Promise<import('../types/api/healthcheck').HealthCheckAPIResponse>;
48
+ getTenantInfo: (params: {
49
+ path: string;
50
+ }) => Promise<import('../types/api/tenant').TTenantInfo>;
48
51
  [method: string]: Function;
49
52
  };
50
53
  }
@@ -1,4 +1,4 @@
1
- import AxiosWrapper from '@yandex-cloud/axios-wrapper';
1
+ import AxiosWrapper from '@gravity-ui/axios-wrapper';
2
2
 
3
3
  import {backend as BACKEND} from '../store';
4
4
  import {StorageTypes} from '../store/reducers/storage';
@@ -1,8 +1,12 @@
1
- import {createRequestActionTypes, createApiRequest} from '../utils';
1
+ import type {Reducer} from 'redux';
2
+
2
3
  import '../../services/api';
3
4
  import {NodesUptimeFilterValues} from '../../utils/nodes';
5
+ import {INodesAction, INodesRootStateSlice, INodesState} from '../../types/store/nodes';
6
+
7
+ import {createRequestActionTypes, createApiRequest} from '../utils';
4
8
 
5
- const FETCH_NODES = createRequestActionTypes('nodes', 'FETCH_NODES');
9
+ export const FETCH_NODES = createRequestActionTypes('nodes', 'FETCH_NODES');
6
10
 
7
11
  const CLEAR_NODES = 'nodes/CLEAR_NODES';
8
12
  const SET_NODES_UPTIME_FILTER = 'nodes/SET_NODES_UPTIME_FILTER';
@@ -14,13 +18,12 @@ const initialState = {
14
18
  nodesUptimeFilter: NodesUptimeFilterValues.All,
15
19
  };
16
20
 
17
- const nodes = (state = initialState, action) => {
21
+ const nodes: Reducer<INodesState, INodesAction> = (state = initialState, action) => {
18
22
  switch (action.type) {
19
23
  case FETCH_NODES.REQUEST: {
20
24
  return {
21
25
  ...state,
22
26
  loading: true,
23
- requestTime: new Date().getTime(),
24
27
  };
25
28
  }
26
29
  case FETCH_NODES.SUCCESS: {
@@ -45,13 +48,15 @@ const nodes = (state = initialState, action) => {
45
48
  loading: true,
46
49
  data: undefined,
47
50
  wasLoaded: false,
48
- requestTime: new Date().getTime(),
49
51
  error: undefined,
50
52
  };
51
53
  }
52
54
 
53
55
  case SET_NODES_UPTIME_FILTER: {
54
- return {...state, nodesUptimeFilter: action.data};
56
+ return {
57
+ ...state,
58
+ nodesUptimeFilter: action.data,
59
+ };
55
60
  }
56
61
  case SET_DATA_WAS_NOT_LOADED: {
57
62
  return {
@@ -64,26 +69,27 @@ const nodes = (state = initialState, action) => {
64
69
  }
65
70
  };
66
71
 
67
- export function getNodes(path) {
72
+ export function getNodes(path: string) {
68
73
  return createApiRequest({
69
74
  request: window.api.getNodes(path),
70
75
  actions: FETCH_NODES,
71
76
  });
72
77
  }
73
78
 
74
- export const clearNodes = () => ({type: CLEAR_NODES});
79
+ export const clearNodes = () => ({type: CLEAR_NODES} as const);
75
80
 
76
- export const setNodesUptimeFilter = (value) => ({
77
- type: SET_NODES_UPTIME_FILTER,
78
- data: value,
79
- });
81
+ export const setNodesUptimeFilter = (value: NodesUptimeFilterValues) =>
82
+ ({
83
+ type: SET_NODES_UPTIME_FILTER,
84
+ data: value,
85
+ } as const);
80
86
 
81
87
  export const setDataWasNotLoaded = () => {
82
88
  return {
83
89
  type: SET_DATA_WAS_NOT_LOADED,
84
- };
90
+ } as const;
85
91
  };
86
92
 
87
- export const getNodesUptimeFilter = (state) => state.nodes.nodesUptimeFilter;
93
+ export const getNodesUptimeFilter = (state: INodesRootStateSlice) => state.nodes.nodesUptimeFilter;
88
94
 
89
95
  export default nodes;