ydb-embedded-ui 4.21.0 → 4.22.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/components/NodeHostWrapper/NodeHostWrapper.scss +2 -1
  3. package/dist/components/QueryResultTable/QueryResultTable.tsx +7 -3
  4. package/dist/components/VirtualTable/TableChunk.tsx +2 -1
  5. package/dist/components/VirtualTable/VirtualTable.tsx +1 -1
  6. package/dist/containers/Node/Node.tsx +9 -17
  7. package/dist/containers/Node/NodeStructure/NodeStructure.tsx +8 -30
  8. package/dist/containers/Node/NodeStructure/Pdisk.tsx +32 -18
  9. package/dist/containers/Node/i18n/en.json +4 -0
  10. package/dist/containers/Node/i18n/index.ts +11 -0
  11. package/dist/containers/Node/i18n/ru.json +4 -0
  12. package/dist/containers/Nodes/Nodes.tsx +5 -10
  13. package/dist/containers/Nodes/getNodesColumns.tsx +57 -13
  14. package/dist/containers/Tablets/Tablets.tsx +3 -8
  15. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +0 -1
  16. package/dist/containers/Tenant/Diagnostics/Network/Network.js +5 -10
  17. package/dist/containers/Tenant/Diagnostics/Network/utils.ts +6 -0
  18. package/dist/containers/Tenant/Query/ExecuteResult/ExecuteResult.scss +13 -5
  19. package/dist/containers/Tenant/Query/ExecuteResult/ExecuteResult.tsx +72 -18
  20. package/dist/containers/Tenant/Query/ExplainResult/ExplainResult.js +2 -1
  21. package/dist/containers/Tenant/Query/ExplainResult/utils.ts +6 -0
  22. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +11 -24
  23. package/dist/containers/Tenant/Query/utils/getPreparedResult.ts +4 -5
  24. package/dist/containers/UserSettings/i18n/en.json +5 -2
  25. package/dist/containers/UserSettings/i18n/ru.json +5 -2
  26. package/dist/containers/UserSettings/settings.ts +12 -6
  27. package/dist/store/reducers/executeQuery.ts +4 -3
  28. package/dist/store/reducers/nodes/nodes.ts +2 -2
  29. package/dist/store/reducers/nodes/types.ts +12 -1
  30. package/dist/store/reducers/nodes/utils.ts +6 -0
  31. package/dist/store/reducers/settings/settings.ts +5 -3
  32. package/dist/types/api/netInfo.ts +1 -1
  33. package/dist/types/api/nodes.ts +24 -0
  34. package/dist/types/api/query.ts +23 -8
  35. package/dist/types/store/query.ts +6 -0
  36. package/dist/utils/constants.ts +3 -0
  37. package/dist/utils/developerUI/__test__/developerUI.test.ts +50 -0
  38. package/dist/utils/developerUI/developerUI.ts +42 -0
  39. package/dist/utils/diagnostics.ts +1 -0
  40. package/dist/utils/query.ts +68 -13
  41. package/package.json +1 -1
  42. package/dist/utils/index.js +0 -9
  43. /package/dist/{components/VirtualTable/utils.ts → utils/index.ts} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.22.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.21.1...v4.22.0) (2023-11-27)
