ydb-embedded-ui 4.19.3 → 4.20.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/components/LinkToSchemaObject/LinkToSchemaObject.tsx +20 -0
  3. package/dist/components/QueryExecutionStatus/QueryExecutionStatus.tsx +3 -2
  4. package/dist/components/UsageLabel/UsageLabel.scss +6 -0
  5. package/dist/components/UsageLabel/UsageLabel.tsx +22 -0
  6. package/dist/containers/AsideNavigation/AsideNavigation.tsx +13 -8
  7. package/dist/containers/AsideNavigation/i18n/en.json +13 -0
  8. package/dist/containers/AsideNavigation/i18n/index.ts +11 -0
  9. package/dist/containers/AsideNavigation/i18n/ru.json +13 -0
  10. package/dist/containers/Node/NodeStructure/Pdisk.tsx +74 -68
  11. package/dist/containers/Node/NodeStructure/Vdisk.tsx +9 -33
  12. package/dist/containers/Nodes/Nodes.tsx +10 -2
  13. package/dist/containers/Nodes/getNodesColumns.tsx +206 -122
  14. package/dist/containers/Storage/Storage.tsx +9 -2
  15. package/dist/containers/Storage/utils/index.ts +1 -22
  16. package/dist/containers/Tenant/Diagnostics/Describe/Describe.tsx +2 -3
  17. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss +0 -1
  18. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx +4 -2
  19. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +1 -0
  20. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckDetails.tsx +8 -1
  21. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.tsx +11 -1
  22. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/IssuesViewer/IssueTree.tsx +0 -1
  23. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.tsx +3 -0
  24. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TenantCpu.tsx +21 -0
  25. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx +53 -0
  26. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx +53 -0
  27. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx +85 -0
  28. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopShards.tsx +53 -0
  29. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TenantMemory.tsx +9 -0
  30. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx +55 -0
  31. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +40 -0
  32. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +35 -19
  33. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverviewTableLayout.tsx +53 -0
  34. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopTables.tsx +15 -7
  35. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +3 -3
  36. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +3 -3
  37. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.scss +0 -2
  38. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +13 -61
  39. package/dist/containers/Tenant/Diagnostics/TopQueries/getTopQueriesColumns.tsx +82 -0
  40. package/dist/containers/Tenant/Diagnostics/TopShards/Filters/Filters.tsx +2 -2
  41. package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.tsx +18 -97
  42. package/dist/containers/Tenant/Diagnostics/TopShards/getTopShardsColumns.tsx +138 -0
  43. package/dist/containers/Tenant/Info/ExternalTable/ExternalTable.tsx +2 -4
  44. package/dist/containers/Tenant/Query/ExecuteResult/{ExecuteResult.js → ExecuteResult.tsx} +51 -31
  45. package/dist/containers/Tenant/Query/Issues/Issues.tsx +4 -6
  46. package/dist/containers/Tenant/Query/QueryDuration/QueryDuration.tsx +1 -1
  47. package/dist/containers/Tenant/utils/paneVisibilityToggleHelpers.tsx +1 -1
  48. package/dist/routes.ts +6 -0
  49. package/dist/store/reducers/{executeTopQueries.ts → executeTopQueries/executeTopQueries.ts} +23 -75
  50. package/dist/{types/store/executeTopQueries.ts → store/reducers/executeTopQueries/types.ts} +3 -7
  51. package/dist/store/reducers/executeTopQueries/utils.ts +36 -0
  52. package/dist/store/reducers/index.ts +12 -2
  53. package/dist/store/reducers/nodes/types.ts +1 -0
  54. package/dist/store/reducers/nodes/utils.ts +16 -6
  55. package/dist/store/reducers/{shardsWorkload.ts → shardsWorkload/shardsWorkload.ts} +5 -11
  56. package/dist/{types/store/shardsWorkload.ts → store/reducers/shardsWorkload/types.ts} +3 -7
  57. package/dist/store/reducers/tenantOverview/topNodesByCpu/topNodesByCpu.ts +87 -0
  58. package/dist/store/reducers/tenantOverview/topNodesByCpu/types.ts +29 -0
  59. package/dist/store/reducers/tenantOverview/topNodesByLoad/topNodesByLoad.ts +87 -0
  60. package/dist/store/reducers/tenantOverview/topNodesByLoad/types.ts +29 -0
  61. package/dist/store/reducers/tenantOverview/topNodesByMemory/topNodesByMemory.ts +87 -0
  62. package/dist/store/reducers/tenantOverview/topNodesByMemory/types.ts +29 -0
  63. package/dist/store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries.ts +93 -0
  64. package/dist/store/reducers/tenantOverview/topQueries/types.ts +14 -0
  65. package/dist/store/reducers/tenantOverview/topShards/tenantOverviewTopShards.ts +103 -0
  66. package/dist/store/reducers/tenantOverview/topShards/types.ts +14 -0
  67. package/dist/store/reducers/tenantOverview/topShards/utils.ts +3 -0
  68. package/dist/styles/mixins.scss +4 -0
  69. package/dist/types/additionalProps.ts +3 -1
  70. package/dist/types/api/compute.ts +1 -1
  71. package/dist/types/react-json-inspector.d.ts +21 -0
  72. package/dist/utils/diagnostics.ts +11 -0
  73. package/dist/utils/generateEvaluator.ts +21 -0
  74. package/package.json +1 -1
