ydb-embedded-ui 4.19.3 → 4.20.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/components/CellWithPopover/CellWithPopover.scss +13 -0
  3. package/dist/components/CellWithPopover/CellWithPopover.tsx +26 -0
  4. package/dist/components/LinkToSchemaObject/LinkToSchemaObject.tsx +20 -0
  5. package/dist/components/NodeHostWrapper/NodeHostWrapper.scss +0 -2
  6. package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +28 -29
  7. package/dist/components/QueryExecutionStatus/QueryExecutionStatus.tsx +3 -2
  8. package/dist/components/TruncatedQuery/TruncatedQuery.scss +8 -0
  9. package/dist/components/TruncatedQuery/TruncatedQuery.tsx +15 -1
  10. package/dist/components/UsageLabel/UsageLabel.scss +6 -0
  11. package/dist/components/UsageLabel/UsageLabel.tsx +22 -0
  12. package/dist/containers/AsideNavigation/AsideNavigation.tsx +13 -8
  13. package/dist/containers/AsideNavigation/i18n/en.json +13 -0
  14. package/dist/containers/AsideNavigation/i18n/index.ts +11 -0
  15. package/dist/containers/AsideNavigation/i18n/ru.json +13 -0
  16. package/dist/containers/Node/NodeStructure/Pdisk.tsx +74 -68
  17. package/dist/containers/Node/NodeStructure/Vdisk.tsx +9 -33
  18. package/dist/containers/Nodes/Nodes.tsx +10 -2
  19. package/dist/containers/Nodes/getNodesColumns.tsx +207 -123
  20. package/dist/containers/Storage/Storage.tsx +9 -2
  21. package/dist/containers/Storage/StorageGroups/StorageGroups.scss +0 -11
  22. package/dist/containers/Storage/StorageGroups/getStorageGroupsColumns.tsx +11 -11
  23. package/dist/containers/Storage/utils/index.ts +1 -22
  24. package/dist/containers/Tenant/Diagnostics/Describe/Describe.tsx +2 -3
  25. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss +0 -1
  26. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx +4 -2
  27. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +1 -0
  28. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckDetails.tsx +8 -1
  29. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.tsx +11 -1
  30. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/IssuesViewer/IssueTree.tsx +0 -1
  31. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.tsx +3 -0
  32. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TenantCpu.tsx +21 -0
  33. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx +53 -0
  34. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx +53 -0
  35. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx +83 -0
  36. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopShards.tsx +53 -0
  37. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TenantMemory.tsx +9 -0
  38. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx +55 -0
  39. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +44 -0
  40. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +35 -19
  41. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverviewTableLayout.tsx +53 -0
  42. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.tsx +4 -2
  43. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopGroups.tsx +9 -36
  44. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopTables.tsx +22 -41
  45. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +3 -3
  46. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +3 -3
  47. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.scss +0 -2
  48. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +19 -61
  49. package/dist/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx +102 -0
  50. package/dist/containers/Tenant/Diagnostics/TopShards/Filters/Filters.tsx +2 -2
  51. package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.tsx +18 -97
  52. package/dist/containers/Tenant/Diagnostics/TopShards/getTopShardsColumns.tsx +138 -0
  53. package/dist/containers/Tenant/Info/ExternalTable/ExternalTable.tsx +2 -4
  54. package/dist/containers/Tenant/Query/ExecuteResult/{ExecuteResult.js → ExecuteResult.tsx} +51 -31
  55. package/dist/containers/Tenant/Query/Issues/Issues.tsx +4 -6
  56. package/dist/containers/Tenant/Query/QueryDuration/QueryDuration.tsx +1 -1
  57. package/dist/containers/Tenant/utils/paneVisibilityToggleHelpers.tsx +1 -1
  58. package/dist/routes.ts +26 -1
  59. package/dist/store/reducers/{executeTopQueries.ts → executeTopQueries/executeTopQueries.ts} +23 -75
  60. package/dist/{types/store/executeTopQueries.ts → store/reducers/executeTopQueries/types.ts} +3 -7
  61. package/dist/store/reducers/executeTopQueries/utils.ts +36 -0
  62. package/dist/store/reducers/index.ts +12 -2
  63. package/dist/store/reducers/nodes/types.ts +1 -0
  64. package/dist/store/reducers/nodes/utils.ts +16 -6
  65. package/dist/store/reducers/{shardsWorkload.ts → shardsWorkload/shardsWorkload.ts} +5 -11
  66. package/dist/{types/store/shardsWorkload.ts → store/reducers/shardsWorkload/types.ts} +3 -7
  67. package/dist/store/reducers/tenantOverview/topNodesByCpu/topNodesByCpu.ts +87 -0
  68. package/dist/store/reducers/tenantOverview/topNodesByCpu/types.ts +29 -0
  69. package/dist/store/reducers/tenantOverview/topNodesByLoad/topNodesByLoad.ts +87 -0
  70. package/dist/store/reducers/tenantOverview/topNodesByLoad/types.ts +29 -0
  71. package/dist/store/reducers/tenantOverview/topNodesByMemory/topNodesByMemory.ts +87 -0
  72. package/dist/store/reducers/tenantOverview/topNodesByMemory/types.ts +29 -0
  73. package/dist/store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries.ts +93 -0
  74. package/dist/store/reducers/tenantOverview/topQueries/types.ts +14 -0
  75. package/dist/store/reducers/tenantOverview/topShards/tenantOverviewTopShards.ts +103 -0
  76. package/dist/store/reducers/tenantOverview/topShards/types.ts +14 -0
  77. package/dist/store/reducers/tenantOverview/topShards/utils.ts +3 -0
  78. package/dist/styles/mixins.scss +4 -0
  79. package/dist/types/additionalProps.ts +3 -1
  80. package/dist/types/api/compute.ts +1 -1
  81. package/dist/types/react-json-inspector.d.ts +21 -0
  82. package/dist/utils/diagnostics.ts +23 -0
  83. package/dist/utils/generateEvaluator.ts +21 -0
  84. package/dist/utils/generateHash.ts +11 -0
  85. package/package.json +3 -2
  86. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.scss +0 -41
