ydb-embedded-ui 2.5.0 → 3.0.0

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.
Files changed (39) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/components/InfoViewer/InfoViewer.scss +3 -3
  3. package/dist/components/InfoViewer/schemaInfo/CDCStreamInfo.tsx +23 -9
  4. package/dist/containers/Storage/Pdisk/Pdisk.tsx +3 -9
  5. package/dist/containers/Storage/Pdisk/__tests__/colors.tsx +1 -1
  6. package/dist/containers/Storage/Storage.js +11 -1
  7. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +39 -32
  8. package/dist/containers/Tenant/Diagnostics/Compute/Compute.js +21 -13
  9. package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +22 -6
  10. package/dist/containers/Tenant/Diagnostics/Describe/Describe.tsx +40 -9
  11. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +15 -9
  12. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +1 -1
  13. package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.tsx +13 -5
  14. package/dist/containers/Tenant/Diagnostics/Network/Network.js +17 -4
  15. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +50 -16
  16. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +16 -2
  17. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.js +1 -0
  18. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +2 -2
  19. package/dist/containers/Tenant/utils/schema.ts +84 -0
  20. package/dist/services/api.d.ts +17 -11
  21. package/dist/store/reducers/describe.ts +56 -14
  22. package/dist/store/reducers/healthcheckInfo.ts +23 -8
  23. package/dist/store/reducers/network.js +22 -1
  24. package/dist/store/reducers/nodes.js +13 -0
  25. package/dist/store/reducers/schema.ts +84 -11
  26. package/dist/store/reducers/storage.js +13 -0
  27. package/dist/types/api/enums.ts +10 -0
  28. package/dist/types/api/nodes.ts +96 -0
  29. package/dist/types/api/pdisk.ts +48 -0
  30. package/dist/types/api/schema.ts +148 -9
  31. package/dist/types/api/storage.ts +3 -173
  32. package/dist/types/api/tablet.ts +97 -0
  33. package/dist/types/api/vdisk.ts +120 -0
  34. package/dist/types/store/describe.ts +8 -2
  35. package/dist/types/store/healthcheck.ts +12 -0
  36. package/dist/types/store/schema.ts +7 -1
  37. package/dist/utils/pdisk.ts +1 -1
  38. package/dist/utils/storage.ts +1 -1
  39. package/package.json +3 -2
@@ -10,6 +10,7 @@ import {
10
10
  getHealthcheckInfo,
11
11
  selectIssuesTreeById,
12
12
  selectIssuesTreesRoots,
13
+ setDataWasNotLoaded,
13
14
  } from '../../../../store/reducers/healthcheckInfo';
14
15
 
15
16
  import {Details} from './Details';