@@ -0,0 +1,53 @@
1
+ import {useDispatch} from 'react-redux';
2
+ import {useCallback} from 'react';
3
+
4
+ import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
5
+ import {
6
+ getTopNodesByLoad,
7
+ selectTopNodesByLoad,
8
+ setDataWasNotLoaded,
9
+ } from '../../../../../store/reducers/tenantOverview/topNodesByLoad/topNodesByLoad';
10
+ import type {AdditionalNodesProps} from '../../../../../types/additionalProps';
11
+ import {getTopNodesByLoadColumns} from '../../../../Nodes/getNodesColumns';
12
+ import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
13
+
14
+ import i18n from '../i18n';
15
+
16
+ interface TopNodesByLoadProps {
17
+ path: string;
18
+ additionalNodesProps?: AdditionalNodesProps;
19
+ }
20
+
21
+ export function TopNodesByLoad({path, additionalNodesProps}: TopNodesByLoadProps) {
22
+ const dispatch = useDispatch();
23
+
24
+ const {wasLoaded, loading, error} = useTypedSelector((state) => state.topNodesByLoad);
25
+ const {autorefresh} = useTypedSelector((state) => state.schema);
26
+ const topNodes = useTypedSelector(selectTopNodesByLoad);
27
+ const columns = getTopNodesByLoadColumns(additionalNodesProps?.getNodeRef);
28
+
29
+ const fetchNodes = useCallback(
30
+ (isBackground) => {
31
+ if (!isBackground) {
32
+ dispatch(setDataWasNotLoaded());
33
+ }
34
+
35
+ dispatch(getTopNodesByLoad({tenant: path}));
36
+ },
37
+ [dispatch, path],
38
+ );
39
+
40
+ useAutofetcher(fetchNodes, [fetchNodes], autorefresh);
41
+
42
+ return (
43
+ <TenantOverviewTableLayout
44
+ data={topNodes || []}
45
+ columns={columns}
46
+ title="Top nodes by load"
47
+ loading={loading}
48
+ wasLoaded={wasLoaded}
49
+ error={error}
50
+ emptyDataMessage={i18n('top-nodes.empty-data')}
51
+ />
52
+ );
53
+ }
@@ -0,0 +1,85 @@
1
+ import qs from 'qs';
2
+ import {useDispatch} from 'react-redux';
3
+ import {useHistory, useLocation} from 'react-router';
4
+ import {useCallback} from 'react';
5
+
6
+ import {
7
+ TENANT_PAGE,
8
+ TENANT_PAGES_IDS,
9
+ TENANT_QUERY_TABS_ID,
10
+ } from '../../../../../store/reducers/tenant/constants';
11
+ import {
12
+ fetchTenantOverviewTopQueries,
13
+ setDataWasNotLoaded,
14
+ } from '../../../../../store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries';
15
+ import {changeUserInput} from '../../../../../store/reducers/executeQuery';
16
+ import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
17
+ import {TenantTabsGroups, getTenantPath} from '../../../TenantPages';
18
+ import {getTenantOverviewTopQueriesColumns} from '../../TopQueries/getTopQueriesColumns';
19
+ import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
20
+
21
+ interface TopQueriesProps {
22
+ path: string;
23
+ }
24
+
25
+ export function TopQueries({path}: TopQueriesProps) {
26
+ const dispatch = useDispatch();
27
+ const location = useLocation();
28
+ const history = useHistory();
29
+
30
+ const {autorefresh} = useTypedSelector((state) => state.schema);
31
+
32
+ const {
33
+ loading,
34
+ wasLoaded,
35
+ error,
36
+ data: {result: data = undefined} = {},
37
+ } = useTypedSelector((state) => state.tenantOverviewTopQueries);
38
+ const columns = getTenantOverviewTopQueriesColumns();
39
+
40
+ useAutofetcher(
41
+ (isBackground) => {
42
+ if (!isBackground) {
43
+ dispatch(setDataWasNotLoaded());
44
+ }
45
+
46
+ dispatch(fetchTenantOverviewTopQueries(path));
47
+ },
48
+ [dispatch, path],
49
+ autorefresh,
50
+ );
51
+
52
+ const handleRowClick = useCallback(
53
+ (row) => {
54
+ const {QueryText: input} = row;
55
+
56
+ dispatch(changeUserInput({input}));
57
+
58
+ const queryParams = qs.parse(location.search, {
59
+ ignoreQueryPrefix: true,
60
+ });
61
+
62
+ const queryPath = getTenantPath({
63
+ ...queryParams,
64
+ [TENANT_PAGE]: TENANT_PAGES_IDS.query,
65
+ [TenantTabsGroups.queryTab]: TENANT_QUERY_TABS_ID.newQuery,
66
+ });
67
+
68
+ history.push(queryPath);
69
+ },
70
+ [dispatch, history, location],
71
+ );
72
+
73
+ return (
74
+ <TenantOverviewTableLayout
75
+ data={data || []}
76
+ columns={columns}
77
+ onRowClick={handleRowClick}
78
+ title="Top queries by cpu time"
79
+ loading={loading}
80
+ wasLoaded={wasLoaded}
81
+ error={error}
82
+ tableClassNameModifiers={{'top-queries': true}}
83
+ />
84
+ );
85
+ }
@@ -0,0 +1,53 @@
1
+ import {useDispatch} from 'react-redux';
2
+ import {useLocation} from 'react-router';
3
+
4
+ import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
5
+ import {
6
+ sendTenantOverviewTopShardsQuery,
7
+ setDataWasNotLoaded,
8
+ } from '../../../../../store/reducers/tenantOverview/topShards/tenantOverviewTopShards';
9
+ import {getTopShardsColumns} from '../../TopShards/getTopShardsColumns';
10
+ import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
11
+
12
+ interface TopShardsProps {
13
+ path: string;
14
+ }
15
+
16
+ export const TopShards = ({path}: TopShardsProps) => {
17
+ const dispatch = useDispatch();
18
+ const location = useLocation();
19
+
20
+ const {autorefresh, currentSchemaPath} = useTypedSelector((state) => state.schema);
21
+
22
+ const {
23
+ loading,
24
+ data: {result: data = undefined} = {},
25
+ error,
26
+ wasLoaded,
27
+ } = useTypedSelector((state) => state.tenantOverviewTopShards);
28
+
29
+ useAutofetcher(
30
+ (isBackground) => {
31
+ if (!isBackground) {
32
+ dispatch(setDataWasNotLoaded());
33
+ }
34
+ dispatch(sendTenantOverviewTopShardsQuery(path, currentSchemaPath));
35
+ },
36
+ [dispatch, path, currentSchemaPath],
37
+ autorefresh,
38
+ );
39
+
40
+ const columns = getTopShardsColumns(path, location);
41
+
42
+ return (
43
+ <TenantOverviewTableLayout
44
+ data={data || []}
45
+ columns={columns}
46
+ title="Top shards by cpu usage"
47
+ loading={loading}
48
+ wasLoaded={wasLoaded}
49
+ error={error}
50
+ tableClassNameModifiers={{'top-queries': true}}
51
+ />
52
+ );
53
+ };
@@ -0,0 +1,9 @@
1
+ import {TopNodesByMemory} from './TopNodesByMemory';
2
+
3
+ interface TenantMemoryProps {
4
+ path: string;
5
+ }
6
+
7
+ export function TenantMemory({path}: TenantMemoryProps) {
8
+ return <TopNodesByMemory path={path} />;
9
+ }
@@ -0,0 +1,55 @@
1
+ import {useDispatch} from 'react-redux';
2
+ import {useCallback} from 'react';
3
+
4
+ import {useAutofetcher, useTypedSelector} from '../../../../../utils/hooks';
5
+ import {
6
+ getTopNodesByMemory,
7
+ selectTopNodesByMemory,
8
+ setDataWasNotLoaded,
9
+ } from '../../../../../store/reducers/tenantOverview/topNodesByMemory/topNodesByMemory';
10
+ import type {AdditionalNodesProps} from '../../../../../types/additionalProps';
11
+ import {getTopNodesByMemoryColumns} from '../../../../Nodes/getNodesColumns';
12
+ import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout';
13
+
14
+ import i18n from '../i18n';
15
+
16
+ interface TopNodesByMemoryProps {
17
+ path: string;
18
+ additionalNodesProps?: AdditionalNodesProps;
19
+ }
20
+
21
+ export function TopNodesByMemory({path, additionalNodesProps}: TopNodesByMemoryProps) {
22
+ const dispatch = useDispatch();
23
+
24
+ const {wasLoaded, loading, error} = useTypedSelector((state) => state.topNodesByMemory);
25
+ const {autorefresh} = useTypedSelector((state) => state.schema);
26
+ const topNodes = useTypedSelector(selectTopNodesByMemory);
27
+ const columns = getTopNodesByMemoryColumns({
28
+ getNodeRef: additionalNodesProps?.getNodeRef,
29
+ });
30
+
31
+ const fetchNodes = useCallback(
32
+ (isBackground) => {
33
+ if (!isBackground) {
34
+ dispatch(setDataWasNotLoaded());
35
+ }
36
+
37
+ dispatch(getTopNodesByMemory({tenant: path}));
38
+ },
39
+ [dispatch, path],
40
+ );
41
+
42
+ useAutofetcher(fetchNodes, [fetchNodes], autorefresh);
43
+
44
+ return (
45
+ <TenantOverviewTableLayout
46
+ data={topNodes || []}
47
+ columns={columns}
48
+ title="Top nodes by memory"
49
+ loading={loading}
50
+ wasLoaded={wasLoaded}
51
+ error={error}
52
+ emptyDataMessage={i18n('top-nodes.empty-data')}
53
+ />
54
+ );
55
+ }
@@ -1,4 +1,9 @@
1
+ @import '../../../../styles/mixins.scss';
2
+
1
3
  .tenant-overview {
4
+ overflow: auto;
5
+
6
+ height: 100%;
2
7
  padding-bottom: 20px;
3
8
 
4
9
  &__loader {
@@ -78,4 +83,39 @@
78
83
  font-weight: 600;
79
84
  line-height: var(--yc-text-body-2-line-height);
80
85
  }
86
+
87
+ &__info {
88
+ position: sticky;
89
+ left: 0;
90
+
91
+ width: max-content;
92
+ }
93
+
94
+ &__title {
95
+ margin-bottom: 10px;
96
+
97
+ font-size: var(--yc-text-body-2-font-size);
98
+ font-weight: 700;
99
+ line-height: var(--yc-text-body-2-line-height);
100
+ }
101
+
102
+ &__table {
103
+ width: var(--diagnostics-section-table-width);
104
+
105
+ @include table-styles();
106
+
107
+ &:not(:last-child) {
108
+ margin-bottom: var(--diagnostics-section-margin);
109
+ }
110
+
111
+ th {
112
+ height: 40px;
113
+
114
+ vertical-align: middle;
115
+ }
116
+
117
+ &_top-queries tr {
118
+ cursor: pointer;
119
+ }
120
+ }
81
121
  }