@@ -1,29 +1,34 @@
1
1
  import {useState} from 'react';
2
2
  import cn from 'bem-cn-lite';
3
- import _ from 'lodash';
3
+ import {isEmpty} from 'lodash/fp';
4
4
 
5
5
  import {ArrowToggle, Button, Popover} from '@gravity-ui/uikit';
6
6
 
7
- import DataTable, {Column, Settings} from '@gravity-ui/react-data-table';
8
-
9
- import EntityStatus from '../../../components/EntityStatus/EntityStatus';
10
- import InfoViewer from '../../../components/InfoViewer/InfoViewer';
11
- import {ProgressViewer} from '../../../components/ProgressViewer/ProgressViewer';
12
- import {Icon} from '../../../components/Icon';
13
- import {Vdisk} from './Vdisk';
7
+ import DataTable, {type Column} from '@gravity-ui/react-data-table';
14
8
 
9
+ import type {ValueOf} from '../../../types/common';
10
+ import type {
11
+ PreparedStructurePDisk,
12
+ PreparedStructureVDisk,
13
+ } from '../../../store/reducers/node/types';
14
+ import {EVDiskState} from '../../../types/api/vdisk';
15
15
  import {bytesToGB, pad9} from '../../../utils/utils';
16
16
  import {formatStorageValuesToGb} from '../../../utils/dataFormatters/dataFormatters';
17
17
  import {getPDiskType} from '../../../utils/pdisk';
18
-
19
18
  import {DEFAULT_TABLE_SETTINGS} from '../../../utils/constants';
