ydb-embedded-ui 2.4.3 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. package/CHANGELOG.md +33 -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 +87 -0
  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 +16 -30
  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/Schema/SchemaTree/SchemaTree.tsx +2 -7
  41. package/dist/containers/Tenant/Tenant.tsx +8 -5
  42. package/dist/containers/Tenant/TenantPages.tsx +1 -1
  43. package/dist/containers/Tenant/utils/schemaActions.ts +9 -20
  44. package/dist/services/api.js +14 -5
  45. package/dist/store/reducers/clusterNodes.js +29 -10
  46. package/dist/store/reducers/describe.ts +60 -30
  47. package/dist/store/reducers/nodes.js +24 -3
  48. package/dist/store/reducers/{schema.js → schema.ts} +22 -14
  49. package/dist/store/reducers/storage.js +46 -5
  50. package/dist/types/api/error.ts +4 -2
  51. package/dist/types/store/describe.ts +21 -1
  52. package/dist/types/store/schema.ts +46 -0
  53. package/dist/utils/index.js +6 -2
  54. package/dist/utils/nodes.ts +9 -0
  55. package/package.json +1 -1
  56. package/dist/containers/Tenant/Diagnostics/Describe/Describe.js +0 -130
@@ -0,0 +1,87 @@
1
+ import {useCallback} from 'react';
2
+ import {useDispatch} from 'react-redux';
3
+ import cn from 'bem-cn-lite';
4
+ // @ts-ignore
5
+ import JSONTree from 'react-json-inspector';
6
+ import 'react-json-inspector/json-inspector.css';
7
+
8
+ import {Loader} from '../../../../components/Loader';
9
+
10
+ import {prepareQueryError} from '../../../../utils/query';
11
+ import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
12
+ import {
13
+ getDescribe,
14
+ setDataWasNotLoaded,
15
+ setCurrentDescribePath,
16
+ } from '../../../../store/reducers/describe';
17
+
18
+ import './Describe.scss';
19
+
20
+ const b = cn('kv-describe');
21
+
22
+ const expandMap = new Map();
23
+
24
+ interface IDescribeProps {
25
+ tenant: string;
26
+ }
27
+
28
+ const Describe = ({tenant}: IDescribeProps) => {
29
+ const dispatch = useDispatch();
30
+
31
+ const {currentDescribe, error, loading, wasLoaded} = useTypedSelector(
32
+ (state) => state.describe,
33
+ );
34
+
35
+ const {autorefresh, currentSchemaPath} = useTypedSelector((state) => state.schema);
36
+
37
+ const fetchData = useCallback(
38
+ (isBackground: boolean) => {
39
+ if (!isBackground) {
40
+ dispatch(setDataWasNotLoaded());
41
+ }
42
+
43
+ const path = currentSchemaPath || tenant;
44
+
45
+ dispatch(setCurrentDescribePath(path));
46
+ dispatch(getDescribe({path}));
47
+ },
48
+ [currentSchemaPath, tenant, dispatch],
49
+ );
50
+
51
+ useAutofetcher(fetchData, [fetchData], autorefresh);
52
+
53
+ if (loading && !wasLoaded) {
54
+ return <Loader size="m" />;
55
+ }
56
+
57
+ if (error) {
58
+ return <div className={b('message-container', 'error')}>{prepareQueryError(error)}</div>;
59
+ }
60
+
61
+ if (!loading && !currentDescribe) {
62
+ return <div className={b('message-container')}>Empty</div>;
63
+ }
64
+
65
+ return (
66
+ <div className={b()}>
67
+ <div className={b('result')}>
68
+ <JSONTree
69
+ data={currentDescribe}
70
+ className={b('tree')}
71
+ onClick={({path}: {path: string}) => {
72
+ const newValue = !(expandMap.get(path) || false);
73
+ expandMap.set(path, newValue);
74
+ }}
75
+ searchOptions={{
76
+ debounceTime: 300,
77
+ }}
78
+ isExpanded={(keypath: string) => {
79
+ return expandMap.get(keypath) || false;
80
+ }}
81
+ />
82
+ </div>
83
+ </div>
84
+ );
85
+ };
86
+
87
+ export default Describe;
@@ -5,13 +5,6 @@
5
5
 