4
+
5
+
6
+ ### Features
7
+
8
+ * **Query:** enable queries with multiple resultsets ([#595](https://github.com/ydb-platform/ydb-embedded-ui/issues/595)) ([2eedfb6](https://github.com/ydb-platform/ydb-embedded-ui/commit/2eedfb6ec3be932c7399bb67de901798c0b31b50))
9
+ * **TenantOverview:** add columns to memory table ([#593](https://github.com/ydb-platform/ydb-embedded-ui/issues/593)) ([6379577](https://github.com/ydb-platform/ydb-embedded-ui/commit/6379577782cfa69de9fb39640d2a143f1670be39))
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * fix disks developer UI links for paths with nodeId ([#594](https://github.com/ydb-platform/ydb-embedded-ui/issues/594)) ([7f5a783](https://github.com/ydb-platform/ydb-embedded-ui/commit/7f5a78393d0c23e584ad73040fd0e73d404e5d01))
15
+ * **TopShards:** sort by InFlightTxCount ([#591](https://github.com/ydb-platform/ydb-embedded-ui/issues/591)) ([eb3592d](https://github.com/ydb-platform/ydb-embedded-ui/commit/eb3592d69a465814de27e8b1e368b34cc60fed2f))
16
+
17
+ ## [4.21.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.21.0...v4.21.1) (2023-11-17)
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * move inverted disk space setting to general page ([#589](https://github.com/ydb-platform/ydb-embedded-ui/issues/589)) ([b09345e](https://github.com/ydb-platform/ydb-embedded-ui/commit/b09345e1ebe9e7a47beea5ab2dac4257790232cc))
23
+ * **Nodes:** always use nodes when flag is enabled ([#584](https://github.com/ydb-platform/ydb-embedded-ui/issues/584)) ([6ac6ee2](https://github.com/ydb-platform/ydb-embedded-ui/commit/6ac6ee2516bb2612cc7832e67ffa0bf92615a36c))
24
+ * **QueryResultTable:** fix table error on null cell sort ([#590](https://github.com/ydb-platform/ydb-embedded-ui/issues/590)) ([805a339](https://github.com/ydb-platform/ydb-embedded-ui/commit/805a339b0bba34412bf8e854cf6d24ae7c080539))
25
+ * **Tablets:** reduce rerenders ([#585](https://github.com/ydb-platform/ydb-embedded-ui/issues/585)) ([f1767a1](https://github.com/ydb-platform/ydb-embedded-ui/commit/f1767a143b139de4cd7c0df5c8c243c0224ebd3c))
26
+ * turn on query modes and metrics cards by default ([#588](https://github.com/ydb-platform/ydb-embedded-ui/issues/588)) ([c2f0d74](https://github.com/ydb-platform/ydb-embedded-ui/commit/c2f0d7424cb3182926f125a1e8c16cd4a2d422b9))
27
+ * update links to VDisk and PDisk Developer UI ([#582](https://github.com/ydb-platform/ydb-embedded-ui/issues/582)) ([97dda88](https://github.com/ydb-platform/ydb-embedded-ui/commit/97dda88bd595295eefaed4c0cbcd333e84b047f0))
28
+ * **VirtualNodes:** display developerUI link on hover ([#587](https://github.com/ydb-platform/ydb-embedded-ui/issues/587)) ([ba6c249](https://github.com/ydb-platform/ydb-embedded-ui/commit/ba6c249a9793b0bac45607b0b36f284dea4e0a7a))
29
+
3
30
  ## [4.21.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.20.4...v4.21.0) (2023-10-27)
4
31
 
5
32
 
@@ -16,7 +16,8 @@
16
16
  }
17
17
  }
18
18
 
19
- .data-table__row:hover {
19
+ .data-table__row:hover,
20
+ .ydb-virtual-table__row:hover {
20
21
  .ydb-node-host-wrapper__external-button {
21
22
  display: inline-flex;
22
23
  }
@@ -36,10 +36,14 @@ const prepareTypedColumns = (columns: ColumnType[]) => {
36
36
  align: columnType === 'number' ? DataTable.RIGHT : DataTable.LEFT,
37
37
  sortAccessor: (row) => {
38
38
  const value = row[name];
39
- if (value === undefined || value === null) return null;
39
+
40
+ if (value === undefined || value === null) {
41
+ return null;
42
+ }
43
+
40
44
  return columnType === 'number' ? BigInt(value) : value;
41
45
  },
42
- render: ({value}) => <Cell value={value as string} />,
46
+ render: ({row}) => <Cell value={String(row[name])} />,
43
47
  };
44
48
 
45
49
  return column;
@@ -56,7 +60,7 @@ const prepareGenericColumns = (data: KeyValueRow[]) => {
56
60
  name,
57
61
  align: isNumeric(data[0][name]) ? DataTable.RIGHT : DataTable.LEFT,
58
62
  sortAccessor: (row) => (isNumeric(row[name]) ? Number(row[name]) : row[name]),
59
- render: ({value}) => <Cell value={value as string} />,
63
+ render: ({row}) => <Cell value={String(row[name])} />,
60
64
  };
61
65
 
62
66
  return column;
@@ -1,8 +1,9 @@
1
1
  import {useEffect, useRef, memo} from 'react';
2
2
 
3
+ import {getArray} from '../../utils';
4
+
3
5
  import type {Column, Chunk, GetRowClassName} from './types';
4
6
  import {LoadingTableRow, TableRow} from './TableRow';
5
- import {getArray} from './utils';
6
7
 
7
8
  // With original memo generic types are lost
8
9
  const typedMemo: <T>(Component: T) => T = memo;
@@ -1,6 +1,7 @@
1
1
  import {useState, useReducer, useRef, useCallback, useEffect} from 'react';
2
2
 
3
3
  import type {IResponseError} from '../../types/api/error';
4
+ import {getArray} from '../../utils';
4
5
 
5
6
  import {TableWithControlsLayout} from '../TableWithControlsLayout/TableWithControlsLayout';
6
7
  import {ResponseError} from '../Errors/ResponseError';
@@ -31,7 +32,6 @@ import {TableHead} from './TableHead';
31
32
  import {TableChunk} from './TableChunk';
32
33
  import {EmptyTableRow} from './TableRow';
33
34
  import {useIntersectionObserver} from './useIntersectionObserver';
34
- import {getArray} from './utils';
35
35
  import i18n from './i18n';
36
36
  import {b} from './shared';
37
37
 
@@ -2,7 +2,6 @@ import * as React from 'react';
2
2
  import {useLocation, useRouteMatch} from 'react-router';
3
3
  import cn from 'bem-cn-lite';
4
4
  import {useDispatch} from 'react-redux';
5
- import _ from 'lodash';
6
5
 
7
6
  import {Tabs} from '@gravity-ui/uikit';
8
7
  import {Link} from 'react-router-dom';
@@ -52,21 +51,22 @@ function Node(props: NodeProps) {
52
51
  const {tenantName: tenantNameFromQuery} = parseQuery(location);
53
52
 
54
53
  const {activeTabVerified, nodeTabs} = React.useMemo(() => {
55
- const hasStorage = _.find(node?.Roles as any[], (el) => el === STORAGE_ROLE);
56
- let activeTabVerified = activeTab;
54
+ const hasStorage = node?.Roles?.find((el) => el === STORAGE_ROLE);
55
+
56
+ let actualActiveTab = activeTab;
57
57
  if (!hasStorage && activeTab === STORAGE) {
58
- activeTabVerified = OVERVIEW;
58
+ actualActiveTab = OVERVIEW;
59
59
  }
60
60
  const nodePages = hasStorage ? NODE_PAGES : NODE_PAGES.filter((el) => el.id !== STORAGE);
61
61
 
62
- const nodeTabs = nodePages.map((page) => {
62
+ const actualNodeTabs = nodePages.map((page) => {
63
63
  return {
64
64
  ...page,
65
65
  title: page.name,
66
66
  };
67
67
  });
68
68
 
69
- return {activeTabVerified, nodeTabs};
69
+ return {activeTabVerified: actualActiveTab, nodeTabs: actualNodeTabs};
70
70
  }, [activeTab, node]);
71
71
 
72
72
  React.useEffect(() => {
@@ -100,13 +100,13 @@ function Node(props: NodeProps) {
100
100
  size="l"
101
101
  items={nodeTabs}
102
102
  activeTab={activeTabVerified}
103
- wrapTo={({id}, node) => (
103
+ wrapTo={({id}, tabNode) => (
104
104
  <Link
105
105
  to={createHref(routes.node, {id: nodeId, activeTab: id})}
106
106
  key={id}
107
107
  className={b('tab')}
108
108
  >
109
- {node}
109
+ {tabNode}
110
110
  </Link>
111
111
  )}
112
112
  allowNotSelected={true}
@@ -115,8 +115,6 @@ function Node(props: NodeProps) {
115
115
  );
116
116
  };
117
117
  const renderTabContent = () => {
118
- const {additionalNodesProps} = props;
119
-
120
118
  switch (activeTab) {
121
119
  case STORAGE: {
122
120
  return (
@@ -134,13 +132,7 @@ function Node(props: NodeProps) {
134
132
  }
135
133
 
136
134
  case STRUCTURE: {
137
- return (
138
- <NodeStructure
139
- className={b('node-page-wrapper')}
140
- nodeId={nodeId}
141
- additionalNodesProps={additionalNodesProps}
142
- />
143
- );
135
+ return <NodeStructure className={b('node-page-wrapper')} nodeId={nodeId} />;
144
136
  }
145
137
  default:
146
138
  return false;
@@ -1,7 +1,7 @@
1
- import {useEffect, useRef, useMemo} from 'react';
1
+ import {useEffect, useRef} from 'react';
2
2
  import {useDispatch} from 'react-redux';
3
3
  import url from 'url';
4
- import _ from 'lodash';
4
+ import {isEmpty} from 'lodash/fp';
5
5
 
6
6
  import cn from 'bem-cn-lite';
7
7
 
@@ -13,15 +13,13 @@ import {selectNodeStructure} from '../../../store/reducers/node/selectors';
13
13
  import {AutoFetcher} from '../../../utils/autofetcher';
14
14
  import {useTypedSelector} from '../../../utils/hooks';
15
15
 
16
- import type {AdditionalNodesProps} from '../../../types/additionalProps';
17
-
18
16
  import {PDisk} from './Pdisk';
19
17
 
20
18
  import './NodeStructure.scss';
21
19
 
22
20
  const b = cn('kv-node-structure');
23
21
 
24
- export function valueIsDefined(value: any) {
22
+ export function valueIsDefined<T>(value: T | null | undefined): value is T {
25
23
  return value !== null && value !== undefined;
26
24
  }
27
25
 
@@ -32,24 +30,16 @@ function generateId({type, id}: {type: 'pdisk' | 'vdisk'; id: string}) {
32
30
  interface NodeStructureProps {
33
31
  nodeId: string;
34
32
  className?: string;
35
- additionalNodesProps?: AdditionalNodesProps;
36
33
  }
37
34
 
38
35
  const autofetcher = new AutoFetcher();
39
36
 
40
- function NodeStructure({nodeId, className, additionalNodesProps}: NodeStructureProps) {
37
+ function NodeStructure({nodeId, className}: NodeStructureProps) {
41
38
  const dispatch = useDispatch();
42
39
 
43
40
  const nodeStructure = useTypedSelector(selectNodeStructure);
44
41
 
45
42
  const {loadingStructure, wasLoadedStructure} = useTypedSelector((state) => state.node);
46
- const nodeData = useTypedSelector((state) => state.node?.data?.SystemStateInfo?.[0]);
47
-
48
- const nodeHref = useMemo(() => {
49
- return additionalNodesProps?.getNodeRef
50
- ? additionalNodesProps.getNodeRef(nodeData)
51
- : undefined;
52
- }, [nodeData, additionalNodesProps]);
53
43
 
54
44
  const {pdiskId: pdiskIdFromUrl, vdiskId: vdiskIdFromUrl} = url.parse(
55
45
  window.location.href,
@@ -57,23 +47,11 @@ function NodeStructure({nodeId, className, additionalNodesProps}: NodeStructureP
57
47
  ).query;
58
48
 
59
49
  const scrollContainerRef = useRef<HTMLDivElement>(null);
60
- const scrollContainer = scrollContainerRef.current;
61
50
 
62
51
  const isReady = useRef(false);
63
52
 
64
53
  const scrolled = useRef(false);
65
54
 
66
- useEffect(() => {
67
- return () => {
68
- if (scrollContainer) {
69
- scrollContainer.scrollTo({
70
- behavior: 'smooth',
71
- top: 0,
72
- });
73
- }
74
- };
75
- }, []);
76
-
77
55
  useEffect(() => {
78
56
  dispatch(getNodeStructure(nodeId));
79
57
  autofetcher.start();
@@ -87,13 +65,13 @@ function NodeStructure({nodeId, className, additionalNodesProps}: NodeStructureP
87
65
  }, [nodeId, dispatch]);
88
66
 
89
67
  useEffect(() => {
90
- if (!_.isEmpty(nodeStructure) && scrollContainer) {
68
+ if (!isEmpty(nodeStructure) && scrollContainerRef.current) {
91
69
  isReady.current = true;
92
70
  }
93
71
  }, [nodeStructure]);
94
72
 
95
73
  useEffect(() => {
96
- if (isReady.current && !scrolled.current && scrollContainer) {
74
+ if (isReady.current && !scrolled.current && scrollContainerRef.current) {
97
75
  const element = document.getElementById(
98
76
  generateId({type: 'pdisk', id: pdiskIdFromUrl as string}),
99
77
  );
@@ -112,7 +90,7 @@ function NodeStructure({nodeId, className, additionalNodesProps}: NodeStructureP
112
90
  }
113
91
 
114
92
  if (element) {
115
- scrollContainer.scrollTo({
93
+ scrollContainerRef.current.scrollTo({
116
94
  behavior: 'smooth',
117
95
  // should subtract 20 to avoid sticking the element to tabs
118
96
  top: scrollToVdisk ? scrollToVdisk : element.offsetTop,
@@ -136,7 +114,7 @@ function NodeStructure({nodeId, className, additionalNodesProps}: NodeStructureP
136
114
  id={generateId({type: 'pdisk', id: pDiskId})}
137
115
  unfolded={pdiskIdFromUrl === pDiskId}
138
116
  selectedVdiskId={vdiskIdFromUrl as string}
139
- nodeHref={nodeHref}
117
+ nodeId={nodeId}
140
118
  />
141
119
  ))
142
120
  : renderStub();
@@ -12,15 +12,20 @@ import type {
12
12
  PreparedStructureVDisk,
13
13
  } from '../../../store/reducers/node/types';
14
14
  import {EVDiskState} from '../../../types/api/vdisk';
15
- import {bytesToGB, pad9} from '../../../utils/utils';
15
+ import {bytesToGB} from '../../../utils/utils';
16
16
  import {formatStorageValuesToGb} from '../../../utils/dataFormatters/dataFormatters';
17
17
  import {getPDiskType} from '../../../utils/pdisk';
18
18
  import {DEFAULT_TABLE_SETTINGS} from '../../../utils/constants';
19
+ import {
20
+ createPDiskDeveloperUILink,
21
+ createVDiskDeveloperUILink,
22
+ } from '../../../utils/developerUI/developerUI';
19
23
  import EntityStatus from '../../../components/EntityStatus/EntityStatus';
20
24
  import InfoViewer, {type InfoViewerItem} from '../../../components/InfoViewer/InfoViewer';
21
25
  import {ProgressViewer} from '../../../components/ProgressViewer/ProgressViewer';
22
26
  import {Icon} from '../../../components/Icon';
23
27
 
28
+ import i18n from '../i18n';
24
29
  import {Vdisk} from './Vdisk';
25
30
  import {valueIsDefined} from './NodeStructure';
26
31
  import {PDiskTitleBadge} from './PDiskTitleBadge';
@@ -32,7 +37,7 @@ interface PDiskProps {
32
37
  unfolded?: boolean;
33
38
  id: string;
34
39
  selectedVdiskId?: string;
35
- nodeHref?: string | null;
40
+ nodeId: string | number;
36
41
  }
37
42
 
38
43
  enum VDiskTableColumnsIds {
@@ -54,11 +59,11 @@ const vDiskTableColumnsNames: Record<VDiskTableColumnsIdsValues, string> = {
54
59
  function getColumns({
55
60
  pDiskId,
56
61
  selectedVdiskId,
57
- nodeHref,
62
+ nodeId,
58
63
  }: {
59
64
  pDiskId: number | undefined;
60
65
  selectedVdiskId?: string;
61
- nodeHref?: string | null;
66
+ nodeId?: string | number;
62
67
  }) {
63
68
  const columns: Column<PreparedStructureVDisk>[] = [
64
69
  {
@@ -66,26 +71,31 @@ function getColumns({
66
71
  header: vDiskTableColumnsNames[VDiskTableColumnsIds.slotId],
67
72
  width: 100,
68
73
  render: ({row}) => {
69
- let vdiskInternalViewerLink = '';
74
+ const vDiskSlotId = row.VDiskSlotId;
75
+ let vdiskInternalViewerLink = null;
70
76
 
71
- if (nodeHref && pDiskId !== undefined && row.VDiskSlotId !== undefined) {
72
- vdiskInternalViewerLink +=
73
- nodeHref +
74
- 'actors/vdisks/vdisk' +
75
- pad9(pDiskId) +
76
- '_' +
77
- pad9(row.VDiskSlotId);
77
+ if (
78
+ valueIsDefined(nodeId) &&
79
+ valueIsDefined(pDiskId) &&
80
+ valueIsDefined(vDiskSlotId)
81
+ ) {
82
+ vdiskInternalViewerLink = createVDiskDeveloperUILink({
83
+ nodeId,
84
+ pDiskId,
85
+ vDiskSlotId,
86
+ });
78
87
  }
79
88
 
80
89
  return (
81
90
  <div className={b('vdisk-id', {selected: row.id === selectedVdiskId})}>
82
- <span>{row.VDiskSlotId}</span>
91
+ <span>{vDiskSlotId}</span>
83
92
  {vdiskInternalViewerLink && (
84
93
  <Button
85
94
  size="s"
86
95
  className={b('external-button', {hidden: true})}
87
96
  href={vdiskInternalViewerLink}
88
97
  target="_blank"
98
+ title={i18n('vdisk.developer-ui-button-title')}
89
99
  >
90
100
  <Icon name="external" />
91
101
  </Button>
@@ -156,7 +166,7 @@ export function PDisk({
156
166
  id,
157
167
  data,
158
168
  selectedVdiskId,
159
- nodeHref,
169
+ nodeId,
160
170
  unfolded: unfoldedFromProps,
161
171
  }: PDiskProps) {
162
172
  const [unfolded, setUnfolded] = useState(unfoldedFromProps ?? false);
@@ -190,7 +200,7 @@ export function PDisk({
190
200
  <DataTable
191
201
  theme="yandex-cloud"
192
202
  data={vDisks}
193
- columns={getColumns({nodeHref, pDiskId: PDiskId, selectedVdiskId})}
203
+ columns={getColumns({nodeId, pDiskId: PDiskId, selectedVdiskId})}
194
204
  settings={{...DEFAULT_TABLE_SETTINGS, dynamicRender: false}}
195
205
  rowClassName={(row) => {
196
206
  return row.id === selectedVdiskId ? b('selected-vdisk') : '';
@@ -203,10 +213,13 @@ export function PDisk({
203
213
  if (isEmpty(data)) {
204
214
  return <div>No information about PDisk</div>;
205
215
  }
206
- let pDiskInternalViewerLink = '';
216
+ let pDiskInternalViewerLink = null;
207
217
 
208
- if (nodeHref) {
209
- pDiskInternalViewerLink += nodeHref + 'actors/pdisks/pdisk' + pad9(PDiskId);
218
+ if (valueIsDefined(PDiskId) && valueIsDefined(nodeId)) {
219
+ pDiskInternalViewerLink = createPDiskDeveloperUILink({
220
+ nodeId,
221
+ pDiskId: PDiskId,
222
+ });
210
223
  }
211
224
 
212
225
  const pdiskInfo: InfoViewerItem[] = [
@@ -222,6 +235,7 @@ export function PDisk({
222
235
  href={pDiskInternalViewerLink}
223
236
  target="_blank"
224
237
  view="flat-secondary"
238
+ title={i18n('pdisk.developer-ui-button-title')}
225
239
  >
226
240
  <Icon name="external" />
227
241
  </Button>
@@ -0,0 +1,4 @@
1
+ {
2
+ "pdisk.developer-ui-button-title": "PDisk Developer UI page",
3
+ "vdisk.developer-ui-button-title": "VDisk Developer UI page"
4
+ }
@@ -0,0 +1,11 @@
1
+ import {i18n, Lang} from '../../../utils/i18n';
2
+
3
+ import en from './en.json';
4
+ import ru from './ru.json';
5
+
6
+ const COMPONENT = 'ydb-node-page';
7
+
8
+ i18n.registerKeyset(Lang.En, COMPONENT, en);
9
+ i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
10
+
11
+ export default i18n.keyset(COMPONENT);
@@ -0,0 +1,4 @@
1
+ {
2
+ "pdisk.developer-ui-button-title": "Страница PDisk в Developer UI",
3
+ "vdisk.developer-ui-button-title": "Страница VDisk в Developer UI"
4
+ }
@@ -5,7 +5,6 @@ import {useDispatch} from 'react-redux';
5
5
  import DataTable from '@gravity-ui/react-data-table';
6
6
  import {ASCENDING} from '@gravity-ui/react-data-table/build/esm/lib/constants';
7
7
 
8
- import type {EPathType} from '../../types/api/schema';
9
8
  import type {ProblemFilterValue} from '../../store/reducers/settings/types';
10
9
  import type {NodesSortParams} from '../../store/reducers/nodes/types';
11
10
 
@@ -39,8 +38,6 @@ import {selectFilteredNodes} from '../../store/reducers/nodes/selectors';
39
38
  import {changeFilter, ProblemFilterValues} from '../../store/reducers/settings/settings';
40
39
  import type {AdditionalNodesProps} from '../../types/additionalProps';
41
40
 
42
- import {isDatabaseEntityType} from '../Tenant/utils/schema';
43
-
44
41
  import {getNodesColumns} from './getNodesColumns';
45
42
 
46
43
  import './Nodes.scss';
@@ -51,11 +48,10 @@ const b = cn('ydb-nodes');
51
48
 
52
49
  interface NodesProps {
53
50
  path?: string;
54
- type?: EPathType;
55
51
  additionalNodesProps?: AdditionalNodesProps;
56
52
  }
57
53
 
58
- export const Nodes = ({path, type, additionalNodesProps = {}}: NodesProps) => {
54
+ export const Nodes = ({path, additionalNodesProps = {}}: NodesProps) => {
59
55
  const dispatch = useDispatch();
60
56
 
61
57
  const isClusterNodes = !path;
@@ -90,15 +86,14 @@ export const Nodes = ({path, type, additionalNodesProps = {}}: NodesProps) => {
90
86
  dispatch(setDataWasNotLoaded());
91
87
  }
92
88
 
93
- // For not DB entities we always use /compute endpoint instead of /nodes
94
- // since /nodes can return data only for tenants
95
- if (path && (!useNodesEndpoint || !isDatabaseEntityType(type))) {
89
+ // If there is no path, it's cluster Nodes tab
90
+ if (path && !useNodesEndpoint) {
96
91
  dispatch(getComputeNodes({path}));
97
92
  } else {
98
- dispatch(getNodes({tenant: path}));
93
+ dispatch(getNodes({path}));
99
94
  }
100
95
  },
101
- [dispatch, path, type, useNodesEndpoint],
96
+ [dispatch, path, useNodesEndpoint],
102
97
  );
103
98
 
104
99
  useAutofetcher(fetchNodes, [fetchNodes], isClusterNodes ? true : autorefresh);
@@ -28,6 +28,9 @@ const NODES_COLUMNS_IDS = {
28
28
  Tablets: 'Tablets',
29
29
  TopNodesLoadAverage: 'TopNodesLoadAverage',
30
30
  TopNodesMemory: 'TopNodesMemory',
31
+ SharedCacheUsage: 'SharedCacheUsage',
32
+ MemoryUsedInAlloc: 'MemoryUsedInAlloc',
33
+ TotalSessions: 'TotalSessions',
31
34
  };
32
35
 
33
36
  interface GetNodesColumnsProps {
@@ -184,23 +187,61 @@ const topNodesLoadAverageColumn: NodesColumn = {
184
187
 
185
188
  const topNodesMemoryColumn: NodesColumn = {
186
189
  name: NODES_COLUMNS_IDS.TopNodesMemory,
187
- header: 'Memory',
188
- render: ({row}) =>
189
- row.MemoryUsed ? (
190
- <ProgressViewer
191
- value={row.MemoryUsed}
192
- capacity={row.MemoryLimit}
193
- formatValues={formatStorageValuesToGb}
194
- colorizeProgress={true}
195
- />
196
- ) : (
197
- '—'
198
- ),
190
+ header: 'Process',
191
+ render: ({row}) => (
192
+ <ProgressViewer
193
+ value={row.MemoryUsed}
194
+ capacity={row.MemoryLimit}
195
+ formatValues={formatStorageValuesToGb}
196
+ colorizeProgress={true}
197
+ />
198
+ ),
199
+ align: DataTable.LEFT,
200
+ width: 140,
201
+ sortable: false,
202
+ };
203
+
204
+ const sharedCacheUsageColumn: NodesColumn = {
205
+ name: NODES_COLUMNS_IDS.SharedCacheUsage,
206
+ header: 'Tablet Cache',
207
+ render: ({row}) => (
208
+ <ProgressViewer
209
+ value={row.SharedCacheUsed}
210
+ capacity={row.SharedCacheLimit}
211
+ formatValues={formatStorageValuesToGb}
212
+ colorizeProgress={true}
213
+ />
214
+ ),
215
+ align: DataTable.LEFT,
216
+ width: 140,
217
+ sortable: false,
218
+ };
219
+
220
+ const memoryUsedInAllocColumn: NodesColumn = {
221
+ name: NODES_COLUMNS_IDS.MemoryUsedInAlloc,
222
+ header: 'Query Runtime',
223
+ render: ({row}) => (
224
+ <ProgressViewer
225
+ value={row.MemoryUsedInAlloc}
226
+ capacity={row.MemoryLimit}
227
+ formatValues={formatStorageValuesToGb}
228
+ colorizeProgress={true}
229
+ />
230
+ ),
199
231
  align: DataTable.LEFT,
200
232
  width: 140,
201
233
  sortable: false,
202
234
  };
203
235
 
236
+ const sessionsColumn: NodesColumn = {
237
+ name: NODES_COLUMNS_IDS.TotalSessions,
238
+ header: 'Sessions',
239
+ render: ({row}) => row.TotalSessions ?? '—',
240
+ align: DataTable.RIGHT,
241
+ width: 100,
242
+ sortable: false,
243
+ };
244
+
204
245
  export function getNodesColumns({tabletsPath, getNodeRef}: GetNodesColumnsProps): NodesColumn[] {
205
246
  return [
206
247
  nodeIdColumn,
@@ -241,8 +282,11 @@ export function getTopNodesByMemoryColumns({
241
282
  nodeIdColumn,
242
283
  getHostColumn(getNodeRef),
243
284
  uptimeColumn,
244
- topNodesMemoryColumn,
245
285
  topNodesLoadAverageColumn,
286
+ topNodesMemoryColumn,
287
+ sharedCacheUsageColumn,
288
+ memoryUsedInAllocColumn,
289
+ sessionsColumn,
246
290
  getTabletsColumn(tabletsPath),
247
291
  ];
248
292
  }
@@ -34,14 +34,9 @@ interface TabletsProps {
34
34
  export const Tablets = ({path, nodeId, className}: TabletsProps) => {
35
35
  const dispatch = useDispatch();
36
36
 
37
- const {
38
- data = {},
39
- wasLoaded,
40
- loading,
41
- error,
42
- stateFilter,
43
- typeFilter,
44
- } = useTypedSelector((state) => state.tablets);
37
+ const {data, wasLoaded, loading, error, stateFilter, typeFilter} = useTypedSelector(
38
+ (state) => state.tablets,
39
+ );
45
40
  const {autorefresh} = useTypedSelector((state) => state.schema);
46
41
 
47
42
  const tablets = useMemo(() => data?.TabletStateInfo || [], [data]);
@@ -123,7 +123,6 @@ function Diagnostics(props: DiagnosticsProps) {
123
123
  return (
124
124
  <Nodes
125
125
  path={currentSchemaPath}
126
- type={type}
127
126
  additionalNodesProps={props.additionalNodesProps}
128
127
  />
129
128
  );
@@ -18,6 +18,8 @@ import {changeFilter, ProblemFilterValues} from '../../../../store/reducers/sett
18
18
  import {AutoFetcher} from '../../../../utils/autofetcher';
19
19
  import {getDefaultNodePath} from '../../../Node/NodePages';
20
20
 
21
+ import {getConnectedNodesCount} from './utils';
22
+
21
23
  import './Network.scss';
22
24
 
23
25
  const b = cn('network');
@@ -145,11 +147,6 @@ class Network extends React.Component {
145
147
  );
146
148
  };
147
149
 
148
- getConnectedNodesCount = (peers) => {
149
- const res = peers?.reduce((acc, item) => (item.Connected ? acc + 1 : acc), 0);
150
- return res;
151
- };
152
-
153
150
  renderNodes = (nodes, isRight) => {
154
151
  const {showId, showRacks, clickedNode} = this.state;
155
152
  let problemNodesCount = 0;
@@ -171,9 +168,7 @@ class Network extends React.Component {
171
168
  let capacity, connected;
172
169
  if (!isRight && nodeInfo?.Peers) {
173
170
  capacity = Object.keys(nodeInfo?.Peers).length;
174
- connected = this.getConnectedNodesCount(
175
- nodeInfo?.Peers,
176
- );
171
+ connected = getConnectedNodesCount(nodeInfo?.Peers);
177
172
  }
178
173
 
179
174
  if (
@@ -214,7 +209,7 @@ class Network extends React.Component {
214
209
  let capacity, connected;
215
210
  if (!isRight) {
216
211
  capacity = nodeInfo?.Peers?.length;
217
- connected = this.getConnectedNodesCount(nodeInfo?.Peers);
212
+ connected = getConnectedNodesCount(nodeInfo?.Peers);
218
213
  }
219
214
 
220
215
  if (
@@ -234,7 +229,7 @@ class Network extends React.Component {
234
229
  capacity={nodeInfo?.Peers && nodeInfo?.Peers.length}
235
230
  connected={
236
231
  nodeInfo?.Peers &&
237
- this.getConnectedNodesCount(nodeInfo?.Peers)
232
+ getConnectedNodesCount(nodeInfo?.Peers)
238
233
  }
239
234
  onMouseEnter={showTooltip}
240
235
  onMouseLeave={hideTooltip}