ydb-embedded-ui 4.21.0 → 4.22.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 (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}