6
6
  height: 100%;
7
7
 
8
- &__loader {
9
- display: flex;
10
- flex-grow: 1;
11
- justify-content: center;
12
- align-items: center;
13
- }
14
-
15
8
  &__header-wrapper {
16
9
  padding: 13px 20px 16px;
17
10
 
@@ -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();
@@ -25,20 +25,6 @@ import {disableFullscreen} from '../../../../store/reducers/fullscreen';
25
25
 
26
26
  const b = cn('kv-query-explain');
27
27
 
28
- const DARK_COLORS = {
29
- success: 'rgba(59,201,53,0.75)',
30
- error: '#bf3230',
31
- warning: '#cc6810',
32
- mute: 'rgba(255,255,255,0.15)',
33
- stroke: 'rgba(255,255,255,0.17)',
34
- fill: '#313037',
35
- nodeFill: '#3b3a41',
36
- nodeShadow: 'rgba(0,0,0,0.2)',
37
- titleColor: 'rgba(255,255,255,0.7)',
38
- textColor: 'rgba(255,255,255,0.55)',
39
- buttonBorderColor: 'rgba(255,255,255,0.07)',
40
- };
41
-
42
28
  const EDITOR_OPTIONS = {
43
29
  automaticLayout: true,
44
30
  selectOnLineNumbers: true,
@@ -64,9 +50,15 @@ const explainOptions = [
64
50
  function GraphRoot(props) {
65
51
  const paranoid = useRef();
66
52
 
67
- const render = () => {
68
- const {data, opts, shapes, version} = props;
53
+ const {data, opts, shapes, version, theme} = props;
54
+
55
+ const [componentTheme, updateComponentTheme] = useState(theme);
69
56
 
57
+ useEffect(() => {
58
+ updateComponentTheme(theme);
59
+ }, [theme]);
60
+
61
+ const render = () => {
70
62
  if (version === explainVersions.v2) {
71
63
  paranoid.current = getTopology('graphRoot', data, opts, shapes);
72
64
  paranoid.current.render();
@@ -74,7 +66,7 @@ function GraphRoot(props) {
74
66
  paranoid.current = getCompactTopology('graphRoot', data, opts);
75
67
  paranoid.current.renderCompactTopology();
76
68
  }
77
- }
69
+ };
78
70
 
79
71
  useEffect(() => {
80
72
  render();
@@ -94,7 +86,7 @@ function GraphRoot(props) {
94
86
  graphRoot.innerHTML = '';
95
87
 
96
88
  render();
97
- }, [props.opts.colors]);
89
+ }, [componentTheme]);
98
90
 
99
91
  useEffect(() => {
100
92
  paranoid.current?.updateData?.(props.data);
@@ -134,11 +126,7 @@ function QueryExplain(props) {
134
126
  };
135
127
 
136
128
  const renderStub = () => {
137
- return (
138
- <div className={b('text-message')}>
139
- There is no explanation for the request
140
- </div>
141
- );
129
+ return <div className={b('text-message')}>There is no explanation for the request</div>;
142
130
  };
143
131
 
144
132
  const hasContent = () => {
@@ -204,12 +192,12 @@ function QueryExplain(props) {
204
192
  })}
205
193
  >
206
194
  <GraphRoot
195
+ theme={theme}
207
196
  version={version}
208
197
  data={{links, nodes}}
209
198
  opts={{
210
199
  renderNodeTitle: renderExplainNode,
211
200
  textOverflow: TextOverflow.Normal,
212
- colors: theme === 'dark' ? DARK_COLORS : {},
213
201
  initialZoomFitsCanvas: true,
214
202
  }}
215
203
  shapes={{
@@ -237,11 +225,7 @@ function QueryExplain(props) {
237
225
  message = error;
238
226
  }
239
227
 
240
- return (
241
- <div className={b('text-message')}>
242
- {message}
243
- </div>
244
- );
228
+ return <div className={b('text-message')}>{message}</div>;
245
229
  };
246
230
 
247
231
  const renderContent = () => {
@@ -292,7 +276,9 @@ function QueryExplain(props) {
292
276
  )}
293
277
  </div>
294
278
  <div className={b('controls-left')}>
295
- <EnableFullscreenButton disabled={Boolean(props.error) || !hasContent()} />
279
+ <EnableFullscreenButton
280
+ disabled={Boolean(props.error) || !hasContent()}
281
+ />
296
282
  <PaneVisibilityToggleButtons
297
283
  onCollapse={props.onCollapseResults}
298
284
  onExpand={props.onExpandResults}
@@ -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
  }
@@ -3,9 +3,7 @@ import {useDispatch} from 'react-redux';
3
3
 
4
4
  import {NavigationTree} from 'ydb-ui-components';
5
5
 
6
- import {setCurrentSchemaPath, getSchema, preloadSchemas} from '../../../../store/reducers/schema';
7
- import {getDescribe} from '../../../../store/reducers/describe';
8
- import {getSchemaAcl} from '../../../../store/reducers/schemaAcl';
6
+ import {setCurrentSchemaPath, preloadSchemas} from '../../../../store/reducers/schema';
9
7
  import type {EPathType, TEvDescribeSchemeResult} from '../../../../types/api/schema';
10
8
 
11
9
  import {mapPathTypeToNavigationTreeType} from '../../utils/schema';
@@ -30,7 +28,7 @@ export function SchemaTree(props: SchemaTreeProps) {
30
28
  const {PathDescription: {Children = []} = {}} = data;
31
29
 
32
30
  const preloadedData: Record<string, TEvDescribeSchemeResult> = {
33
- [path]: data
31
+ [path]: data,
34
32
  };
35
33
 
36
34
  const childItems = Children.map((childData) => {
@@ -55,9 +53,6 @@ export function SchemaTree(props: SchemaTreeProps) {
55
53
 
56
54
  const handleActivePathUpdate = (activePath: string) => {
57
55
  dispatch(setCurrentSchemaPath(activePath));
58
- dispatch(getSchema({path: activePath}));
59
- dispatch(getDescribe({path: activePath}));
60
- dispatch(getSchemaAcl({path: activePath}));
61
56
  };
62
57
 
63
58
  useEffect(() => {
@@ -78,12 +78,15 @@ function Tenant(props: TenantProps) {
78
78
  const tenantName = name as string;
79
79
 
80
80
  useEffect(() => {
81
- const schemaPath = currentSchemaPath || tenantName;
82
- dispatch(resetLoadingState());
83
81
  dispatch(getSchema({path: tenantName}));
84
- dispatch(getSchema({path: schemaPath}));
85
- dispatch(getSchemaAcl({path: schemaPath}));
86
- }, [tenantName, currentSchemaPath, dispatch]);
82
+ dispatch(getSchemaAcl({path: tenantName}));
83
+ }, [tenantName, dispatch]);
84
+
85
+ useEffect(() => {
86
+ dispatch(resetLoadingState());
87
+ dispatch(getSchema({path: currentSchemaPath}));
88
+ dispatch(getSchemaAcl({path: currentSchemaPath}));
89
+ }, [currentSchemaPath, dispatch]);
87
90
 
88
91
  useEffect(() => {
89
92
  dispatch(disableAutorefresh());
@@ -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
 
@@ -83,17 +83,26 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
83
83
  path,
84
84
  enums: true,
85
85
  backup: false,
86
+ private: true,
87
+ partition_config: false,
86
88
  partition_stats: false,
87
89
  partitioning_info: false,
90
+ subs: 1,
88
91
  },
89
92
  {concurrentId: concurrentId || `getSchema|${path}`},
90
93
  );
91
94
  }
92
- getDescribe({path}) {
93
- return this.get(this.getPath('/viewer/json/describe'), {
94
- path,
95
- enums: true,
96
- });
95
+ getDescribe({path}, {concurrentId} = {}) {
96
+ return this.get(
97
+ this.getPath('/viewer/json/describe'),
98
+ {
99
+ path,
100
+ enums: true,
101
+ partition_stats: true,
102
+ subs: 0,
103
+ },
104
+ {concurrentId: concurrentId || `getDescribe|${path}`},
105
+ );
97
106
  }
98
107
  getSchemaAcl({path}) {
99
108
  return this.get(
@@ -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