@@ -43,14 +44,21 @@ export const Healthcheck = (props: HealthcheckProps) => {
43
44
 
44
45
  const {autorefresh} = useTypedSelector((state) => state.schema);
45
46
 
46
- const fetchHealthcheck = useCallback(() => {
47
- dispatch(getHealthcheckInfo(tenant));
48
- }, [dispatch, tenant]);
47
+ const fetchHealthcheck = useCallback(
48
+ (isBackground = true) => {
49
+ if (!isBackground) {
50
+ dispatch(setDataWasNotLoaded());
51
+ }
52
+
53
+ dispatch(getHealthcheckInfo(tenant));
54
+ },
55
+ [dispatch, tenant],
56
+ );
49
57
 
50
58
  useAutofetcher(
51
- () => {
59
+ (isBackground) => {
52
60
  if (fetchData) {
53
- fetchHealthcheck();
61
+ fetchHealthcheck(isBackground);
54
62
  }
55
63
  },
56
64
  [fetchData, fetchHealthcheck],
@@ -12,7 +12,7 @@ import Icon from '../../../../components/Icon/Icon';
12
12
  import ProblemFilter, {problemFilterType} from '../../../../components/ProblemFilter/ProblemFilter';
13
13
  import {Illustration} from '../../../../components/Illustration';
14
14
 
15
- import {getNetworkInfo} from '../../../../store/reducers/network';
15
+ import {getNetworkInfo, setDataWasNotLoaded} from '../../../../store/reducers/network';
16
16
  import {hideTooltip, showTooltip} from '../../../../store/reducers/tooltip';
17
17
  import {ALL, PROBLEMS} from '../../../../utils/constants';
18
18
  import {changeFilter} from '../../../../store/reducers/settings';
@@ -26,6 +26,7 @@ const b = cn('network');
26
26
  class Network extends React.Component {
27
27
  static propTypes = {
28
28
  getNetworkInfo: PropTypes.func,
29
+ setDataWasNotLoaded: PropTypes.func,
29
30
  netWorkInfo: PropTypes.object,
30
31
  hideTooltip: PropTypes.func,
31
32
  showTooltip: PropTypes.func,
@@ -75,16 +76,27 @@ class Network extends React.Component {
75
76
  }
76
77
 
77
78
  componentDidUpdate(prevProps) {
78
- const {autorefresh, path} = this.props;
79
+ const {autorefresh, path, setDataWasNotLoaded, getNetworkInfo} = this.props;
79
80
 
80
- if (autorefresh && !prevProps.autorefresh) {
81
- getNetworkInfo(path);
81
+ const restartAutorefresh = () => {
82
+ this.autofetcher.stop();
82
83
  this.autofetcher.start();
83
84
  this.autofetcher.fetch(() => getNetworkInfo(path));
85
+ };
86
+
87
+ if (autorefresh && !prevProps.autorefresh) {
88
+ getNetworkInfo(path);
89
+ restartAutorefresh();
84
90
  }
85
91
  if (!autorefresh && prevProps.autorefresh) {
86
92
  this.autofetcher.stop();
87
93
  }
94
+
95
+ if (path !== prevProps.path) {
96
+ setDataWasNotLoaded();
97
+ getNetworkInfo(path);
98
+ restartAutorefresh();
99
+ }
88
100
  }
89
101
 
90
102
  componentWillUnmount() {
@@ -364,6 +376,7 @@ const mapDispatchToProps = {
364
376
  hideTooltip,
365
377
  showTooltip,
366
378
  changeFilter,
379
+ setDataWasNotLoaded,
367
380
  };
368
381
 
369
382
  export default connect(mapStateToProps, mapDispatchToProps)(Network);
@@ -1,5 +1,5 @@
1
- import {ReactNode, useMemo} from 'react';
2
- import {useDispatch, useSelector} from 'react-redux';
1
+ import {ReactNode, useCallback, useMemo} from 'react';
2
+ import {shallowEqual, useDispatch, useSelector} from 'react-redux';
3
3
  import cn from 'bem-cn-lite';
4
4
 
5
5
  import {Loader} from '@gravity-ui/uikit';
@@ -13,15 +13,24 @@ import {
13
13
  } from '../../../../components/InfoViewer/schemaInfo';
14
14
 
15
15
  import {EPathType, TColumnTableDescription} from '../../../../types/api/schema';
16
- import {isColumnEntityType, isTableType} from '../../utils/schema';
16
+ import {
17
+ isEntityWithMergedImplementation,
18
+ isColumnEntityType,
19
+ isTableType,
20
+ } from '../../utils/schema';
17
21
  //@ts-ignore
18
- import {getSchema, resetLoadingState} from '../../../../store/reducers/schema';
22
+ import {
23
+ getSchema,
24
+ getSchemaBatched,
25
+ resetLoadingState,
26
+ selectSchemaMergedChildrenPaths,
27
+ } from '../../../../store/reducers/schema';
19
28
  //@ts-ignore
20
29
  import {
21
30
  getOlapStats,
22
31
  resetLoadingState as resetOlapLoadingState,
23
32
  } from '../../../../store/reducers/olapStats';
24
- import {useAutofetcher} from '../../../../utils/hooks';
33
+ import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
25
34
 
26
35
  import './Overview.scss';
27
36
 
@@ -60,9 +69,7 @@ interface OverviewProps {
60
69
 
61
70
  const b = cn('kv-tenant-overview');
62
71
 
63
- function Overview(props: OverviewProps) {
64
- const {tenantName, type} = props;
65
-
72
+ function Overview({type, tenantName, className}: OverviewProps) {
66
73
  const dispatch = useDispatch();
67
74
 
68
75
  const {
@@ -78,14 +85,31 @@ function Overview(props: OverviewProps) {
78
85
 
79
86
  const loading = schemaLoading || olapStatsLoading;
80
87
 
81
- useAutofetcher(
82
- (isBackground) => {
88
+ const isEntityWithMergedImpl = isEntityWithMergedImplementation(type);
89
+
90
+ // There is a circular dependency here. Fetch data depends on children paths
91
+ // When data in store updated on fetch request,
92
+ // new object is set there, so source children array is updated
93
+ // This updates selector, the selector returns a new array, and data is fetched again
94
+ // To prevent it, shallowEqual, which compares array content, was added
95
+ const mergedChildrenPaths = useTypedSelector(
96
+ (state) => selectSchemaMergedChildrenPaths(state, currentSchemaPath, type),
97
+ shallowEqual,
98
+ );
99
+
100
+ const fetchData = useCallback(
101
+ (isBackground: boolean) => {
83
102
  if (!isBackground) {
84
103
  dispatch(resetLoadingState());
85
104
  }
86
105
 
87
106
  const schemaPath = currentSchemaPath || tenantName;
88
- dispatch(getSchema({path: schemaPath}));
107
+
108
+ if (!isEntityWithMergedImpl) {
109
+ dispatch(getSchema({path: schemaPath}));
110
+ } else if (mergedChildrenPaths) {
111
+ dispatch(getSchemaBatched([schemaPath, ...mergedChildrenPaths]));
112
+ }
89
113
 
90
114
  if (isTableType(type) && isColumnEntityType(type)) {
91
115
  if (!isBackground) {
@@ -94,10 +118,18 @@ function Overview(props: OverviewProps) {
94
118
  dispatch(getOlapStats({path: schemaPath}));
95
119
  }
96
120
  },
97
- [currentSchemaPath, dispatch, tenantName, type],
98
- autorefresh,
121
+ [
122
+ tenantName,
123
+ currentSchemaPath,
124
+ type,
125
+ isEntityWithMergedImpl,
126
+ mergedChildrenPaths,
127
+ dispatch,
128
+ ],
99
129
  );
100
130
 
131
+ useAutofetcher(fetchData, [fetchData], autorefresh);
132
+
101
133
  const tableSchema =
102
134
  currentItem?.PathDescription?.Table || currentItem?.PathDescription?.ColumnTableDescription;
103
135
 
@@ -128,7 +160,9 @@ function Overview(props: OverviewProps) {
128
160
  [EPathType.EPathTypeExtSubDomain]: undefined,
129
161
  [EPathType.EPathTypeColumnStore]: undefined,
130
162
  [EPathType.EPathTypeColumnTable]: undefined,
131
- [EPathType.EPathTypeCdcStream]: () => <CDCStreamInfo data={schemaData} />,
163
+ [EPathType.EPathTypeCdcStream]: () => (
164
+ <CDCStreamInfo data={schemaData} childrenPaths={mergedChildrenPaths} />
165
+ ),
132
166
  [EPathType.EPathTypePersQueueGroup]: () => <PersQueueGroupInfo data={schemaData} />,
133
167
  };
134
168
 
@@ -139,10 +173,10 @@ function Overview(props: OverviewProps) {
139
173
  );
140
174
  };
141
175
 
142
- return loading && !wasLoaded ? (
176
+ return (loading && !wasLoaded) || (isEntityWithMergedImpl && !mergedChildrenPaths) ? (
143
177
  renderLoader()
144
178
  ) : (
145
- <div className={props.className}>{renderContent()}</div>
179
+ <div className={className}>{renderContent()}</div>
146
180
  );
147
181
  }
148
182
 
@@ -53,6 +53,7 @@ class TenantOverview extends React.Component {
53
53
 
54
54
  componentDidMount() {
55
55
  const {tenantName, autorefresh, getTenantInfo} = this.props;
56
+ getTenantInfo({path: tenantName});
56
57
  this.autofetcher = new AutoFetcher();
57
58
  if (autorefresh) {
58
59
  this.autofetcher.start();
@@ -62,12 +63,25 @@ class TenantOverview extends React.Component {
62
63
 
63
64
  componentDidUpdate(prevProps) {
64
65
  const {autorefresh, tenantName, getTenantInfo} = this.props;
65
- if (autorefresh && !prevProps.autorefresh) {
66
- getTenantInfo({path: tenantName});
66
+
67
+ const restartAutorefresh = () => {
67
68
  this.autofetcher.stop();
68
69
  this.autofetcher.start();
69
70
  this.autofetcher.fetch(() => getTenantInfo({path: tenantName}));
71
+ };
72
+
73
+ if (prevProps.tenantName !== this.props.tenantName) {
74
+ getTenantInfo({path: tenantName});
75
+ if (autorefresh) {
76
+ restartAutorefresh();
77
+ }
70
78
  }
79
+
80
+ if (autorefresh && !prevProps.autorefresh) {
81
+ getTenantInfo({path: tenantName});
82
+ restartAutorefresh();
83
+ }
84
+
71
85
  if (!autorefresh && prevProps.autorefresh) {
72
86
  this.autofetcher.stop();
73
87
  }
@@ -90,6 +90,7 @@ class TopQueries extends React.Component {
90
90
  wasLoaded: false,
91
91
  data: undefined,
92
92
  });
93
+ this.getTopQueries();
93
94
  }
94
95
  }
95
96
 
@@ -6,7 +6,7 @@ import {NavigationTree} from 'ydb-ui-components';
6
6
  import {setCurrentSchemaPath, preloadSchemas} from '../../../../store/reducers/schema';
7
7
  import type {EPathType, TEvDescribeSchemeResult} from '../../../../types/api/schema';
8
8
 
9
- import {mapPathTypeToNavigationTreeType} from '../../utils/schema';
9
+ import {isChildlessPathType, mapPathTypeToNavigationTreeType} from '../../utils/schema';
10
10
  import {getActions} from '../../utils/schemaActions';
11
11
 
12
12
  interface SchemaTreeProps {
@@ -42,7 +42,7 @@ export function SchemaTree(props: SchemaTreeProps) {
42
42
  type: mapPathTypeToNavigationTreeType(PathType, PathSubType),
43
43
  // FIXME: should only be explicitly set to true for tables with indexes
44
44
  // at the moment of writing there is no property to determine this, fix later
45
- expandable: true,
45
+ expandable: !isChildlessPathType(PathType, PathSubType),
46
46
  };
47
47
  });
48
48
 
@@ -88,3 +88,87 @@ const pathTypeToIsColumn: Record<EPathType, boolean> = {
88
88
  };
89
89
 
90
90
  export const isColumnEntityType = (type?: EPathType) => (type && pathTypeToIsColumn[type]) ?? false;
91
+
92
+ // ====================
93
+
94
+ const pathTypeToIsDatabase: Record<EPathType, boolean> = {
95
+ [EPathType.EPathTypeSubDomain]: true,
96
+ [EPathType.EPathTypeExtSubDomain]: true,
97
+
98
+ [EPathType.EPathTypeInvalid]: false,
99
+ [EPathType.EPathTypeDir]: false,
100
+ [EPathType.EPathTypeColumnStore]: false,
101
+ [EPathType.EPathTypeColumnTable]: false,
102
+ [EPathType.EPathTypeTable]: false,
103
+ [EPathType.EPathTypeTableIndex]: false,
104
+ [EPathType.EPathTypeCdcStream]: false,
105
+ [EPathType.EPathTypePersQueueGroup]: false,
106
+ };
107
+
108
+ export const isDatabaseEntityType = (type?: EPathType) =>
109
+ (type && pathTypeToIsDatabase[type]) ?? false;
110
+
111
+ // ====================
112
+
113
+ const pathTypeToIsCdcStream: Record<EPathType, boolean> = {
114
+ [EPathType.EPathTypeCdcStream]: true,
115
+
116
+ [EPathType.EPathTypeInvalid]: false,
117
+ [EPathType.EPathTypeColumnStore]: false,
118
+ [EPathType.EPathTypeColumnTable]: false,
119
+ [EPathType.EPathTypeDir]: false,
120
+ [EPathType.EPathTypeTable]: false,
121
+ [EPathType.EPathTypeSubDomain]: false,
122
+ [EPathType.EPathTypeTableIndex]: false,
123
+ [EPathType.EPathTypeExtSubDomain]: false,
124
+ [EPathType.EPathTypePersQueueGroup]: false,
125
+ };
126
+
127
+ export const isCdcStreamEntityType = (type?: EPathType) =>
128
+ (type && pathTypeToIsCdcStream[type]) ?? false;
129
+
130
+ // ====================
131
+
132
+ const pathTypeToEntityWithMergedImplementation: Record<EPathType, boolean> = {
133
+ [EPathType.EPathTypeCdcStream]: true,
134
+
135
+ [EPathType.EPathTypePersQueueGroup]: false,
136
+ [EPathType.EPathTypeInvalid]: false,
137
+ [EPathType.EPathTypeColumnStore]: false,
138
+ [EPathType.EPathTypeColumnTable]: false,
139
+ [EPathType.EPathTypeDir]: false,
140
+ [EPathType.EPathTypeTable]: false,
141
+ [EPathType.EPathTypeSubDomain]: false,
142
+ [EPathType.EPathTypeTableIndex]: false,
143
+ [EPathType.EPathTypeExtSubDomain]: false,
144
+ };
145
+
146
+ export const isEntityWithMergedImplementation = (type?: EPathType) =>
147
+ (type && pathTypeToEntityWithMergedImplementation[type]) ?? false;
148
+
149
+ // ====================
150
+
151
+ const pathSubTypeToChildless: Record<EPathSubType, boolean> = {
152
+ [EPathSubType.EPathSubTypeSyncIndexImplTable]: true,
153
+ [EPathSubType.EPathSubTypeAsyncIndexImplTable]: true,
154
+
155
+ [EPathSubType.EPathSubTypeStreamImpl]: false,
156
+ [EPathSubType.EPathSubTypeEmpty]: false,
157
+ };
158
+
159
+ const pathTypeToChildless: Record<EPathType, boolean> = {
160
+ [EPathType.EPathTypeCdcStream]: true,
161
+ [EPathType.EPathTypePersQueueGroup]: true,
162
+
163
+ [EPathType.EPathTypeInvalid]: false,
164
+ [EPathType.EPathTypeColumnStore]: false,
165
+ [EPathType.EPathTypeColumnTable]: false,
166
+ [EPathType.EPathTypeDir]: false,
167
+ [EPathType.EPathTypeTable]: false,
168
+ [EPathType.EPathTypeSubDomain]: false,
169
+ [EPathType.EPathTypeTableIndex]: false,
170
+ [EPathType.EPathTypeExtSubDomain]: false,
171
+ };
172
+
173
+ export const isChildlessPathType = (type?: EPathType, subType?: EPathSubType) =>
174
+ ((subType && pathSubTypeToChildless[subType]) || (type && pathTypeToChildless[type])) ?? false;
@@ -8,25 +8,29 @@ interface Window {
8
8
  params: {path: string},
9
9
  axiosOptions?: AxiosOptions,
10
10
  ) => Promise<import('../types/api/schema').TEvDescribeSchemeResult>;
11
+ getDescribe: (
12
+ params: {path: string},
13
+ axiosOptions?: AxiosOptions,
14
+ ) => Promise<import('../types/api/schema').TEvDescribeSchemeResult>;
11
15
  getStorageInfo: (
12
16
  params: {
13
- tenant: string,
14
- filter: string,
15
- nodeId: string,
16
- type: 'Groups' | 'Nodes',
17
+ tenant: string;
18
+ filter: string;
19
+ nodeId: string;
20
+ type: 'Groups' | 'Nodes';
17
21
  },
18
22
  axiosOptions?: AxiosOptions,
19
23
  ) => Promise<import('../types/api/storage').TStorageInfo>;
20
24
  sendQuery: <
21
25
  Action extends import('../types/api/query').Actions,
22
- Schema extends import('../types/api/query').Schemas = undefined
26
+ Schema extends import('../types/api/query').Schemas = undefined,
23
27
  >(
24
28
  params: {
25
- query?: string,
26
- database?: string,
27
- action?: Action,
28
- stats?: string,
29
- schema?: Schema,
29
+ query?: string;
30
+ database?: string;
31
+ action?: Action;
32
+ stats?: string;
33
+ schema?: Schema;
30
34
  },
31
35
  axiosOptions?: AxiosOptions,
32
36
  ) => Promise<import('../types/api/query').QueryAPIResponse<Action, Schema>>;
@@ -38,7 +42,9 @@ interface Window {
38
42
  query: string,
39
43
  database: string,
40
44
  ) => Promise<import('../types/api/query').QueryAPIExplainResponse<'explain-ast'>>;
41
- getHealthcheckInfo: (database: string) => Promise<import('../types/api/healthcheck').HealthCheckAPIResponse>,
45
+ getHealthcheckInfo: (
46
+ database: string,
47
+ ) => Promise<import('../types/api/healthcheck').HealthCheckAPIResponse>;
42
48
  [method: string]: Function;
43
49
  };
44
50
  }
@@ -3,7 +3,13 @@ import {Reducer} from 'redux';
3
3
 
4
4
  import '../../services/api';
5
5
  import {IConsumer} from '../../types/api/consumers';
6
- import {IDescribeRootStateSlice, IDescribeState, IDescribeAction} from '../../types/store/describe';
6
+ import {
7
+ IDescribeRootStateSlice,
8
+ IDescribeState,
9
+ IDescribeAction,
10
+ IDescribeHandledResponse,
11
+ IDescribeData,
12
+ } from '../../types/store/describe';
7
13
  import {createRequestActionTypes, createApiRequest} from '../utils';
8
14
 
9
15
  export const FETCH_DESCRIBE = createRequestActionTypes('describe', 'FETCH_DESCRIBE');
@@ -27,16 +33,8 @@ const describe: Reducer<IDescribeState, IDescribeAction> = (state = initialState
27
33
  };
28
34
  }
29
35
  case FETCH_DESCRIBE.SUCCESS: {
30
- const data = action.data;
31
-
32
- const isCurrentDescribePath = data.Path === state.currentDescribePath;
33
-
34
- let newData = state.data;
35
-
36
- if (data.Path) {
37
- newData = JSON.parse(JSON.stringify(state.data));
38
- newData[data.Path] = data;
39
- }
36
+ const isCurrentDescribePath = action.data.path === state.currentDescribePath;
37
+ const newData = {...state.data, ...action.data.data};
40
38
 
41
39
  if (!isCurrentDescribePath) {
42
40
  return {
@@ -48,7 +46,7 @@ const describe: Reducer<IDescribeState, IDescribeAction> = (state = initialState
48
46
  return {
49
47
  ...state,
50
48
  data: newData,
51
- currentDescribe: data,
49
+ currentDescribe: action.data.currentDescribe,
52
50
  loading: false,
53
51
  wasLoaded: true,
54
52
  error: undefined,
@@ -97,7 +95,7 @@ export const setDataWasNotLoaded = () => {
97
95
  };
98
96
 
99
97
  // Consumers selectors
100
- const selectConsumersNames = (state: IDescribeRootStateSlice, path: string | undefined) =>
98
+ const selectConsumersNames = (state: IDescribeRootStateSlice, path?: string) =>
101
99
  path
102
100
  ? state.describe.data[path]?.PathDescription?.PersQueueGroup?.PQTabletConfig?.ReadRules
103
101
  : undefined;
@@ -106,9 +104,53 @@ export const selectConsumers: Selector<IDescribeRootStateSlice, IConsumer[], [st
106
104
  createSelector(selectConsumersNames, (names = []) => names.map((name) => ({name})));
107
105
 
108
106
  export function getDescribe({path}: {path: string}) {
107
+ const request = window.api.getDescribe({path});
108
+ return createApiRequest({
109
+ request,
110
+ actions: FETCH_DESCRIBE,
111
+ dataHandler: (data): IDescribeHandledResponse => {
112
+ const dataPath = data.Path;
113
+ const currentDescribe: IDescribeData = {};
114
+ const newData: IDescribeData = {};
115
+
116
+ if (dataPath) {
117
+ currentDescribe[dataPath] = data;
118
+ newData[dataPath] = data;
119
+ }
120
+
121
+ return {
122
+ path: dataPath,
123
+ currentDescribe,
124
+ data: newData,
125
+ };
126
+ },
127
+ });
128
+ }
129
+
130
+ export function getDescribeBatched(paths: string[]) {
131
+ const requestsArray = paths.map((p) => window.api.getDescribe({path: p}));
132
+
133
+ const request = Promise.all(requestsArray);
109
134
  return createApiRequest({
110
- request: window.api.getDescribe({path}),
135
+ request,
111
136
  actions: FETCH_DESCRIBE,
137
+ dataHandler: (data): IDescribeHandledResponse => {
138
+ const currentDescribe: IDescribeData = {};
139
+ const newData: IDescribeData = {};
140
+
141
+ data.forEach((dataItem) => {
142
+ if (dataItem.Path) {
143
+ newData[dataItem.Path] = dataItem;
144
+ currentDescribe[dataItem.Path] = dataItem;
145
+ }
146
+ });
147
+
148
+ return {
149
+ path: data[0].Path,
150
+ currentDescribe,
151
+ data: newData,
152
+ };
153
+ },
112
154
  });
113
155
  }
114
156
 
@@ -9,21 +9,23 @@ import {
9
9
  IHealthcheckInfoState,
10
10
  IHealthcheckInfoRootStateSlice,
11
11
  IIssuesTree,
12
+ IHealthCheckInfoAction,
12
13
  } from '../../types/store/healthcheck';
13
- import {HealthCheckAPIResponse, IssueLog, StatusFlag} from '../../types/api/healthcheck';
14
- import {IResponseError} from '../../types/api/error';
14
+ import {IssueLog, StatusFlag} from '../../types/api/healthcheck';
15
15
 
16
16
  import '../../services/api';
17
- import {createRequestActionTypes, createApiRequest, ApiRequestAction} from '../utils';
17
+ import {createRequestActionTypes, createApiRequest} from '../utils';
18
18
 
19
- const FETCH_HEALTHCHECK = createRequestActionTypes('cluster', 'FETCH_HEALTHCHECK');
19
+ export const FETCH_HEALTHCHECK = createRequestActionTypes('cluster', 'FETCH_HEALTHCHECK');
20
+
21
+ const SET_DATA_WAS_NOT_LOADED = 'healthcheckInfo/SET_DATA_WAS_NOT_LOADED';
20
22
 
21
23
  const initialState = {loading: false, wasLoaded: false};
22
24
 
23
- const healthcheckInfo: Reducer<
24
- IHealthcheckInfoState,
25
- ApiRequestAction<typeof FETCH_HEALTHCHECK, HealthCheckAPIResponse, IResponseError>
26
- > = function (state = initialState, action) {
25
+ const healthcheckInfo: Reducer<IHealthcheckInfoState, IHealthCheckInfoAction> = function (
26
+ state = initialState,
27
+ action,
28
+ ) {
27
29
  switch (action.type) {
28
30
  case FETCH_HEALTHCHECK.REQUEST: {
29
31
  return {
@@ -49,6 +51,13 @@ const healthcheckInfo: Reducer<
49
51
  loading: false,
50
52
  };
51
53
  }
54
+
55
+ case SET_DATA_WAS_NOT_LOADED: {
56
+ return {
57
+ ...state,
58
+ wasLoaded: false,
59
+ };
60
+ }
52
61
  default:
53
62
  return state;
54
63
  }
@@ -127,4 +136,10 @@ export function getHealthcheckInfo(database: string) {
127
136
  });
128
137
  }
129
138
 
139
+ export const setDataWasNotLoaded = () => {
140
+ return {
141
+ type: SET_DATA_WAS_NOT_LOADED,
142
+ } as const;
143
+ };
144
+
130
145
  export default healthcheckInfo;
@@ -6,7 +6,15 @@ const FETCH_ALL_NODES_NETWORK = createRequestActionTypes(
6
6
  'FETCH_ALL_NODES_NETWORK',
7
7
  );
8
8
 
9
- const network = (state = {data: {}, loading: true, wasLoaded: false}, action) => {
9
+ const SET_DATA_WAS_NOT_LOADED = 'network/SET_DATA_WAS_NOT_LOADED';
10
+
11
+ const initialState = {
12
+ data: {},
13
+ loading: false,
14
+ wasLoaded: false,
15
+ };
16
+
17
+ const network = (state = initialState, action) => {
10
18
  switch (action.type) {
11
19
  case FETCH_ALL_NODES_NETWORK.REQUEST: {
12
20
  return {
@@ -30,11 +38,24 @@ const network = (state = {data: {}, loading: true, wasLoaded: false}, action) =>
30
38
  loading: false,
31
39
  };
32
40
  }
41
+
42
+ case SET_DATA_WAS_NOT_LOADED: {
43
+ return {
44
+ ...state,
45
+ wasLoaded: false,
46
+ };
47
+ }
33
48
  default:
34
49
  return state;
35
50
  }
36
51
  };
37
52
 
53
+ export const setDataWasNotLoaded = () => {
54
+ return {
55
+ type: SET_DATA_WAS_NOT_LOADED,
56
+ };
57
+ };
58
+
38
59
  export const getNetworkInfo = (tenant) => {
39
60
  return createApiRequest({
40
61
  request: window.api.getNetwork(tenant),
@@ -6,6 +6,7 @@ const FETCH_NODES = createRequestActionTypes('nodes', 'FETCH_NODES');
6
6
 
7
7
  const CLEAR_NODES = 'nodes/CLEAR_NODES';
8
8
  const SET_NODES_UPTIME_FILTER = 'nodes/SET_NODES_UPTIME_FILTER';
9
+ const SET_DATA_WAS_NOT_LOADED = 'nodes/SET_DATA_WAS_NOT_LOADED';
9
10
 
10
11
  const initialState = {
11
12
  loading: true,
@@ -52,6 +53,12 @@ const nodes = (state = initialState, action) => {
52
53
  case SET_NODES_UPTIME_FILTER: {
53
54
  return {...state, nodesUptimeFilter: action.data};
54
55
  }
56
+ case SET_DATA_WAS_NOT_LOADED: {
57
+ return {
58
+ ...state,
59
+ wasLoaded: false,
60
+ };
61
+ }
55
62
  default:
56
63
  return state;
57
64
  }
@@ -71,6 +78,12 @@ export const setNodesUptimeFilter = (value) => ({
71
78
  data: value,
72
79
  });
73
80
 
81
+ export const setDataWasNotLoaded = () => {
82
+ return {
83
+ type: SET_DATA_WAS_NOT_LOADED,
84
+ };
85
+ };
86
+
74
87
  export const getNodesUptimeFilter = (state) => state.nodes.nodesUptimeFilter;
75
88
 
76
89
  export default nodes;