ydb-embedded-ui 3.3.1 → 3.3.3

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 (58) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/components/Errors/ResponseError/ResponseError.tsx +17 -0
  3. package/dist/components/Errors/ResponseError/index.ts +1 -0
  4. package/dist/components/Errors/i18n/en.json +2 -1
  5. package/dist/components/Errors/i18n/ru.json +2 -1
  6. package/dist/components/FullGroupViewer/FullGroupViewer.js +1 -1
  7. package/dist/components/InfoViewer/InfoViewer.scss +1 -1
  8. package/dist/components/InfoViewer/InfoViewer.tsx +29 -21
  9. package/dist/components/InfoViewer/formatters/index.ts +1 -0
  10. package/dist/components/InfoViewer/formatters/table.ts +40 -0
  11. package/dist/components/QueryExecutionStatus/QueryExecutionStatus.tsx +26 -8
  12. package/dist/components/QueryExecutionStatus/index.ts +1 -0
  13. package/dist/components/QueryResultTable/QueryResultTable.tsx +2 -2
  14. package/dist/containers/App/Content.js +12 -5
  15. package/dist/containers/AsideNavigation/AsideNavigation.tsx +10 -13
  16. package/dist/containers/Authentication/Authentication.scss +6 -0
  17. package/dist/containers/Authentication/Authentication.tsx +34 -15
  18. package/dist/containers/Node/NodeStructure/Pdisk.tsx +7 -10
  19. package/dist/containers/Nodes/Nodes.tsx +1 -1
  20. package/dist/containers/Nodes/getNodesColumns.tsx +4 -4
  21. package/dist/containers/Storage/PDisk/PDisk.tsx +25 -17
  22. package/dist/containers/Storage/PDisk/__tests__/colors.tsx +64 -1
  23. package/dist/containers/Storage/Storage.js +1 -1
  24. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +4 -3
  25. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +1 -1
  26. package/dist/containers/Storage/VDisk/VDisk.tsx +1 -1
  27. package/dist/containers/Storage/utils/index.ts +26 -10
  28. package/dist/containers/Tablet/Tablet.js +1 -1
  29. package/dist/containers/Tenant/Acl/Acl.js +1 -1
  30. package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +2 -2
  31. package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +1 -1
  32. package/dist/containers/Tenant/Diagnostics/OverloadedShards/OverloadedShards.tsx +6 -1
  33. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +10 -21
  34. package/dist/containers/Tenant/{Schema/SchemaInfoViewer/SchemaInfoViewer.scss → Diagnostics/Overview/TableInfo/TableInfo.scss} +8 -10
  35. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/TableInfo.tsx +71 -0
  36. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/i18n/en.json +5 -0
  37. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/i18n/index.ts +11 -0
  38. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/i18n/ru.json +5 -0
  39. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/index.ts +1 -0
  40. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.ts +96 -0
  41. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +7 -1
  42. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +3 -1
  43. package/dist/containers/Tenant/QueryEditor/QueryEditor.js +8 -3
  44. package/dist/containers/Tenant/QueryEditor/QueryExplain/QueryExplain.js +16 -11
  45. package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.js +37 -23
  46. package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.scss +4 -0
  47. package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.js +1 -1
  48. package/dist/containers/Tenants/Tenants.js +4 -3
  49. package/dist/routes.ts +1 -0
  50. package/dist/services/api.js +4 -1
  51. package/dist/store/reducers/shardsWorkload.ts +2 -1
  52. package/dist/store/reducers/storage.js +1 -1
  53. package/dist/utils/constants.ts +1 -1
  54. package/dist/utils/index.js +3 -1
  55. package/dist/utils/prepareQueryExplain.ts +1 -1
  56. package/package.json +5 -3
  57. package/dist/containers/Tenant/Diagnostics/Overview/Overview.scss +0 -13
  58. package/dist/containers/Tenant/Schema/SchemaInfoViewer/SchemaInfoViewer.js +0 -201