19
+ import EntityStatus from '../../../components/EntityStatus/EntityStatus';
20
+ import InfoViewer, {type InfoViewerItem} from '../../../components/InfoViewer/InfoViewer';
21
+ import {ProgressViewer} from '../../../components/ProgressViewer/ProgressViewer';
22
+ import {Icon} from '../../../components/Icon';
23
+
24
+ import {Vdisk} from './Vdisk';
20
25
  import {valueIsDefined} from './NodeStructure';
21
26
  import {PDiskTitleBadge} from './PDiskTitleBadge';
22
27
 
23
28
  const b = cn('kv-node-structure');
24
29
 
25
30
  interface PDiskProps {
26
- data: Record<string, any>;
31
+ data: PreparedStructurePDisk;
27
32
  unfolded?: boolean;
28
33
  id: string;
29
34
  selectedVdiskId?: string;
@@ -37,8 +42,7 @@ enum VDiskTableColumnsIds {
37
42
  Info = 'Info',
38
43
  }
39
44
 
40
- type VDiskTableColumnsIdsKeys = keyof typeof VDiskTableColumnsIds;
41
- type VDiskTableColumnsIdsValues = typeof VDiskTableColumnsIds[VDiskTableColumnsIdsKeys];
45
+ type VDiskTableColumnsIdsValues = ValueOf<typeof VDiskTableColumnsIds>;
42
46
 
43
47
  const vDiskTableColumnsNames: Record<VDiskTableColumnsIdsValues, string> = {
44
48
  VDiskSlotId: 'Slot id',
@@ -47,39 +51,35 @@ const vDiskTableColumnsNames: Record<VDiskTableColumnsIdsValues, string> = {
47
51
  Info: '',
48
52
  };
49
53
 
50
- interface RowType {
51
- id: string;
52
- [VDiskTableColumnsIds.slotId]: number;
53
- [VDiskTableColumnsIds.VDiskState]: string;
54
- AllocatedSize: string;
55
- AvailableSize: string;
56
- }
57
-
58
54
  function getColumns({
59
55
  pDiskId,
60
56
  selectedVdiskId,
61
57
  nodeHref,
62
58
  }: {
63
- pDiskId: number;
59
+ pDiskId: number | undefined;
64
60
  selectedVdiskId?: string;
65
61
  nodeHref?: string | null;
66
62
  }) {
67
- const columns: Column<RowType>[] = [
63
+ const columns: Column<PreparedStructureVDisk>[] = [
68
64
  {
69
- name: VDiskTableColumnsIds.slotId as string,
65
+ name: VDiskTableColumnsIds.slotId,
70
66
  header: vDiskTableColumnsNames[VDiskTableColumnsIds.slotId],
71
67
  width: 100,
72
- render: ({value, row}) => {
68
+ render: ({row}) => {
73
69
  let vdiskInternalViewerLink = '';
74
70
 
75
- if (nodeHref && value !== undefined) {
71
+ if (nodeHref && pDiskId !== undefined && row.VDiskSlotId !== undefined) {
76
72
  vdiskInternalViewerLink +=
77
- nodeHref + 'actors/vdisks/vdisk' + pad9(pDiskId) + '_' + pad9(value);
73
+ nodeHref +
74
+ 'actors/vdisks/vdisk' +
75
+ pad9(pDiskId) +
76
+ '_' +
77
+ pad9(row.VDiskSlotId);
78
78
  }
79
79
 
80
80
  return (
81
81
  <div className={b('vdisk-id', {selected: row.id === selectedVdiskId})}>
82
- <span>{value as number}</span>
82
+ <span>{row.VDiskSlotId}</span>
83
83
  {vdiskInternalViewerLink && (
84
84
  <Button
85
85
  size="s"
@@ -96,17 +96,19 @@ function getColumns({
96
96
  align: DataTable.LEFT,
97
97
  },
98
98
  {
99
- name: VDiskTableColumnsIds.VDiskState as string,
99
+ name: VDiskTableColumnsIds.VDiskState,
100
100
  header: vDiskTableColumnsNames[VDiskTableColumnsIds.VDiskState],
101
101
  width: 70,
102
- render: ({value}) => {
103
- return <EntityStatus status={value === 'OK' ? 'green' : 'red'} />;
102
+ render: ({row}) => {
103
+ return (
104
+ <EntityStatus status={row.VDiskState === EVDiskState.OK ? 'green' : 'red'} />
105
+ );
104
106
  },
105
- sortAccessor: (row) => (row[VDiskTableColumnsIds.VDiskState] === 'OK' ? 1 : 0),
107
+ sortAccessor: (row) => (row.VDiskState === EVDiskState.OK ? 1 : 0),
106
108
  align: DataTable.CENTER,
107
109
  },
108
110
  {
109
- name: VDiskTableColumnsIds.Size as string,
111
+ name: VDiskTableColumnsIds.Size,
110
112
  header: vDiskTableColumnsNames[VDiskTableColumnsIds.Size],
111
113
  width: 100,
112
114
  render: ({row}) => {
@@ -123,7 +125,7 @@ function getColumns({
123
125
  align: DataTable.CENTER,
124
126
  },
125
127
  {
126
- name: VDiskTableColumnsIds.Info as string,
128
+ name: VDiskTableColumnsIds.Info,
127
129
  header: vDiskTableColumnsNames[VDiskTableColumnsIds.Info],
128
130
  width: 70,
129
131
  render: ({row}) => {
@@ -150,10 +152,31 @@ function getColumns({
150
152
  return columns;
151
153
  }
152
154
 
153
- export function PDisk(props: PDiskProps) {
154
- const [unfolded, setUnfolded] = useState(props.unfolded ?? false);
155
+ export function PDisk({
156
+ id,
157
+ data,
158
+ selectedVdiskId,
159
+ nodeHref,
160
+ unfolded: unfoldedFromProps,
161
+ }: PDiskProps) {
162
+ const [unfolded, setUnfolded] = useState(unfoldedFromProps ?? false);
163
+
164
+ const {
165
+ TotalSize = 0,
166
+ AvailableSize = 0,
167
+ Device,
168
+ Guid,
169
+ PDiskId,
170
+ Path,
171
+ Realtime,
172
+ State,
173
+ Category,
174
+ SerialNumber,
175
+ vDisks,
176
+ } = data;
155
177
 
156
- const data = props.data ?? {};
178
+ const total = Number(TotalSize);
179
+ const available = Number(AvailableSize);
157
180
 
158
181
  const onOpenPDiskDetails = () => {
159
182
  setUnfolded(true);
@@ -163,15 +186,12 @@ export function PDisk(props: PDiskProps) {
163
186
  };
164
187
 
165
188
  const renderVDisks = () => {
166
- const {selectedVdiskId, data, nodeHref} = props;
167
- const {vDisks} = data;
168
-
169
189
  return (
170
190
  <DataTable
171
191
  theme="yandex-cloud"
172
192
  data={vDisks}
173
- columns={getColumns({nodeHref, pDiskId: data.PDiskId, selectedVdiskId})}
174
- settings={{...DEFAULT_TABLE_SETTINGS, dynamicRender: false} as Settings}
193
+ columns={getColumns({nodeHref, pDiskId: PDiskId, selectedVdiskId})}
194
+ settings={{...DEFAULT_TABLE_SETTINGS, dynamicRender: false}}
175
195
  rowClassName={(row) => {
176
196
  return row.id === selectedVdiskId ? b('selected-vdisk') : '';
177
197
  }}
@@ -180,30 +200,16 @@ export function PDisk(props: PDiskProps) {
180
200
  };
181
201
 
182
202
  const renderPDiskDetails = () => {
183
- if (_.isEmpty(data)) {
203
+ if (isEmpty(data)) {
184
204
  return <div>No information about PDisk</div>;
185
205
  }
186
- const {nodeHref} = props;
187
- const {
188
- TotalSize,
189
- AvailableSize,
190
- Device,
191
- Guid,
192
- PDiskId,
193
- Path,
194
- Realtime,
195
- State,
196
- Category,
197
- SerialNumber,
198
- } = data;
199
-
200
206
  let pDiskInternalViewerLink = '';
201
207
 
202
208
  if (nodeHref) {
203
209
  pDiskInternalViewerLink += nodeHref + 'actors/pdisks/pdisk' + pad9(PDiskId);
204
210
  }
205
211
 
206
- const pdiskInfo: any = [
212
+ const pdiskInfo: InfoViewerItem[] = [
207
213
  {
208
214
  label: 'PDisk Id',
209
215
  value: (
@@ -236,19 +242,19 @@ export function PDisk(props: PDiskProps) {
236
242
  }
237
243
  pdiskInfo.push({
238
244
  label: 'Allocated Size',
239
- value: bytesToGB(TotalSize - AvailableSize),
245
+ value: bytesToGB(total - available),
240
246
  });
241
247
  pdiskInfo.push({
242
248
  label: 'Available Size',
243
- value: bytesToGB(AvailableSize),
249
+ value: bytesToGB(available),
244
250
  });
245
- if (Number(TotalSize) >= 0 && Number(AvailableSize) >= 0) {
251
+ if (total >= 0 && available >= 0) {
246
252
  pdiskInfo.push({
247
253
  label: 'Size',
248
254
  value: (
249
255
  <ProgressViewer
250
- value={TotalSize - AvailableSize}
251
- capacity={TotalSize}
256
+ value={total - available}
257
+ capacity={total}
252
258
  formatValues={formatStorageValuesToGb}
253
259
  colorizeProgress={true}
254
260
  className={b('size')}
@@ -286,24 +292,24 @@ export function PDisk(props: PDiskProps) {
286
292
  };
287
293
 
288
294
  return (
289
- <div className={b('pdisk')} id={props.id}>
295
+ <div className={b('pdisk')} id={id}>
290
296
  <div className={b('pdisk-header')}>
291
297
  <div className={b('pdisk-title-wrapper')}>
292
- <EntityStatus status={data.Device} />
298
+ <EntityStatus status={Device} />
293
299
  <PDiskTitleBadge
294
300
  label="PDiskID"
295
- value={data.PDiskId}
301
+ value={PDiskId}
296
302
  className={b('pdisk-title-id')}
297
303
  />
298
304
  <PDiskTitleBadge value={getPDiskType(data)} className={b('pdisk-title-type')} />
299
305
  <ProgressViewer
300
- value={data.TotalSize - data.AvailableSize}
301
- capacity={data.TotalSize}
306
+ value={total - available}
307
+ capacity={total}
302
308
  formatValues={formatStorageValuesToGb}
303
309
  colorizeProgress={true}
304
310
  className={b('pdisk-title-size')}
305
311
  />
306
- <PDiskTitleBadge label="VDisks" value={data.vDisks.length} />
312
+ <PDiskTitleBadge label="VDisks" value={vDisks.length} />
307
313
  </div>
308
314
  <Button
309
315
  onClick={unfolded ? onClosePDiskDetails : onOpenPDiskDetails}
@@ -1,43 +1,19 @@
1
1
  import React from 'react';
2
2
  import cn from 'bem-cn-lite';
3
3
 
4
- import {ProgressViewer} from '../../../components/ProgressViewer/ProgressViewer';
4
+ import type {TVDiskStateInfo} from '../../../types/api/vdisk';
5
5
  import {
6
6
  formatStorageValuesToGb,
7
7
  stringifyVdiskId,
8
8
  } from '../../../utils/dataFormatters/dataFormatters';
9
9
  import {bytesToGB, bytesToSpeed} from '../../../utils/utils';
10
10
  import EntityStatus from '../../../components/EntityStatus/EntityStatus';
11
- import {valueIsDefined} from './NodeStructure';
12
11
  import InfoViewer from '../../../components/InfoViewer/InfoViewer';
12
+ import {ProgressViewer} from '../../../components/ProgressViewer/ProgressViewer';
13
13
 
14
- const b = cn('kv-node-structure');
14
+ import {valueIsDefined} from './NodeStructure';
15
15
 
16
- interface VdiskProps {
17
- AllocatedSize?: string;
18
- DiskSpace?: string;
19
- FrontQueues?: string;
20
- Guid?: string;
21
- Replicated?: boolean;
22
- VDiskState?: string;
23
- VDiskId?: {
24
- GroupId: number;
25
- GroupGeneration: number;
26
- Ring: number;
27
- Domain: number;
28
- VDisk: number;
29
- };
30
- VDiskSlotId?: number;
31
- Kind?: string;
32
- SatisfactionRank?: {FreshRank: {Flag: string}; LevelRank: {Flag: string}};
33
- AvailableSize?: string;
34
- HasUnreadableBlobs?: boolean;
35
- IncarnationGuid?: string;
36
- InstanceGuid?: string;
37
- StoragePoolName?: string;
38
- ReadThroughput?: string;
39
- WriteThroughput?: string;
40
- }
16
+ const b = cn('kv-node-structure');
41
17
 
42
18
  export function Vdisk({
43
19
  AllocatedSize,
@@ -57,7 +33,7 @@ export function Vdisk({
57
33
  StoragePoolName,
58
34
  ReadThroughput,
59
35
  WriteThroughput,
60
- }: VdiskProps) {
36
+ }: TVDiskStateInfo) {
61
37
  const vdiskInfo = [];
62
38
 
63
39
  if (valueIsDefined(VDiskSlotId)) {
@@ -81,16 +57,16 @@ export function Vdisk({
81
57
  value: <EntityStatus status={DiskSpace} />,
82
58
  });
83
59
  }
84
- if (valueIsDefined(SatisfactionRank?.FreshRank.Flag)) {
60
+ if (valueIsDefined(SatisfactionRank?.FreshRank?.Flag)) {
85
61
  vdiskInfo.push({
86
62
  label: 'Fresh Rank Satisfaction',
87
- value: <EntityStatus status={SatisfactionRank?.FreshRank.Flag} />,
63
+ value: <EntityStatus status={SatisfactionRank?.FreshRank?.Flag} />,
88
64
  });
89
65
  }
90
- if (valueIsDefined(SatisfactionRank?.LevelRank.Flag)) {
66
+ if (valueIsDefined(SatisfactionRank?.LevelRank?.Flag)) {
91
67
  vdiskInfo.push({
92
68
  label: 'Level Rank Satisfaction',
93
- value: <EntityStatus status={SatisfactionRank?.LevelRank.Flag} />,
69
+ value: <EntityStatus status={SatisfactionRank?.LevelRank?.Flag} />,
94
70
  });
95
71
  }
96
72
  vdiskInfo.push({label: 'Replicated', value: Replicated ? 'Yes' : 'No'});
@@ -26,7 +26,11 @@ import {
26
26
  useNodesRequestParams,
27
27
  useTableSort,
28
28
  } from '../../utils/hooks';
29
- import {isUnavailableNode, NodesUptimeFilterValues} from '../../utils/nodes';
29
+ import {
30
+ isSortableNodesProperty,
31
+ isUnavailableNode,
32
+ NodesUptimeFilterValues,
33
+ } from '../../utils/nodes';
30
34
 
31
35
  import {
32
36
  getNodes,
@@ -153,10 +157,14 @@ export const Nodes = ({path, type, additionalNodesProps = {}}: NodesProps) => {
153
157
  };
154
158
 
155
159
  const renderTable = () => {
156
- const columns = getNodesColumns({
160
+ const rawColumns = getNodesColumns({
157
161
  getNodeRef: additionalNodesProps.getNodeRef,
158
162
  });
159
163
 
164
+ const columns = rawColumns.map((column) => {
165
+ return {...column, sortable: isSortableNodesProperty(column.name)};
166
+ });
167
+
160
168
  if (nodes && nodes.length === 0) {
161
169
  if (
162
170
  problemFilter !== ProblemFilterValues.ALL ||