ydb-embedded-ui 2.4.4 → 2.5.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 (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
+ }