@@ -91,6 +91,8 @@ const initialTenantCommonInfoState = {
91
91
  function QueryEditor(props) {
92
92
  const [resultType, setResultType] = useState(RESULT_TYPES.EXECUTE);
93
93
 
94
+ const [isResultLoaded, setIsResultLoaded] = useState(false);
95
+
94
96
  const [resultVisibilityState, dispatchResultVisibilityState] = useReducer(
95
97
  paneVisibilityToggleReducerCreator(DEFAULT_IS_QUERY_RESULT_COLLAPSED),
96
98
  initialTenantCommonInfoState,
@@ -117,11 +119,12 @@ function QueryEditor(props) {
117
119
  }, []);
118
120
 
119
121
  useEffect(() => {
120
- const {showPreview} = props;
121
- if (showPreview && resultVisibilityState.collapsed) {
122
+ if (props.showPreview || isResultLoaded) {
122
123
  dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerExpand);
124
+ } else {
125
+ dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerCollapse);
123
126
  }
124
- }, [props.showPreview, resultVisibilityState.collapsed]);
127
+ }, [props.showPreview, isResultLoaded]);
125
128
 
126
129
  useEffect(() => {
127
130
  const {
@@ -254,6 +257,7 @@ function QueryEditor(props) {
254
257
 
255
258
  setResultType(RESULT_TYPES.EXECUTE);
256
259
  sendQuery({query: input, database: path, action: runAction});
260
+ setIsResultLoaded(true);
257
261
  setShowPreview(false);
258
262
 
259
263
  const {queries, currentIndex} = history;
@@ -272,6 +276,7 @@ function QueryEditor(props) {
272
276
  } = props;
273
277
  setResultType(RESULT_TYPES.EXPLAIN);
274
278
  getExplainQuery({query: input, database: path});
279
+ setIsResultLoaded(true);
275
280
  setShowPreview(false);
276
281
  dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerExpand);
277
282
  };
@@ -1,28 +1,33 @@
1
1
  import React, {useEffect, useRef, useState} from 'react';
2
+ import {useDispatch, useSelector} from 'react-redux';
2
3
  import cn from 'bem-cn-lite';
3
4
  import MonacoEditor from 'react-monaco-editor';
4
- import {Loader, RadioButton} from '@gravity-ui/uikit';
5
5
  import JSONTree from 'react-json-inspector';
6
- import {LANGUAGE_S_EXPRESSION_ID} from '../../../../utils/monaco';
6
+ import 'react-json-inspector/json-inspector.css';
7
+
7
8
  import {
8
9
  TextOverflow,
9
10
  getYdbPlanNodeShape,
10
11
  getCompactTopology,
11
12
  getTopology,
12
- } from '@yandex-cloud/paranoid';
13
- import {renderExplainNode} from '../../../../utils';
14
- import {explainVersions} from '../../../../store/reducers/explainQuery';
15
- import QueryExecutionStatus from '../../../../components/QueryExecutionStatus/QueryExecutionStatus';
13
+ } from '@gravity-ui/paranoid';
14
+ import {Loader, RadioButton} from '@gravity-ui/uikit';
15
+
16
16
  import Divider from '../../../../components/Divider/Divider';
17
17
  import EnableFullscreenButton from '../../../../components/EnableFullscreenButton/EnableFullscreenButton';
18
- import {PaneVisibilityToggleButtons} from '../../utils/paneVisibilityToggleHelpers';
19
18
  import Fullscreen from '../../../../components/Fullscreen/Fullscreen';
19
+ import {QueryExecutionStatus} from '../../../../components/QueryExecutionStatus';
20
20
 
21
- import 'react-json-inspector/json-inspector.css';
22
- import './QueryExplain.scss';
23
- import {useDispatch, useSelector} from 'react-redux';
21
+ import {explainVersions} from '../../../../store/reducers/explainQuery';
24
22
  import {disableFullscreen} from '../../../../store/reducers/fullscreen';
25
23
 
24
+ import {renderExplainNode} from '../../../../utils';
25
+ import {LANGUAGE_S_EXPRESSION_ID} from '../../../../utils/monaco';
26
+
27
+ import {PaneVisibilityToggleButtons} from '../../utils/paneVisibilityToggleHelpers';
28
+
29
+ import './QueryExplain.scss';
30
+
26
31
  const b = cn('kv-query-explain');
27
32
 
28
33
  const EDITOR_OPTIONS = {
@@ -263,7 +268,7 @@ function QueryExplain(props) {
263
268
  {!props.loading && (
264
269
  <React.Fragment>
265
270
  <div className={b('controls-right')}>
266
- <QueryExecutionStatus hasError={Boolean(props.error)} />
271
+ <QueryExecutionStatus error={props.error} />
267
272
  {!props.error && (
268
273
  <React.Fragment>
269
274
  <Divider />
@@ -1,20 +1,26 @@
1
1
  import React, {useEffect, useState} from 'react';
2
2
  import {useDispatch, useSelector} from 'react-redux';
3
3
  import cn from 'bem-cn-lite';
4
- import {RadioButton} from '@gravity-ui/uikit';
5
4
  import JSONTree from 'react-json-inspector';
6
5
 
6
+ import {RadioButton} from '@gravity-ui/uikit';
7
+
7
8
  import CopyToClipboard from '../../../../components/CopyToClipboard/CopyToClipboard';
8
9
  import Divider from '../../../../components/Divider/Divider';
10
+ import EnableFullscreenButton from '../../../../components/EnableFullscreenButton/EnableFullscreenButton';
9
11
  import Fullscreen from '../../../../components/Fullscreen/Fullscreen';
12
+ import {QueryExecutionStatus} from '../../../../components/QueryExecutionStatus';
13
+
10
14
  import {disableFullscreen} from '../../../../store/reducers/fullscreen';
11
15
 
12
- import './QueryResult.scss';
16
+ import {prepareQueryError} from '../../../../utils/query';
17
+
13
18
  import {PaneVisibilityToggleButtons} from '../../utils/paneVisibilityToggleHelpers';
14
- import QueryExecutionStatus from '../../../../components/QueryExecutionStatus/QueryExecutionStatus';
15
- import EnableFullscreenButton from '../../../../components/EnableFullscreenButton/EnableFullscreenButton';
19
+
16
20
  import ResultIssues from '../Issues/Issues';
17
21
 
22
+ import './QueryResult.scss';
23
+
18
24
  const b = cn('kv-query-result');
19
25
 
20
26
  const resultOptionsIds = {
@@ -94,31 +100,39 @@ function QueryResult(props) {
94
100
  };
95
101
 
96
102
  const renderIssues = () => {
97
- const error = props.error?.data;
98
-
99
- const hasIssues = error?.issues && Array.isArray(error.issues);
100
-
101
- return hasIssues ? (
102
- <React.Fragment>
103
- <ResultIssues data={error} />
104
- {isFullscreen && (
105
- <Fullscreen>
106
- <div className={b('result', {fullscreen: true})}>
107
- <ResultIssues data={error} />
108
- </div>
109
- </Fullscreen>
110
- )}
111
- </React.Fragment>
112
- ) : (
113
- <span>{error?.data ?? error}</span>
114
- );
103
+ const error = props.error;
104
+
105
+ const hasIssues = error?.data?.issues && Array.isArray(error.data.issues);
106
+
107
+ if (hasIssues) {
108
+ return (
109
+ <React.Fragment>
110
+ <ResultIssues data={error.data} />
111
+ {isFullscreen && (
112
+ <Fullscreen>
113
+ <div className={b('result', {fullscreen: true})}>
114
+ <ResultIssues data={error.data} />
115
+ </div>
116
+ </Fullscreen>
117
+ )}
118
+ </React.Fragment>
119
+ )
120
+ }
121
+
122
+ if (error) {
123
+ return (
124
+ <div className={b('error')}>
125
+ {prepareQueryError(error)}
126
+ </div>
127
+ );
128
+ }
115
129
  };
116
130
 
117
131
  return (
118
132
  <React.Fragment>
119
133
  <div className={b('controls')}>
120
134
  <div className={b('controls-right')}>
121
- <QueryExecutionStatus hasError={Boolean(props.error)} />
135
+ <QueryExecutionStatus error={props.error} />
122
136
 
123
137
  {props.stats && !props.error && (
124
138
  <React.Fragment>
@@ -20,6 +20,10 @@
20
20
  }
21
21
  }
22
22
 
23
+ &__error {
24
+ padding: 15px 10px;
25
+ }
26
+
23
27
  &__controls {
24
28
  position: sticky;
25
29
  z-index: 2;
@@ -5,7 +5,7 @@ import cn from 'bem-cn-lite';
5
5
  import find from 'lodash/find';
6
6
 
7
7
  import Icon from '../../../../components/Icon/Icon';
8
- import DataTable from '@yandex-cloud/react-data-table';
8
+ import DataTable from '@gravity-ui/react-data-table';
9
9
  import {DEFAULT_TABLE_SETTINGS} from '../../../../utils/constants';
10
10
  import './SchemaViewer.scss';
11
11
 
@@ -5,7 +5,7 @@ import {connect} from 'react-redux';
5
5
  import _ from 'lodash';
6
6
  import {escapeRegExp} from 'lodash/fp';
7
7
 
8
- import DataTable from '@yandex-cloud/react-data-table';
8
+ import DataTable from '@gravity-ui/react-data-table';
9
9
  import {Loader, TextInput, Button} from '@gravity-ui/uikit';
10
10
 
11
11
  import EntityStatus from '../../components/EntityStatus/EntityStatus';
@@ -218,8 +218,9 @@ class Tenants extends React.Component {
218
218
  },
219
219
  accessor: ({Metrics = {}, CoresUsed}) => {
220
220
  if (!isNaN(Number(CoresUsed))) {
221
- const cores = Math.round(Number(CoresUsed) * 100) / 100;
222
- return cores || '—';
221
+ return Number(CoresUsed) * 100 > 1
222
+ ? formatCPU(Number(CoresUsed) * 1_000_000)
223
+ : '—';
223
224
  } else {
224
225
  return Number(Metrics.CPU) ? formatCPU(Number(Metrics.CPU)) : '—';
225
226
  }
package/dist/routes.ts CHANGED
@@ -16,6 +16,7 @@ const routes = {
16
16
  tablet: '/tablet/:id',
17
17
  tabletsFilters: '/tabletsFilters',
18
18
  clusterPage: '/clusters/:name',
19
+ auth: '/auth',
19
20
  };
20
21
 
21
22
  export const CLUSTER_PAGES = {
@@ -185,7 +185,10 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
185
185
  timeout: 600000,
186
186
  },
187
187
  null,
188
- {concurrentId},
188
+ {
189
+ concurrentId,
190
+ timeout: 9 * 60 * 1000,
191
+ },
189
192
  );
190
193
  }
191
194
  getExplainQuery(query, database) {
@@ -77,7 +77,8 @@ function createShardQuery(
77
77
  DataSize,
78
78
  NodeId,
79
79
  PeakTime,
80
- InFlightTxCount
80
+ InFlightTxCount,
81
+ IntervalEnd
81
82
  FROM \`.sys/top_partitions_one_hour\`
82
83
  WHERE ${where}
83
84
  ${orderBy}
@@ -420,7 +420,7 @@ export const getUsageFilterOptions = createSelector(getVisibleEntitiesList, (ent
420
420
  entities.forEach((entity) => {
421
421
  const usage = getUsage(entity, 5);
422
422
 
423
- if (!Object.hasOwn(items, usage)) {
423
+ if (!Object.prototype.hasOwnProperty.call(items, usage)) {
424
424
  items[usage] = 0;
425
425
  }
426
426
 
@@ -1,4 +1,4 @@
1
- import DataTable from '@yandex-cloud/react-data-table';
1
+ import DataTable from '@gravity-ui/react-data-table';
2
2
 
3
3
  const SECOND = 1000;
4
4
 
@@ -1,6 +1,8 @@
1
1
  import numeral from 'numeral';
2
2
  import locales from 'numeral/locales'; // eslint-disable-line no-unused-vars
3
3
 
4
+ import {dateTimeParse} from '@gravity-ui/date-utils';
5
+
4
6
  import {i18n} from './i18n';
5
7
  import {MEGABYTE, TERABYTE, GIGABYTE, DAY_IN_SECONDS} from './constants';
6
8
  import {isNumeric} from './utils';
@@ -76,7 +78,7 @@ export const formatDateTime = (value) => {
76
78
  return '';
77
79
  }
78
80
 
79
- return value > 0 ? new Date(Number(value)).toUTCString() : 'N/A';
81
+ return value > 0 ? dateTimeParse(Number(value)).format('YYYY-MM-DD HH:mm') : 'N/A';
80
82
  };
81
83
 
82
84
  export const calcUptimeInSeconds = (milliseconds) => {
@@ -5,7 +5,7 @@ import {
5
5
  TopologyNodeDataStatsSection,
6
6
  ExplainPlanNodeData,
7
7
  TopologyNodeDataStatsItem,
8
- } from '@yandex-cloud/paranoid';
8
+ } from '@gravity-ui/paranoid';
9
9
 
10
10
  interface PlanOperator {
11
11
  Name: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "3.3.1",
3
+ "version": "3.3.3",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -10,10 +10,11 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "@gravity-ui/axios-wrapper": "^1.3.0",
13
+ "@gravity-ui/date-utils": "^1.1.1",
13
14
  "@gravity-ui/i18n": "^1.0.0",
14
15
  "@gravity-ui/navigation": "^0.3.1",
15
- "@yandex-cloud/paranoid": "^1.3.0",
16
- "@yandex-cloud/react-data-table": "^1.0.2",
16
+ "@gravity-ui/paranoid": "^1.4.0",
17
+ "@gravity-ui/react-data-table": "^1.0.3",
17
18
  "axios": "0.19.2",
18
19
  "bem-cn-lite": "4.0.0",
19
20
  "history": "4.10.1",
@@ -107,6 +108,7 @@
107
108
  "@testing-library/react": "^11.2.7",
108
109
  "@testing-library/user-event": "^12.8.3",
109
110
  "@types/lodash": "^4.14.178",
111
+ "@types/numeral": "^2.0.2",
110
112
  "@types/qs": "^6.9.7",
111
113
  "@types/react": "^17.0.44",
112
114
  "@types/react-dom": "^17.0.11",
@@ -1,13 +0,0 @@
1
- .kv-tenant-overview {
2
- &__title {
3
- margin: 0;
4
- margin-bottom: 15px;
5
-
6
- font-weight: 600;
7
- }
8
- &__loader {
9
- display: flex;
10
- flex-grow: 1;
11
- justify-content: center;
12
- }
13
- }
@@ -1,201 +0,0 @@
1
- import React from 'react';
2
- import PropTypes from 'prop-types';
3
- import cn from 'bem-cn-lite';
4
-
5
- import {formatCPU, formatBytes, formatNumber, formatBps, formatDateTime} from '../../../../utils';
6
-
7
- import {InfoViewer, createInfoFormatter} from '../../../../components/InfoViewer';
8
-
9
- import {getEntityName} from '../../utils';
10
-
11
- import './SchemaInfoViewer.scss';
12
-
13
- const b = cn('schema-info-viewer');
14
-
15
- const formatTabletMetricsItem = createInfoFormatter({
16
- values: {
17
- CPU: formatCPU,
18
- Memory: formatBytes,
19
- Storage: formatBytes,
20
- Network: formatBps,
21
- ReadThroughput: formatBps,
22
- WriteThroughput: formatBps,
23
- },
24
- defaultValueFormatter: formatNumber,
25
- });
26
-
27
- const formatFollowerGroupItem = createInfoFormatter({
28
- values: {
29
- FollowerCount: formatNumber,
30
- },
31
- });
32
-
33
- const formatPartitionConfigItem = createInfoFormatter({
34
- values: {
35
- FollowerCount: formatNumber,
36
- CrossDataCenterFollowerCount: formatNumber,
37
- },
38
- });
39
-
40
- const formatTableStatsItem = createInfoFormatter({
41
- values: {
42
- DataSize: formatBytes,
43
- IndexSize: formatBytes,
44
- LastAccessTime: formatDateTime,
45
- LastUpdateTime: formatDateTime,
46
- },
47
- defaultValueFormatter: formatNumber,
48
- });
49
-
50
- const formatTableStats = (fields) =>
51
- Object.entries(fields)
52
- .map(([label, value]) => formatTableStatsItem(label, value))
53
- .filter(({value}) => Boolean(value));
54
-
55
- class SchemaInfoViewer extends React.Component {
56
- static propTypes = {
57
- data: PropTypes.object.isRequired,
58
- };
59
-
60
- renderItem(itemData, title) {
61
- if (!Array.isArray(itemData) || !itemData.length) {
62
- return null;
63
- }
64
-
65
- return (
66
- <div className={b('item')}>
67
- <InfoViewer title={title} info={itemData} />
68
- </div>
69
- );
70
- }
71
-
72
- renderContent(data) {
73
- const {PathDescription = {}} = data;
74
- const entityName = getEntityName(PathDescription);
75
-
76
- const {
77
- TableStats = {},
78
- TabletMetrics = {},
79
- Table: {PartitionConfig = {}} = {},
80
- } = PathDescription;
81
- const {
82
- PartCount,
83
- RowCount,
84
- DataSize,
85
- IndexSize,
86
-
87
- LastAccessTime,
88
- LastUpdateTime,
89
-
90
- ImmediateTxCompleted,
91
- PlannedTxCompleted,
92
- TxRejectedByOverload,
93
- TxRejectedBySpace,
94
- TxCompleteLagMsec,
95
- InFlightTxCount,
96
-
97
- RowUpdates,
98
- RowDeletes,
99
- RowReads,
100
- RangeReads,
101
- RangeReadRows,
102
-
103
- ...restTableStats
104
- } = TableStats;
105
- const {FollowerGroups, FollowerCount, CrossDataCenterFollowerCount} = PartitionConfig;
106
-
107
- const generalTableInfo = formatTableStats({
108
- PartCount,
109
- RowCount,
110
- DataSize,
111
- IndexSize,
112
- ...restTableStats,
113
- });
114
-
115
- const tableStatsInfo = [
116
- formatTableStats({
117
- LastAccessTime,
118
- LastUpdateTime,
119
- }),
120
- formatTableStats({
121
- ImmediateTxCompleted,
122
- PlannedTxCompleted,
123
- TxRejectedByOverload,
124
- TxRejectedBySpace,
125
- TxCompleteLagMsec,
126
- InFlightTxCount,
127
- }),
128
- formatTableStats({
129
- RowUpdates,
130
- RowDeletes,
131
- RowReads,
132
- RangeReads,
133
- RangeReadRows,
134
- }),
135
- ];
136
-
137
- const tabletMetricsInfo = Object.keys(TabletMetrics).map((key) =>
138
- formatTabletMetricsItem(key, TabletMetrics[key]),
139
- );
140
-
141
- const partitionConfigInfo = [];
142
-
143
- if (Array.isArray(FollowerGroups) && FollowerGroups.length > 0) {
144
- partitionConfigInfo.push(
145
- ...Object.keys(FollowerGroups[0]).map((key) =>
146
- formatFollowerGroupItem(key, FollowerGroups[0][key]),
147
- ),
148
- );
149
- } else if (FollowerCount !== undefined) {
150
- partitionConfigInfo.push(formatPartitionConfigItem('FollowerCount', FollowerCount));
151
- } else if (CrossDataCenterFollowerCount !== undefined) {
152
- partitionConfigInfo.push(
153
- formatPartitionConfigItem(
154
- 'CrossDataCenterFollowerCount',
155
- CrossDataCenterFollowerCount,
156
- ),
157
- );
158
- }
159
-
160
- if (
161
- [generalTableInfo, tabletMetricsInfo, partitionConfigInfo, tableStatsInfo.flat()].flat()
162
- .length === 0
163
- ) {
164
- return <div className={b('title')}>{entityName}</div>;
165
- }
166
-
167
- return (
168
- <div>
169
- <div>{this.renderItem(generalTableInfo, entityName)}</div>
170
- <div className={b('row')}>
171
- {tabletMetricsInfo.length > 0 || partitionConfigInfo.length > 0 ? (
172
- <div className={b('col')}>
173
- {this.renderItem(tabletMetricsInfo, 'Tablet Metrics')}
174
- {this.renderItem(partitionConfigInfo, 'Partition Config')}
175
- </div>
176
- ) : null}
177
- <div className={b('col')}>
178
- {tableStatsInfo.map((info, index) => (
179
- <React.Fragment key={index}>
180
- {this.renderItem(info, index === 0 ? 'Table Stats' : undefined)}
181
- </React.Fragment>
182
- ))}
183
- </div>
184
- </div>
185
- </div>
186
- );
187
- }
188
-
189
- render() {
190
- const {data} = this.props;
191
- const entityName = getEntityName(data?.PathDescription);
192
-
193
- if (data) {
194
- return <div className={b()}>{this.renderContent(data)}</div>;
195
- } else {
196
- return <div className="error">No {entityName} data</div>;
197
- }
198
- }
199
- }
200
-
201
- export default SchemaInfoViewer;