@@ -9,15 +9,16 @@ import {TENANT_DEFAULT_TITLE} from '../../../../utils/constants';
9
9
  import {TENANT_METRICS_TABS_IDS} from '../../../../store/reducers/tenant/constants';
10
10
  import {mapDatabaseTypeToDBName} from '../../utils/schema';
11
11
  import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
12
- import type {AdditionalTenantsProps} from '../../../../types/additionalProps';
12
+ import type {AdditionalNodesProps, AdditionalTenantsProps} from '../../../../types/additionalProps';
13
13
  import {getTenantInfo, setDataWasNotLoaded} from '../../../../store/reducers/tenant/tenant';
14
14
  import {calculateTenantMetrics} from '../../../../store/reducers/tenants/utils';
15
+ import {TenantCpu} from './TenantCpu/TenantCpu';
15
16
  import {HealthcheckDetails} from './Healthcheck/HealthcheckDetails';
16
17
  import {MetricsCards, type TenantMetrics} from './MetricsCards/MetricsCards';
17
18
  import {TenantStorage} from './TenantStorage/TenantStorage';
19
+ import {TenantMemory} from './TenantMemory/TenantMemory';
18
20
  import {useHealthcheck} from './useHealthcheck';
19
21
 
20
- import i18n from './i18n';
21
22
  import './TenantOverview.scss';
