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
@@ -5,7 +5,9 @@ import {Link} from 'react-router-dom';
5
5
  import {useDispatch, useSelector} from 'react-redux';
6
6
  import {useLocation} from 'react-router';
7
7
 
8
- import {Loader, Switch, Tabs} from '@gravity-ui/uikit';
8
+ import {Switch, Tabs} from '@gravity-ui/uikit';
9
+
10
+ import {Loader} from '../../../components/Loader';
9
11
 
10
12
  //@ts-ignore
11
13
  import TopQueries from './TopQueries/TopQueries';
@@ -153,7 +155,7 @@ function Diagnostics(props: DiagnosticsProps) {
153
155
  return <Heatmap path={currentItem.Path} />;
154
156
  }
155
157
  case GeneralPagesIds.consumers: {
156
- return <Consumers path={currentItem.Path} />;
158
+ return <Consumers path={currentSchemaPath} />;
157
159
  }
158
160
  default: {
159
161
  return <div>No data...</div>;
@@ -196,11 +198,7 @@ function Diagnostics(props: DiagnosticsProps) {
196
198
  // After tabs are initially loaded it is no longer needed
197
199
  // Thus there is no also "loading" check as in other parts of the project
198
200
  if (!wasLoaded) {
199
- return (
200
- <div className={b('loader')}>
201
- <Loader size="l" />
202
- </div>
203
- );
201
+ return <Loader size="l" />;
204
202
  }
205
203
 
206
204
  return (
@@ -47,17 +47,23 @@ function prepareDateSizeValue(value) {
47
47
  }
48
48
 
49
49
  function stringToDataTableSortOrder(value) {
50
- return value && value.split(',').map((columnId) => ({
51
- columnId,
52
- order: DataTable.DESCENDING,
53
- }));
50
+ return (
51
+ value &&
52
+ value.split(',').map((columnId) => ({
53
+ columnId,
54
+ order: DataTable.DESCENDING,
55
+ }))
56
+ );
54
57
  }
55
58
 
56
59
  function stringToQuerySortOrder(value) {
57
- return value && value.split(',').map((columnId) => ({
58
- columnId,
59
- order: 'DESC',
60
- }));
60
+ return (
61
+ value &&
62
+ value.split(',').map((columnId) => ({
63
+ columnId,
64
+ order: 'DESC',
65
+ }))
66
+ );
61
67
  }
62
68
 
63
69
  function dataTableToStringSortOrder(value = []) {
@@ -85,11 +91,13 @@ function TopShards({
85
91
 
86
92
  if (autorefresh) {
87
93
  autofetcher.start();
88
- autofetcher.fetch(() => sendShardQuery({
89
- database: path,
90
- path: currentSchemaPath,
91
- sortOrder: stringToQuerySortOrder(sortOrder),
92
- }));
94
+ autofetcher.fetch(() =>
95
+ sendShardQuery({
96
+ database: path,
97
+ path: currentSchemaPath,
98
+ sortOrder: stringToQuerySortOrder(sortOrder),
99
+ }),
100
+ );
93
101
  }
94
102
 
95
103
  return () => {
@@ -54,11 +54,7 @@ function ObjectGeneral(props: ObjectGeneralProps) {
54
54
  if (!tenantName) {
55
55
  return null;
56
56
  }
57
- return (
58
- <div className={b()}>
59
- {renderTabContent()}
60
- </div>
61
- );
57
+ return <div className={b()}>{renderTabContent()}</div>;
62
58
  };
63
59
 
64
60
  return renderContent();
@@ -1,4 +1,4 @@
1
- import React, {useCallback, useEffect, useRef, useState} from 'react';
1
+ import React, {useEffect, useRef, useState} from 'react';
2
2
  import cn from 'bem-cn-lite';
3
3
  import MonacoEditor from 'react-monaco-editor';
4
4
  import {Loader, RadioButton} from '@gravity-ui/uikit';
@@ -58,7 +58,7 @@ function GraphRoot(props) {
58
58
  updateComponentTheme(theme);
59
59
  }, [theme]);
60
60
 
61
- const render = useCallback(() => {
61
+ const render = () => {
62
62
  if (version === explainVersions.v2) {
63
63
  paranoid.current = getTopology('graphRoot', data, opts, shapes);
64
64
  paranoid.current.render();
@@ -66,7 +66,7 @@ function GraphRoot(props) {
66
66
  paranoid.current = getCompactTopology('graphRoot', data, opts);
67
67
  paranoid.current.renderCompactTopology();
68
68
  }
69
- }, [data, opts, shapes, version]);
69
+ };
70
70
 
71
71
  useEffect(() => {
72
72
  render();
@@ -86,7 +86,7 @@ function GraphRoot(props) {
86
86
  graphRoot.innerHTML = '';
87
87
 
88
88
  render();
89
- }, [componentTheme, render]);
89
+ }, [componentTheme]);
90
90
 
91
91
  useEffect(() => {
92
92
  paranoid.current?.updateData?.(props.data);
@@ -73,10 +73,7 @@ function SaveQuery({savedQueries, onSaveQuery, saveButtonDisabled}) {
73
73
  </div>
74
74
  )}
75
75
  <div className={b('dialog-row')}>
76
- <label
77
- htmlFor="queryName"
78
- className={b('field-title', 'required')}
79
- >
76
+ <label htmlFor="queryName" className={b('field-title', 'required')}>
80
77
  Query name
81
78
  </label>
82
79
  <div className={b('control-wrapper')}>
@@ -44,9 +44,10 @@ const formatTableStatsItem = createInfoFormatter({
44
44
  defaultValueFormatter: formatNumber,
45
45
  });
46
46
 
47
- const formatTableStats = (fields) => Object.entries(fields)
48
- .map(([label, value]) => formatTableStatsItem(label, value))
49
- .filter(({value}) => Boolean(value));
47
+ const formatTableStats = (fields) =>
48
+ Object.entries(fields)
49
+ .map(([label, value]) => formatTableStatsItem(label, value))
50
+ .filter(({value}) => Boolean(value));
50
51
 
51
52
  class SchemaInfoViewer extends React.Component {
52
53
  static propTypes = {
@@ -60,17 +61,18 @@ class SchemaInfoViewer extends React.Component {
60
61
 
61
62
  return (
62
63
  <div className={b('item')}>
63
- <InfoViewer
64
- title={title}
65
- info={itemData}
66
- />
64
+ <InfoViewer title={title} info={itemData} />
67
65
  </div>
68
66
  );
69
67
  }
70
68
 
71
69
  renderContent(data) {
72
70
  const {PathDescription = {}} = data;
73
- const {TableStats = {}, TabletMetrics = {}, Table: {PartitionConfig = {}} = {}} = PathDescription;
71
+ const {
72
+ TableStats = {},
73
+ TabletMetrics = {},
74
+ Table: {PartitionConfig = {}} = {},
75
+ } = PathDescription;
74
76
  const {
75
77
  PartCount,
76
78
  RowCount,
@@ -127,33 +129,30 @@ class SchemaInfoViewer extends React.Component {
127
129
  ];
128
130
 
129
131
  const tabletMetricsInfo = Object.keys(TabletMetrics).map((key) =>
130
- formatTabletMetricsItem(key, TabletMetrics[key])
132
+ formatTabletMetricsItem(key, TabletMetrics[key]),
131
133
  );
132
134
 
133
135
  const partitionConfigInfo = [];
134
136
 
135
137
  if (Array.isArray(FollowerGroups) && FollowerGroups.length > 0) {
136
- partitionConfigInfo.push(...Object.keys(FollowerGroups[0]).map((key) =>
137
- formatFollowerGroupItem(key, FollowerGroups[0][key])
138
- ));
139
- } else if (FollowerCount !== undefined) {
140
138
  partitionConfigInfo.push(
141
- formatPartitionConfigItem('FollowerCount', FollowerCount)
139
+ ...Object.keys(FollowerGroups[0]).map((key) =>
140
+ formatFollowerGroupItem(key, FollowerGroups[0][key]),
141
+ ),
142
142
  );
143
+ } else if (FollowerCount !== undefined) {
144
+ partitionConfigInfo.push(formatPartitionConfigItem('FollowerCount', FollowerCount));
143
145
  } else if (CrossDataCenterFollowerCount !== undefined) {
144
146
  partitionConfigInfo.push(
145
- formatPartitionConfigItem('CrossDataCenterFollowerCount', CrossDataCenterFollowerCount)
147
+ formatPartitionConfigItem(
148
+ 'CrossDataCenterFollowerCount',
149
+ CrossDataCenterFollowerCount,
150
+ ),
146
151
  );
147
152
  }
148
153
 
149
- if ([
150
- tabletMetricsInfo,
151
- partitionConfigInfo,
152
- tableStatsInfo.flat(),
153
- ].flat().length === 0) {
154
- return (
155
- <div className={b('item')}>Empty</div>
156
- );
154
+ if ([tabletMetricsInfo, partitionConfigInfo, tableStatsInfo.flat()].flat().length === 0) {
155
+ return <div className={b('item')}>Empty</div>;
157
156
  }
158
157
 
159
158
  return (
@@ -179,11 +178,7 @@ class SchemaInfoViewer extends React.Component {
179
178
  const {data} = this.props;
180
179
 
181
180
  if (data) {
182
- return (
183
- <div className={b()}>
184
- {this.renderContent(data)}
185
- </div>
186
- );
181
+ return <div className={b()}>{this.renderContent(data)}</div>;
187
182
  } else {
188
183
  return <div className="error">no schema data</div>;
189
184
  }
@@ -14,7 +14,7 @@ export enum TenantInfoTabsIds {
14
14
  export enum TenantTabsGroups {
15
15
  info = 'info',
16
16
  general = 'general',
17
- generalTab = 'generalTab'
17
+ generalTab = 'generalTab',
18
18
  }
19
19
 
20
20
  export const TENANT_GENERAL_TABS = [
@@ -37,9 +37,9 @@ const bindActions = (
37
37
  ) => {
38
38
  const inputQuery = (tmpl: (path: string) => string) => () => {
39
39
  dispatch(changeUserInput({input: tmpl(path)}));
40
- dispatch(setTopLevelTab(TenantGeneralTabsIds.query))
40
+ dispatch(setTopLevelTab(TenantGeneralTabsIds.query));
41
41
  setActivePath(path);
42
- }
42
+ };
43
43
 
44
44
  return {
45
45
  createTable: inputQuery(createTableTemplate),
@@ -66,7 +66,7 @@ const bindActions = (
66
66
  },
67
67
  openPreview: () => {
68
68
  dispatch(setShowPreview(true));
69
- dispatch(setTopLevelTab(TenantGeneralTabsIds.query))
69
+ dispatch(setTopLevelTab(TenantGeneralTabsIds.query));
70
70
  setActivePath(path);
71
71
  },
72
72
  };
@@ -74,27 +74,18 @@ const bindActions = (
74
74
 
75
75
  type ActionsSet = ReturnType<Required<NavigationTreeProps>['getActions']>;
76
76
 
77
- export const getActions = (
78
- dispatch: Dispatch<any>,
79
- setActivePath: (path: string) => void,
80
- ) =>
77
+ export const getActions =
78
+ (dispatch: Dispatch<any>, setActivePath: (path: string) => void) =>
81
79
  (path: string, type: NavigationTreeNodeType) => {
82
80
  const actions = bindActions(path, dispatch, setActivePath);
83
81
  const copyItem = {text: 'Copy path', action: actions.copyPath};
84
82
 
85
83
  const DIR_SET: ActionsSet = [
86
- [
87
- copyItem,
88
- ],
89
- [
90
- {text: 'Create table...', action: actions.createTable},
91
- ],
84
+ [copyItem],
85
+ [{text: 'Create table...', action: actions.createTable}],
92
86
  ];
93
87
  const TABLE_SET: ActionsSet = [
94
- [
95
- {text: 'Open preview', action: actions.openPreview},
96
- copyItem,
97
- ],
88
+ [{text: 'Open preview', action: actions.openPreview}, copyItem],
98
89
  [
99
90
  {text: 'Alter table...', action: actions.alterTable},
100
91
  {text: 'Select query...', action: actions.selectQuery},
@@ -102,9 +93,7 @@ export const getActions = (
102
93
  ],
103
94
  ];
104
95
 
105
- const JUST_COPY: ActionsSet = [
106
- copyItem,
107
- ];
96
+ const JUST_COPY: ActionsSet = [copyItem];
108
97
 
109
98
  const EMPTY_SET: ActionsSet = [];
110
99
 
@@ -1,7 +1,11 @@
1
- import {createRequestActionTypes, createApiRequest} from '../utils';
2
1
  import {createSelector} from 'reselect';
2
+
3
3
  import '../../services/api';
4
4
  import {ALL} from '../../utils/constants';
5
+ import {createRequestActionTypes, createApiRequest} from '../utils';
6
+
7
+ import {filterByUptime} from './storage';
8
+ import {getNodesUptimeFilter} from './nodes';
5
9
 
6
10
  const FETCH_NODES_LIST = createRequestActionTypes('tenants', 'FETCH_NODES_LIST');
7
11
 
@@ -47,23 +51,38 @@ export function getNodesList() {
47
51
  });
48
52
  }
49
53
 
54
+ const filterByProblemsStatus = (nodes = [], problemFilter) => {
55
+ if (problemFilter === ALL) {
56
+ return nodes;
57
+ }
58
+
59
+ return nodes.filter(({Overall}) => {
60
+ return Overall && Overall !== 'Green';
61
+ });
62
+ };
63
+
64
+ export const filterNodesByStatusAndUptime = (nodes = [], problemFilter, uptimeFilter) => {
65
+ let result = filterByProblemsStatus(nodes, problemFilter);
66
+ result = filterByUptime(result, uptimeFilter);
67
+
68
+ return result;
69
+ };
70
+
50
71
  export const getFilteredNodes = createSelector(
51
- (state) => state.nodes.data?.Tenants,
52
- (state) => state.settings.problemFilter,
53
- (tenants, filter) => {
72
+ [
73
+ (state) => state.nodes.data?.Tenants,
74
+ (state) => state.settings.problemFilter,
75
+ getNodesUptimeFilter,
76
+ ],
77
+ (tenants, problemFilter, uptimeFilter) => {
54
78
  const nodes = tenants?.reduce((acc, item) => {
55
79
  if (Array.isArray(item.Nodes)) {
56
80
  return [...acc, ...item.Nodes.map((node) => ({...node, TenantName: item.Name}))];
57
81
  }
58
82
  return acc;
59
83
  }, []);
60
- if (filter === ALL) {
61
- return nodes;
62
- }
63
84
 
64
- return nodes?.filter(({Overall}) => {
65
- return Overall && Overall !== 'Green';
66
- });
85
+ return filterNodesByStatusAndUptime(nodes, problemFilter, uptimeFilter);
67
86
  },
68
87
  );
69
88
 
@@ -1,9 +1,19 @@
1
1
  import {createRequestActionTypes, createApiRequest} from '../utils';
2
2
  import '../../services/api';
3
+ import {NodesUptimeFilterValues} from '../../utils/nodes';
3
4
 
4
5
  const FETCH_NODES = createRequestActionTypes('nodes', 'FETCH_NODES');
5
6
 
6
- const nodes = function z(state = {loading: true, wasLoaded: false}, action) {
7
+ const CLEAR_NODES = 'nodes/CLEAR_NODES';
8
+ const SET_NODES_UPTIME_FILTER = 'nodes/SET_NODES_UPTIME_FILTER';
9
+
10
+ const initialState = {
11
+ loading: true,
12
+ wasLoaded: false,
13
+ nodesUptimeFilter: NodesUptimeFilterValues.All,
14
+ };
15
+
16
+ const nodes = (state = initialState, action) => {
7
17
  switch (action.type) {
8
18
  case FETCH_NODES.REQUEST: {
9
19
  return {
@@ -28,7 +38,7 @@ const nodes = function z(state = {loading: true, wasLoaded: false}, action) {
28
38
  loading: false,
29
39
  };
30
40
  }
31
- case 'CLEAR_NODES': {
41
+ case CLEAR_NODES: {
32
42
  return {
33
43
  ...state,
34
44
  loading: true,
@@ -38,6 +48,10 @@ const nodes = function z(state = {loading: true, wasLoaded: false}, action) {
38
48
  error: undefined,
39
49
  };
40
50
  }
51
+
52
+ case SET_NODES_UPTIME_FILTER: {
53
+ return {...state, nodesUptimeFilter: action.data};
54
+ }
41
55
  default:
42
56
  return state;
43
57
  }
@@ -50,6 +64,13 @@ export function getNodes(path) {
50
64
  });
51
65
  }
52
66
 
53
- export const clearNodes = () => ({type: 'CLEAR_NODES'});
67
+ export const clearNodes = () => ({type: CLEAR_NODES});
68
+
69
+ export const setNodesUptimeFilter = (value) => ({
70
+ type: SET_NODES_UPTIME_FILTER,
71
+ data: value,
72
+ });
73
+
74
+ export const getNodesUptimeFilter = (state) => state.nodes.nodesUptimeFilter;
54
75
 
55
76
  export default nodes;
@@ -1,7 +1,11 @@
1
- import {createRequestActionTypes, createApiRequest} from '../utils';
1
+ import {Reducer} from 'redux';
2
+
3
+ import {ISchemaAction, ISchemaData, ISchemaState} from '../../types/store/schema';
2
4
  import '../../services/api';
3
5
 
4
- const FETCH_SCHEMA = createRequestActionTypes('schema', 'FETCH_SCHEMA');
6
+ import {createRequestActionTypes, createApiRequest} from '../utils';
7
+
8
+ export const FETCH_SCHEMA = createRequestActionTypes('schema', 'FETCH_SCHEMA');
5
9
  const PRELOAD_SCHEMAS = 'schema/PRELOAD_SCHEMAS';
6
10
  const SET_SCHEMA = 'schema/SET_SCHEMA';
7
11
  const SET_SHOW_PREVIEW = 'schema/SET_SHOW_PREVIEW';
@@ -18,7 +22,7 @@ export const initialState = {
18
22
  showPreview: false,
19
23
  };
20
24
 
21
- const schema = (state = initialState, action) => {
25
+ const schema: Reducer<ISchemaState, ISchemaAction> = (state = initialState, action) => {
22
26
  switch (action.type) {
23
27
  case FETCH_SCHEMA.REQUEST: {
24
28
  return {
@@ -28,7 +32,11 @@ const schema = (state = initialState, action) => {
28
32
  }
29
33
  case FETCH_SCHEMA.SUCCESS: {
30
34
  const newData = JSON.parse(JSON.stringify(state.data));
31
- newData[action.data.Path] = action.data;
35
+
36
+ if (action.data.Path) {
37
+ newData[action.data.Path] = action.data;
38
+ }
39
+
32
40
  const currentSchema = state.currentSchemaPath
33
41
  ? newData[state.currentSchemaPath]
34
42
  : action.data;
@@ -100,49 +108,49 @@ const schema = (state = initialState, action) => {
100
108
  }
101
109
  };
102
110
 
103
- export function getSchema({path}) {
111
+ export function getSchema({path}: {path: string}) {
104
112
  return createApiRequest({
105
113
  request: window.api.getSchema({path}),
106
114
  actions: FETCH_SCHEMA,
107
115
  });
108
116
  }
109
117
 
110
- export function setCurrentSchemaPath(currentSchemaPath) {
118
+ export function setCurrentSchemaPath(currentSchemaPath: string) {
111
119
  return {
112
120
  type: SET_SCHEMA,
113
121
  data: currentSchemaPath,
114
- };
122
+ } as const;
115
123
  }
116
124
  export function enableAutorefresh() {
117
125
  return {
118
126
  type: ENABLE_AUTOREFRESH,
119
- };
127
+ } as const;
120
128
  }
121
129
  export function disableAutorefresh() {
122
130
  return {
123
131
  type: DISABLE_AUTOREFRESH,
124
- };
132
+ } as const;
125
133
  }
126
- export function setShowPreview(value) {
134
+ export function setShowPreview(value: boolean) {
127
135
  return {
128
136
  type: SET_SHOW_PREVIEW,
129
137
  data: value,
130
- };
138
+ } as const;
131
139
  }
132
140
 
133
141
  // only stores data for paths that are not in the store yet
134
142
  // existing paths are ignored
135
- export function preloadSchemas(data) {
143
+ export function preloadSchemas(data: ISchemaData) {
136
144
  return {
137
145
  type: PRELOAD_SCHEMAS,
138
146
  data,
139
- };
147
+ } as const;
140
148
  }
141
149
 
142
150
  export function resetLoadingState() {
143
151
  return {
144
152
  type: RESET_LOADING_STATE,
145
- };
153
+ } as const;
146
154
  }
147
155
 
148
156
  export default schema;
@@ -1,10 +1,14 @@
1
- import {createRequestActionTypes, createApiRequest} from '../utils';
2
- import '../../services/api';
3
1
  import _ from 'lodash';
4
2
  import {createSelector} from 'reselect';
5
- import {calcUptime} from '../../utils';
3
+
4
+ import {calcUptime, calcUptimeInSeconds} from '../../utils';
6
5
  import {getUsage} from '../../utils/storage';
6
+ import {NodesUptimeFilterValues} from '../../utils/nodes';
7
7
  import {getPDiskType} from '../../utils/pdisk';
8
+ import {HOUR_IN_SECONDS} from '../../utils/constants';
9
+ import '../../services/api';
10
+
11
+ import {createRequestActionTypes, createApiRequest} from '../utils';
8
12
 
9
13
  export const VisibleEntities = {
10
14
  All: 'All',
@@ -29,6 +33,7 @@ const SET_FILTER = 'storage/SET_FILTER';
29
33
  const SET_USAGE_FILTER = 'storage/SET_USAGE_FILTER';
30
34
  const SET_VISIBLE_GROUPS = 'storage/SET_VISIBLE_GROUPS';
31
35
  const SET_STORAGE_TYPE = 'storage/SET_STORAGE_TYPE';
36
+ const SET_NODES_UPTIME_FILTER = 'storage/SET_NODES_UPTIME_FILTER';
32
37
 
33
38
  const initialState = {
34
39
  loading: true,
@@ -36,6 +41,7 @@ const initialState = {
36
41
  filter: '',
37
42
  usageFilter: [],
38
43
  visible: VisibleEntities.Missing,
44
+ nodesUptimeFilter: NodesUptimeFilterValues.All,
39
45
  type: StorageTypes.groups,
40
46
  };
41
47
 
@@ -93,6 +99,13 @@ const storage = (state = initialState, action) => {
93
99
  error: undefined,
94
100
  };
95
101
  }
102
+
103
+ case SET_NODES_UPTIME_FILTER: {
104
+ return {
105
+ ...state,
106
+ nodesUptimeFilter: action.data,
107
+ };
108
+ }
96
109
  case SET_STORAGE_TYPE: {
97
110
  return {
98
111
  ...state,
@@ -149,6 +162,13 @@ export function setVisibleEntities(value) {
149
162
  };
150
163
  }
151
164
 
165
+ export function setNodesUptimeFilter(value) {
166
+ return {
167
+ type: SET_NODES_UPTIME_FILTER,
168
+ data: value,
169
+ };
170
+ }
171
+
152
172
  export const getStoragePools = (state) => state.storage.data?.StoragePools;
153
173
  export const getStoragePoolsGroupsCount = (state) => ({
154
174
  total: state.storage.data?.TotalGroups || 0,
@@ -162,6 +182,7 @@ export const getStorageNodesCount = (state) => ({
162
182
  export const getStorageFilter = (state) => state.storage.filter;
163
183
  export const getUsageFilter = (state) => state.storage.usageFilter;
164
184
  export const getVisibleEntities = (state) => state.storage.visible;
185
+ export const getNodesUptimeFilter = (state) => state.storage.nodesUptimeFilter;
165
186
  export const getStorageType = (state) => state.storage.type;
166
187
  export const getNodesObject = (state) =>
167
188
  _.reduce(
@@ -337,12 +358,32 @@ const filterByUsage = (entities, usage) => {
337
358
  });
338
359
  };
339
360
 
361
+ export const filterByUptime = (nodes = [], nodesUptimeFilter) => {
362
+ if (nodesUptimeFilter === NodesUptimeFilterValues.All) {
363
+ return nodes;
364
+ }
365
+ return nodes.filter(({StartTime}) => {
366
+ return !StartTime || calcUptimeInSeconds(StartTime) < HOUR_IN_SECONDS;
367
+ });
368
+ };
369
+
340
370
  export const getFilteredEntities = createSelector(
341
- [getStorageFilter, getUsageFilter, getStorageType, getVisibleEntitiesList],
342
- (textFilter, usageFilter, type, entities) => {
371
+ [
372
+ getStorageFilter,
373
+ getUsageFilter,
374
+ getStorageType,
375
+ getNodesUptimeFilter,
376
+ getVisibleEntitiesList,
377
+ ],
378
+ (textFilter, usageFilter, type, nodesUptimeFilter, entities) => {
343
379
  let result = entities;
344
380
  result = filterByText(result, type, textFilter);
345
381
  result = filterByUsage(result, usageFilter);
382
+
383
+ if (type === StorageTypes.nodes) {
384
+ result = filterByUptime(result, nodesUptimeFilter);
385
+ }
386
+
346
387
  return result;
347
388
  },
348
389
  );
@@ -0,0 +1,46 @@
1
+ import {
2
+ disableAutorefresh,
3
+ enableAutorefresh,
4
+ FETCH_SCHEMA,
5
+ preloadSchemas,
6
+ resetLoadingState,
7
+ setCurrentSchemaPath,
8
+ setShowPreview,
9
+ } from '../../store/reducers/schema';
10
+ import {ApiRequestAction} from '../../store/utils';
11
+ import {IResponseError} from '../api/error';
12
+ import {TEvDescribeSchemeResult} from '../api/schema';
13
+
14
+ export type ISchemaData = Record<string, TEvDescribeSchemeResult>;
15
+
16
+ export interface ISchemaState {
17
+ loading: boolean;
18
+ wasLoaded: boolean;
19
+ data: ISchemaData;
20
+ currentSchema?: TEvDescribeSchemeResult;
21
+ currentSchemaPath?: string;
22
+ autorefresh: boolean;
23
+ showPreview: boolean;
24
+ error?: IResponseError;
25
+ }
26
+
27
+ type ISchemaApiRequestAction = ApiRequestAction<
28
+ typeof FETCH_SCHEMA,
29
+ TEvDescribeSchemeResult,
30
+ IResponseError
31
+ >;
32
+
33
+ export type ISchemaAction =
34
+ | ISchemaApiRequestAction
35
+ | (
36
+ | ReturnType<typeof setCurrentSchemaPath>
37
+ | ReturnType<typeof enableAutorefresh>
38
+ | ReturnType<typeof disableAutorefresh>
39
+ | ReturnType<typeof setShowPreview>
40
+ | ReturnType<typeof preloadSchemas>
41
+ | ReturnType<typeof resetLoadingState>
42
+ );
43
+
44
+ export interface ISchemaRootStateSlice {
45
+ schema: ISchemaState;
46
+ }