22
23
 
23
24
  const b = cn('tenant-overview');
@@ -25,9 +26,14 @@ const b = cn('tenant-overview');
25
26
  interface TenantOverviewProps {
26
27
  tenantName: string;
27
28
  additionalTenantProps?: AdditionalTenantsProps;
29
+ additionalNodesProps?: AdditionalNodesProps;
28
30
  }
29
31
 
30
- export function TenantOverview({tenantName, additionalTenantProps}: TenantOverviewProps) {
32
+ export function TenantOverview({
33
+ tenantName,
34
+ additionalTenantProps,
35
+ additionalNodesProps,
36
+ }: TenantOverviewProps) {
31
37
  const dispatch = useDispatch();
32
38
 
33
39
  const {
@@ -115,16 +121,23 @@ export function TenantOverview({tenantName, additionalTenantProps}: TenantOvervi
115
121
  const renderTabContent = () => {
116
122
  switch (metricsTab) {
117
123
  case TENANT_METRICS_TABS_IDS.cpu: {
118
- return i18n('label.under-development');
124
+ return <TenantCpu path={tenantName} additionalNodesProps={additionalNodesProps} />;
119
125
  }
120
126
  case TENANT_METRICS_TABS_IDS.storage: {
121
127
  return <TenantStorage tenantName={tenantName} metrics={storageMetrics} />;
122
128
  }
123
129
  case TENANT_METRICS_TABS_IDS.memory: {
124
- return i18n('label.under-development');
130
+ return <TenantMemory path={tenantName} />;
125
131
  }
126
132
  case TENANT_METRICS_TABS_IDS.healthcheck: {
127
- return <HealthcheckDetails issueTrees={issueTrees} error={healthcheckError} />;
133
+ return (
134
+ <HealthcheckDetails
135
+ issueTrees={issueTrees}
136
+ loading={healthcheckLoading}
137
+ wasLoaded={healthCheckWasLoaded}
138
+ error={healthcheckError}
139
+ />
140
+ );
128
141
  }
129
142
  default: {
130
143
  return undefined;
@@ -132,7 +145,7 @@ export function TenantOverview({tenantName, additionalTenantProps}: TenantOvervi
132
145
  }
133
146
  };
134
147
 
135
- if ((tenantLoading && !tenantWasLoaded) || (healthcheckLoading && !healthCheckWasLoaded)) {
148
+ if (tenantLoading && !tenantWasLoaded) {
136
149
  return (
137
150
  <div className={b('loader')}>
138
151
  <Loader size="m" />
@@ -142,19 +155,22 @@ export function TenantOverview({tenantName, additionalTenantProps}: TenantOvervi
142
155
 
143
156
  return (
144
157
  <div className={b()}>
145
- <div className={b('top-label')}>{tenantType}</div>
146
- <div className={b('top')}>
147
- {renderName()}
148
- {additionalTenantProps?.getMonitoringLink?.(Name, Type)}
158
+ <div className={b('info')}>
159
+ <div className={b('top-label')}>{tenantType}</div>
160
+ <div className={b('top')}>
161
+ {renderName()}
162
+ {additionalTenantProps?.getMonitoringLink?.(Name, Type)}
163
+ </div>
164
+ <MetricsCards
165
+ metrics={calculatedMetrics}
166
+ issuesStatistics={issuesStatistics}
167
+ selfCheckResult={selfCheckResult}
168
+ fetchHealthcheck={fetchHealthcheck}
169
+ healthcheckLoading={healthcheckLoading}
170
+ healthCheckWasLoaded={healthCheckWasLoaded}
171
+ healthcheckError={healthcheckError}
172
+ />
149
173
  </div>
150
- <MetricsCards
151
- metrics={calculatedMetrics}
152
- issuesStatistics={issuesStatistics}
153
- selfCheckResult={selfCheckResult}
154
- fetchHealthcheck={fetchHealthcheck}
155
- healthcheckLoading={healthcheckLoading}
156
- healthcheckError={healthcheckError}
157
- />
158
174
  {renderTabContent()}
159
175
  </div>
160
176
  );
@@ -0,0 +1,53 @@
1
+ import cn from 'bem-cn-lite';
2
+
3
+ import DataTable from '@gravity-ui/react-data-table';
4
+ import type {DataTableProps} from '@gravity-ui/react-data-table';
5
+
6
+ import {
7
+ TENANT_OVERVIEW_TABLES_LIMIT,
8
+ TENANT_OVERVIEW_TABLES_SETTINGS,
9
+ } from '../../../../utils/constants';
10
+ import type {IResponseError} from '../../../../types/api/error';
11
+ import {TableSkeleton} from '../../../../components/TableSkeleton/TableSkeleton';
12
+ import {ResponseError} from '../../../../components/Errors/ResponseError';
13
+
14
+ const b = cn('tenant-overview');
15
+
16
+ interface TenantOverviewTableLayoutProps<T> extends Omit<DataTableProps<T>, 'theme'> {
17
+ title: string;
18
+ loading?: boolean;
19
+ wasLoaded?: boolean;
20
+ error?: IResponseError;
21
+ tableClassNameModifiers?: {
22
+ [name: string]: string | boolean | undefined;
23
+ };
24
+ }
25
+
26
+ export function TenantOverviewTableLayout<T>({
27
+ title,
28
+ error,
29
+ loading,
30
+ wasLoaded,
31
+ tableClassNameModifiers = {},
32
+ ...props
33
+ }: TenantOverviewTableLayoutProps<T>) {
34
+ const renderContent = () => {
35
+ if (error) {
36
+ return <ResponseError error={error} />;
37
+ }
38
+
39
+ if (loading && !wasLoaded) {
40
+ return <TableSkeleton rows={TENANT_OVERVIEW_TABLES_LIMIT} />;
41
+ }
42
+
43
+ return (
44
+ <DataTable theme="yandex-cloud" settings={TENANT_OVERVIEW_TABLES_SETTINGS} {...props} />
45
+ );
46
+ };
47
+ return (
48
+ <>
49
+ <div className={b('title')}>{title}</div>
50
+ <div className={b('table', tableClassNameModifiers)}>{renderContent()}</div>
51
+ </>
52
+ );
53
+ }
@@ -1,4 +1,5 @@
1
1
  import {useDispatch} from 'react-redux';
2
+ import {useLocation} from 'react-router';
2
3
  import cn from 'bem-cn-lite';
3
4
 
4
5
  import DataTable, {Column} from '@gravity-ui/react-data-table';
@@ -17,6 +18,7 @@ import type {KeyValueRow} from '../../../../../types/api/query';
17
18
  import {formatBytes, getSizeWithSignificantDigits} from '../../../../../utils/bytesParsers';
18
19
  import {TableSkeleton} from '../../../../../components/TableSkeleton/TableSkeleton';
19
20
  import {ResponseError} from '../../../../../components/Errors/ResponseError';
21
+ import {LinkToSchemaObject} from '../../../../../components/LinkToSchemaObject/LinkToSchemaObject';
20
22
 
21
23
  import './TenantStorage.scss';
22
24
 
@@ -28,6 +30,7 @@ interface TopTablesProps {
28
30
 
29
31
  export function TopTables({path}: TopTablesProps) {
30
32
  const dispatch = useDispatch();
33
+ const location = useLocation();
31
34
 
32
35
  const {autorefresh} = useTypedSelector((state) => state.schema);
33
36
 
@@ -67,13 +70,18 @@ export function TopTables({path}: TopTablesProps) {
67
70
  {
68
71
  name: 'Path',
69
72
  sortable: false,
70
- render: ({row}) => (
71
- <div className={b('cell-with-popover-wrapper')}>
72
- <Popover className={b('cell-with-popover')} content={row.Path}>
73
- {row.Path}
74
- </Popover>
75
- </div>
76
- ),
73
+ render: ({row}) =>
74
+ row.Path ? (
75
+ <LinkToSchemaObject
76
+ className={b('cell-with-popover-wrapper')}
77
+ path={String(row.Path)}
78
+ location={location}
79
+ >
80
+ <Popover className={b('cell-with-popover')} content={row.Path}>
81
+ {row.Path}
82
+ </Popover>
83
+ </LinkToSchemaObject>
84
+ ) : null,
77
85
  },
78
86
  ];
79
87
 
@@ -2,10 +2,10 @@
2
2
  "no-data": "No data",
3
3
  "no-pools-data": "No pools data",
4
4
 
5
+ "top-nodes.empty-data": "No such nodes",
6
+
5
7
  "title.pools": "Pools",
6
8
  "title.metrics": "Metrics",
7
9
 
8
- "top-groups.empty-data": "No such groups",
9
-
10
- "label.under-development": "This section is under development"
10
+ "top-groups.empty-data": "No such groups"
11
11
  }
@@ -2,10 +2,10 @@
2
2
  "no-data": "Нет данных",
3
3
  "no-pools-data": "Нет данных о пулах",
4
4
 
5
+ "top-nodes.empty-data": "Нет узлов",
6
+
5
7
  "title.pools": "Пулы",
6
8
  "title.metrics": "Метрики",
7
9
 
8
- "top-groups.empty-data": "Нет групп",
9
-
10
- "label.under-development": "Этот раздел находится в разработке"
10
+ "top-groups.empty-data": "Нет групп"
11
11
  }
@@ -39,8 +39,6 @@
39
39
  &__query {
40
40
  overflow: hidden;
41
41
 
42
- width: 500px;
43
-
44
42
  vertical-align: top;
45
43
  white-space: pre-wrap;
46
44
  text-overflow: ellipsis;