ydb-embedded-ui 3.0.0 → 3.1.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.
- package/CHANGELOG.md +17 -0
- package/dist/components/ClusterInfo/ClusterInfo.tsx +1 -1
- package/dist/components/InfoViewer/InfoViewer.tsx +1 -1
- package/dist/components/InfoViewer/schemaInfo/CDCStreamInfo.tsx +5 -2
- package/dist/components/InfoViewer/schemaInfo/PersQueueGroupInfo.tsx +6 -5
- package/dist/components/InfoViewer/schemaInfo/TableIndexInfo.tsx +5 -2
- package/dist/components/ProblemFilter/ProblemFilter.tsx +18 -0
- package/dist/components/ProblemFilter/index.ts +1 -0
- package/dist/components/UptimeFIlter/UptimeFilter.tsx +4 -3
- package/dist/containers/Nodes/Nodes.js +2 -2
- package/dist/containers/NodesViewer/NodesViewer.js +2 -2
- package/dist/containers/Pool/Pool.js +2 -2
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +2 -3
- package/dist/containers/Tenant/Diagnostics/Network/Network.js +2 -2
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +11 -9
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +6 -3
- package/dist/containers/Tenant/Diagnostics/TopShards/DateRange/DateRange.scss +13 -0
- package/dist/containers/Tenant/Diagnostics/TopShards/DateRange/DateRange.tsx +75 -0
- package/dist/containers/Tenant/Diagnostics/TopShards/DateRange/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.scss +17 -1
- package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.tsx +278 -0
- package/dist/containers/Tenant/Diagnostics/TopShards/i18n/en.json +4 -0
- package/dist/containers/Tenant/Diagnostics/TopShards/i18n/index.ts +11 -0
- package/dist/containers/Tenant/Diagnostics/TopShards/i18n/ru.json +4 -0
- package/dist/containers/Tenant/Diagnostics/TopShards/index.ts +1 -0
- package/dist/containers/Tenant/Schema/SchemaInfoViewer/SchemaInfoViewer.js +35 -22
- package/dist/containers/Tenant/Schema/SchemaInfoViewer/SchemaInfoViewer.scss +8 -0
- package/dist/containers/Tenant/Tenant.tsx +1 -1
- package/dist/containers/Tenant/utils/index.ts +8 -0
- package/dist/containers/Tenant/utils/schema.ts +45 -0
- package/dist/containers/Tenants/Tenants.js +2 -2
- package/dist/services/api.d.ts +3 -0
- package/dist/services/api.js +1 -1
- package/dist/store/reducers/{nodes.js → nodes.ts} +20 -14
- package/dist/store/reducers/shardsWorkload.ts +182 -0
- package/dist/store/reducers/{tooltip.js → tooltip.ts} +28 -11
- package/dist/store/state-url-mapping.js +8 -0
- package/dist/types/api/nodes.ts +3 -3
- package/dist/types/api/schema.ts +1 -1
- package/dist/types/api/tenant.ts +131 -0
- package/dist/types/store/nodes.ts +32 -0
- package/dist/types/store/shardsWorkload.ts +28 -0
- package/dist/types/store/tooltip.ts +25 -0
- package/dist/utils/constants.ts +2 -0
- package/dist/utils/nodes.ts +4 -4
- package/dist/utils/query.ts +1 -1
- package/dist/utils/tooltip.js +8 -6
- package/package.json +2 -2
- package/dist/components/ProblemFilter/ProblemFilter.js +0 -24
- package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.js +0 -246
- package/dist/store/reducers/shardsWorkload.js +0 -101
- package/dist/utils/actionsConstants.js +0 -4
@@ -0,0 +1,278 @@
|
|
1
|
+
import {useState, useContext, useEffect, useMemo} from 'react';
|
2
|
+
import {useDispatch} from 'react-redux';
|
3
|
+
import cn from 'bem-cn-lite';
|
4
|
+
|
5
|
+
import DataTable, {Column, Settings, SortOrder} from '@yandex-cloud/react-data-table';
|
6
|
+
import {Loader} from '@gravity-ui/uikit';
|
7
|
+
|
8
|
+
import InternalLink from '../../../../components/InternalLink/InternalLink';
|
9
|
+
|
10
|
+
import HistoryContext from '../../../../contexts/HistoryContext';
|
11
|
+
|
12
|
+
import routes, {createHref} from '../../../../routes';
|
13
|
+
|
14
|
+
import {
|
15
|
+
sendShardQuery,
|
16
|
+
setShardQueryOptions,
|
17
|
+
setTopShardFilters,
|
18
|
+
} from '../../../../store/reducers/shardsWorkload';
|
19
|
+
import {setCurrentSchemaPath, getSchema} from '../../../../store/reducers/schema';
|
20
|
+
import type {IShardsWorkloadFilters} from '../../../../types/store/shardsWorkload';
|
21
|
+
|
22
|
+
import type {EPathType} from '../../../../types/api/schema';
|
23
|
+
|
24
|
+
import {formatDateTime, formatNumber} from '../../../../utils';
|
25
|
+
import {DEFAULT_TABLE_SETTINGS, HOUR_IN_SECONDS} from '../../../../utils/constants';
|
26
|
+
import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
|
27
|
+
import {prepareQueryError} from '../../../../utils/query';
|
28
|
+
|
29
|
+
import {getDefaultNodePath} from '../../../Node/NodePages';
|
30
|
+
|
31
|
+
import {isColumnEntityType} from '../../utils/schema';
|
32
|
+
|
33
|
+
import {DateRange, DateRangeValues} from './DateRange';
|
34
|
+
|
35
|
+
import i18n from './i18n';
|
36
|
+
import './TopShards.scss';
|
37
|
+
|
38
|
+
const b = cn('top-shards');
|
39
|
+
const bLink = cn('yc-link');
|
40
|
+
|
41
|
+
const TABLE_SETTINGS: Settings = {
|
42
|
+
...DEFAULT_TABLE_SETTINGS,
|
43
|
+
dynamicRender: false, // no more than 20 rows
|
44
|
+
externalSort: true,
|
45
|
+
disableSortReset: true,
|
46
|
+
defaultOrder: DataTable.DESCENDING,
|
47
|
+
};
|
48
|
+
|
49
|
+
const tableColumnsNames = {
|
50
|
+
TabletId: 'TabletId',
|
51
|
+
CPUCores: 'CPUCores',
|
52
|
+
DataSize: 'DataSize',
|
53
|
+
Path: 'Path',
|
54
|
+
NodeId: 'NodeId',
|
55
|
+
PeakTime: 'PeakTime',
|
56
|
+
InFlightTxCount: 'InFlightTxCount',
|
57
|
+
};
|
58
|
+
|
59
|
+
function prepareCPUWorkloadValue(value: string) {
|
60
|
+
return `${(Number(value) * 100).toFixed(2)}%`;
|
61
|
+
}
|
62
|
+
|
63
|
+
function stringToDataTableSortOrder(value: string): SortOrder[] | undefined {
|
64
|
+
return value
|
65
|
+
? value.split(',').map((columnId) => ({
|
66
|
+
columnId,
|
67
|
+
order: DataTable.DESCENDING,
|
68
|
+
}))
|
69
|
+
: undefined;
|
70
|
+
}
|
71
|
+
|
72
|
+
function stringToQuerySortOrder(value: string) {
|
73
|
+
return value
|
74
|
+
? value.split(',').map((columnId) => ({
|
75
|
+
columnId,
|
76
|
+
order: 'DESC',
|
77
|
+
}))
|
78
|
+
: undefined;
|
79
|
+
}
|
80
|
+
|
81
|
+
function dataTableToStringSortOrder(value: SortOrder | SortOrder[] = []) {
|
82
|
+
const sortOrders = Array.isArray(value) ? value : [value];
|
83
|
+
return sortOrders.map(({columnId}) => columnId).join(',');
|
84
|
+
}
|
85
|
+
|
86
|
+
interface TopShardsProps {
|
87
|
+
tenantPath: string;
|
88
|
+
type?: EPathType;
|
89
|
+
}
|
90
|
+
|
91
|
+
export const TopShards = ({tenantPath, type}: TopShardsProps) => {
|
92
|
+
const dispatch = useDispatch();
|
93
|
+
|
94
|
+
const {autorefresh, currentSchemaPath} = useTypedSelector((state) => state.schema);
|
95
|
+
|
96
|
+
const {
|
97
|
+
loading,
|
98
|
+
data: {result: data = undefined} = {},
|
99
|
+
filters: storeFilters,
|
100
|
+
error,
|
101
|
+
wasLoaded,
|
102
|
+
} = useTypedSelector((state) => state.shardsWorkload);
|
103
|
+
|
104
|
+
// default date range should be the last hour, but shouldn't propagate into URL until user interacts with the control
|
105
|
+
// redux initial value can't be used, as it synchronizes with URL
|
106
|
+
const [filters, setFilters] = useState<IShardsWorkloadFilters>(() => {
|
107
|
+
if (!storeFilters?.from && !storeFilters?.to) {
|
108
|
+
return {
|
109
|
+
from: Date.now() - HOUR_IN_SECONDS * 1000,
|
110
|
+
to: Date.now(),
|
111
|
+
};
|
112
|
+
}
|
113
|
+
|
114
|
+
return storeFilters;
|
115
|
+
});
|
116
|
+
|
117
|
+
const [sortOrder, setSortOrder] = useState(tableColumnsNames.CPUCores);
|
118
|
+
|
119
|
+
useAutofetcher(
|
120
|
+
() => {
|
121
|
+
dispatch(
|
122
|
+
sendShardQuery({
|
123
|
+
database: tenantPath,
|
124
|
+
path: currentSchemaPath,
|
125
|
+
sortOrder: stringToQuerySortOrder(sortOrder),
|
126
|
+
filters,
|
127
|
+
}),
|
128
|
+
);
|
129
|
+
},
|
130
|
+
[dispatch, tenantPath, currentSchemaPath, sortOrder, filters],
|
131
|
+
autorefresh,
|
132
|
+
);
|
133
|
+
|
134
|
+
// don't show loader for requests triggered by table sort, only for path change
|
135
|
+
useEffect(() => {
|
136
|
+
dispatch(
|
137
|
+
setShardQueryOptions({
|
138
|
+
wasLoaded: false,
|
139
|
+
data: undefined,
|
140
|
+
}),
|
141
|
+
);
|
142
|
+
}, [dispatch, currentSchemaPath, tenantPath, filters]);
|
143
|
+
|
144
|
+
const history = useContext(HistoryContext);
|
145
|
+
|
146
|
+
const onSort = (newSortOrder?: SortOrder | SortOrder[]) => {
|
147
|
+
// omit information about sort order to disable ASC order, only DESC makes sense for top shards
|
148
|
+
// use a string (and not the DataTable default format) to prevent reference change,
|
149
|
+
// which would cause an excess state change, to avoid repeating requests
|
150
|
+
setSortOrder(dataTableToStringSortOrder(newSortOrder));
|
151
|
+
};
|
152
|
+
|
153
|
+
const handleDateRangeChange = (value: DateRangeValues) => {
|
154
|
+
dispatch(setTopShardFilters(value));
|
155
|
+
setFilters(value);
|
156
|
+
};
|
157
|
+
|
158
|
+
const tableColumns: Column<any>[] = useMemo(() => {
|
159
|
+
const onSchemaClick = (schemaPath: string) => {
|
160
|
+
return () => {
|
161
|
+
dispatch(setCurrentSchemaPath(schemaPath));
|
162
|
+
dispatch(getSchema({path: schemaPath}));
|
163
|
+
history.go(0);
|
164
|
+
};
|
165
|
+
};
|
166
|
+
|
167
|
+
return [
|
168
|
+
{
|
169
|
+
name: tableColumnsNames.Path,
|
170
|
+
render: ({value: relativeNodePath}) => {
|
171
|
+
return (
|
172
|
+
<span
|
173
|
+
onClick={onSchemaClick(tenantPath + relativeNodePath)}
|
174
|
+
className={bLink({view: 'normal'})}
|
175
|
+
>
|
176
|
+
{relativeNodePath as string}
|
177
|
+
</span>
|
178
|
+
);
|
179
|
+
},
|
180
|
+
sortable: false,
|
181
|
+
},
|
182
|
+
{
|
183
|
+
name: tableColumnsNames.CPUCores,
|
184
|
+
render: ({value}) => {
|
185
|
+
return prepareCPUWorkloadValue(value as string);
|
186
|
+
},
|
187
|
+
align: DataTable.RIGHT,
|
188
|
+
},
|
189
|
+
{
|
190
|
+
name: tableColumnsNames.DataSize,
|
191
|
+
header: 'DataSize (B)',
|
192
|
+
render: ({value}) => {
|
193
|
+
return formatNumber(value as number);
|
194
|
+
},
|
195
|
+
align: DataTable.RIGHT,
|
196
|
+
},
|
197
|
+
{
|
198
|
+
name: tableColumnsNames.TabletId,
|
199
|
+
render: ({value}) => {
|
200
|
+
return (
|
201
|
+
<InternalLink to={createHref(routes.tablet, {id: value})}>
|
202
|
+
{value as string}
|
203
|
+
</InternalLink>
|
204
|
+
);
|
205
|
+
},
|
206
|
+
sortable: false,
|
207
|
+
},
|
208
|
+
{
|
209
|
+
name: tableColumnsNames.NodeId,
|
210
|
+
render: ({value: nodeId}) => {
|
211
|
+
return (
|
212
|
+
<InternalLink to={getDefaultNodePath(nodeId as string)}>
|
213
|
+
{nodeId as string}
|
214
|
+
</InternalLink>
|
215
|
+
);
|
216
|
+
},
|
217
|
+
align: DataTable.RIGHT,
|
218
|
+
sortable: false,
|
219
|
+
},
|
220
|
+
{
|
221
|
+
name: tableColumnsNames.PeakTime,
|
222
|
+
render: ({value}) => formatDateTime(new Date(value as string).valueOf()),
|
223
|
+
sortable: false,
|
224
|
+
},
|
225
|
+
{
|
226
|
+
name: tableColumnsNames.InFlightTxCount,
|
227
|
+
render: ({value}) => formatNumber(value as number),
|
228
|
+
align: DataTable.RIGHT,
|
229
|
+
sortable: false,
|
230
|
+
},
|
231
|
+
];
|
232
|
+
}, [dispatch, history, tenantPath]);
|
233
|
+
|
234
|
+
const renderLoader = () => {
|
235
|
+
return (
|
236
|
+
<div className={b('loader')}>
|
237
|
+
<Loader size="m" />
|
238
|
+
</div>
|
239
|
+
);
|
240
|
+
};
|
241
|
+
|
242
|
+
const renderContent = () => {
|
243
|
+
if (loading && !wasLoaded) {
|
244
|
+
return renderLoader();
|
245
|
+
}
|
246
|
+
|
247
|
+
if (error && !error.isCancelled) {
|
248
|
+
return <div className="error">{prepareQueryError(error)}</div>;
|
249
|
+
}
|
250
|
+
|
251
|
+
if (!data || isColumnEntityType(type)) {
|
252
|
+
return i18n('no-data');
|
253
|
+
}
|
254
|
+
|
255
|
+
return (
|
256
|
+
<div className={b('table')}>
|
257
|
+
<DataTable
|
258
|
+
columns={tableColumns}
|
259
|
+
data={data}
|
260
|
+
settings={TABLE_SETTINGS}
|
261
|
+
theme="yandex-cloud"
|
262
|
+
onSort={onSort}
|
263
|
+
sortOrder={stringToDataTableSortOrder(sortOrder)}
|
264
|
+
/>
|
265
|
+
</div>
|
266
|
+
);
|
267
|
+
};
|
268
|
+
|
269
|
+
return (
|
270
|
+
<div className={b()}>
|
271
|
+
<div className={b('controls')}>
|
272
|
+
{i18n('description')}
|
273
|
+
<DateRange from={filters.from} to={filters.to} onChange={handleDateRangeChange} />
|
274
|
+
</div>
|
275
|
+
{renderContent()}
|
276
|
+
</div>
|
277
|
+
);
|
278
|
+
};
|
@@ -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-diagnostics-top-shards';
|
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 @@
|
|
1
|
+
export * from './TopShards';
|
@@ -1,12 +1,15 @@
|
|
1
1
|
import React from 'react';
|
2
2
|
import PropTypes from 'prop-types';
|
3
3
|
import cn from 'bem-cn-lite';
|
4
|
-
import './SchemaInfoViewer.scss';
|
5
4
|
|
6
5
|
import {formatCPU, formatBytes, formatNumber, formatBps, formatDateTime} from '../../../../utils';
|
7
6
|
|
8
7
|
import {InfoViewer, createInfoFormatter} from '../../../../components/InfoViewer';
|
9
8
|
|
9
|
+
import {getEntityName} from '../../utils';
|
10
|
+
|
11
|
+
import './SchemaInfoViewer.scss';
|
12
|
+
|
10
13
|
const b = cn('schema-info-viewer');
|
11
14
|
|
12
15
|
const formatTabletMetricsItem = createInfoFormatter({
|
@@ -68,6 +71,8 @@ class SchemaInfoViewer extends React.Component {
|
|
68
71
|
|
69
72
|
renderContent(data) {
|
70
73
|
const {PathDescription = {}} = data;
|
74
|
+
const entityName = getEntityName(PathDescription);
|
75
|
+
|
71
76
|
const {
|
72
77
|
TableStats = {},
|
73
78
|
TabletMetrics = {},
|
@@ -99,13 +104,15 @@ class SchemaInfoViewer extends React.Component {
|
|
99
104
|
} = TableStats;
|
100
105
|
const {FollowerGroups, FollowerCount, CrossDataCenterFollowerCount} = PartitionConfig;
|
101
106
|
|
107
|
+
const generalTableInfo = formatTableStats({
|
108
|
+
PartCount,
|
109
|
+
RowCount,
|
110
|
+
DataSize,
|
111
|
+
IndexSize,
|
112
|
+
...restTableStats,
|
113
|
+
});
|
114
|
+
|
102
115
|
const tableStatsInfo = [
|
103
|
-
formatTableStats({
|
104
|
-
PartCount,
|
105
|
-
RowCount,
|
106
|
-
DataSize,
|
107
|
-
IndexSize,
|
108
|
-
}),
|
109
116
|
formatTableStats({
|
110
117
|
LastAccessTime,
|
111
118
|
LastUpdateTime,
|
@@ -125,7 +132,6 @@ class SchemaInfoViewer extends React.Component {
|
|
125
132
|
RangeReads,
|
126
133
|
RangeReadRows,
|
127
134
|
}),
|
128
|
-
formatTableStats(restTableStats),
|
129
135
|
];
|
130
136
|
|
131
137
|
const tabletMetricsInfo = Object.keys(TabletMetrics).map((key) =>
|
@@ -151,24 +157,30 @@ class SchemaInfoViewer extends React.Component {
|
|
151
157
|
);
|
152
158
|
}
|
153
159
|
|
154
|
-
if (
|
155
|
-
|
160
|
+
if (
|
161
|
+
[generalTableInfo, tabletMetricsInfo, partitionConfigInfo, tableStatsInfo.flat()].flat()
|
162
|
+
.length === 0
|
163
|
+
) {
|
164
|
+
return <div className={b('title')}>{entityName}</div>;
|
156
165
|
}
|
157
166
|
|
158
167
|
return (
|
159
|
-
<div
|
160
|
-
{
|
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}
|
161
177
|
<div className={b('col')}>
|
162
|
-
{
|
163
|
-
|
178
|
+
{tableStatsInfo.map((info, index) => (
|
179
|
+
<React.Fragment key={index}>
|
180
|
+
{this.renderItem(info, index === 0 ? 'Table Stats' : undefined)}
|
181
|
+
</React.Fragment>
|
182
|
+
))}
|
164
183
|
</div>
|
165
|
-
) : null}
|
166
|
-
<div className={b('col')}>
|
167
|
-
{tableStatsInfo.map((info, index) => (
|
168
|
-
<React.Fragment key={index}>
|
169
|
-
{this.renderItem(info, index === 0 ? 'Table Stats' : undefined)}
|
170
|
-
</React.Fragment>
|
171
|
-
))}
|
172
184
|
</div>
|
173
185
|
</div>
|
174
186
|
);
|
@@ -176,11 +188,12 @@ class SchemaInfoViewer extends React.Component {
|
|
176
188
|
|
177
189
|
render() {
|
178
190
|
const {data} = this.props;
|
191
|
+
const entityName = getEntityName(data?.PathDescription);
|
179
192
|
|
180
193
|
if (data) {
|
181
194
|
return <div className={b()}>{this.renderContent(data)}</div>;
|
182
195
|
} else {
|
183
|
-
return <div className="error">
|
196
|
+
return <div className="error">No {entityName} data</div>;
|
184
197
|
}
|
185
198
|
}
|
186
199
|
}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import {TPathDescription} from '../../../types/api/schema';
|
2
|
+
import {mapPathTypeToEntityName} from './schema';
|
3
|
+
|
4
|
+
export const getEntityName = (pathDescription?: TPathDescription) => {
|
5
|
+
const {PathType, PathSubType} = pathDescription?.Self || {};
|
6
|
+
|
7
|
+
return mapPathTypeToEntityName(PathType, PathSubType);
|
8
|
+
};
|
@@ -1,5 +1,7 @@
|
|
1
1
|
import type {NavigationTreeNodeType} from 'ydb-ui-components';
|
2
|
+
|
2
3
|
import {EPathSubType, EPathType} from '../../../types/api/schema';
|
4
|
+
import {ETenantType} from '../../../types/api/tenant';
|
3
5
|
|
4
6
|
// this file contains verbose mappings that are typed in a way that ensures
|
5
7
|
// correctness when a new node type or a new path type is added
|
@@ -41,6 +43,49 @@ export const mapPathTypeToNavigationTreeType = (
|
|
41
43
|
|
42
44
|
// ====================
|
43
45
|
|
46
|
+
const pathSubTypeToEntityName: Record<EPathSubType, string | undefined> = {
|
47
|
+
[EPathSubType.EPathSubTypeSyncIndexImplTable]: 'Secondary Index Table',
|
48
|
+
[EPathSubType.EPathSubTypeAsyncIndexImplTable]: 'Secondary Index Table',
|
49
|
+
|
50
|
+
[EPathSubType.EPathSubTypeStreamImpl]: undefined,
|
51
|
+
[EPathSubType.EPathSubTypeEmpty]: undefined,
|
52
|
+
};
|
53
|
+
|
54
|
+
const pathTypeToEntityName: Record<EPathType, string | undefined> = {
|
55
|
+
[EPathType.EPathTypeInvalid]: undefined,
|
56
|
+
|
57
|
+
[EPathType.EPathTypeSubDomain]: 'Database',
|
58
|
+
[EPathType.EPathTypeExtSubDomain]: 'Database',
|
59
|
+
|
60
|
+
[EPathType.EPathTypeDir]: 'Directory',
|
61
|
+
[EPathType.EPathTypeTable]: 'Table',
|
62
|
+
[EPathType.EPathTypeTableIndex]: 'Secondary Index',
|
63
|
+
[EPathType.EPathTypeColumnStore]: 'Tablestore',
|
64
|
+
[EPathType.EPathTypeColumnTable]: 'Columntable',
|
65
|
+
[EPathType.EPathTypeCdcStream]: 'Changefeed',
|
66
|
+
[EPathType.EPathTypePersQueueGroup]: 'Topic',
|
67
|
+
};
|
68
|
+
|
69
|
+
export const mapPathTypeToEntityName = (
|
70
|
+
type?: EPathType,
|
71
|
+
subType?: EPathSubType,
|
72
|
+
): string | undefined =>
|
73
|
+
(subType && pathSubTypeToEntityName[subType]) || (type && pathTypeToEntityName[type]);
|
74
|
+
|
75
|
+
// ====================
|
76
|
+
|
77
|
+
const databaseTypeToDBName: Record<ETenantType, string | undefined> = {
|
78
|
+
[ETenantType.UnknownTenantType]: 'Database',
|
79
|
+
[ETenantType.Domain]: 'Cluster Root',
|
80
|
+
[ETenantType.Dedicated]: 'Dedicated Database',
|
81
|
+
[ETenantType.Shared]: 'Shared Database',
|
82
|
+
[ETenantType.Serverless]: 'Serverless Database',
|
83
|
+
};
|
84
|
+
|
85
|
+
export const mapDatabaseTypeToDBName = (type?: ETenantType) => type && databaseTypeToDBName[type];
|
86
|
+
|
87
|
+
// ====================
|
88
|
+
|
44
89
|
const pathTypeToIsTable: Record<EPathType, boolean> = {
|
45
90
|
[EPathType.EPathTypeTable]: true,
|
46
91
|
[EPathType.EPathTypeColumnTable]: true,
|
@@ -10,7 +10,7 @@ import {Loader, TextInput, Button} from '@gravity-ui/uikit';
|
|
10
10
|
import EntityStatus from '../../components/EntityStatus/EntityStatus';
|
11
11
|
import PoolsGraph from '../../components/PoolsGraph/PoolsGraph';
|
12
12
|
import TabletsStatistic from '../../components/TabletsStatistic/TabletsStatistic';
|
13
|
-
import ProblemFilter
|
13
|
+
import {ProblemFilter} from '../../components/ProblemFilter';
|
14
14
|
import {Illustration} from '../../components/Illustration';
|
15
15
|
import {AutoFetcher} from '../../utils/autofetcher';
|
16
16
|
|
@@ -50,7 +50,7 @@ class Tenants extends React.Component {
|
|
50
50
|
searchQuery: PropTypes.string,
|
51
51
|
handleSearchQuery: PropTypes.func,
|
52
52
|
setHeader: PropTypes.func,
|
53
|
-
filter:
|
53
|
+
filter: PropTypes.string,
|
54
54
|
changeFilter: PropTypes.func,
|
55
55
|
cluster: PropTypes.object,
|
56
56
|
singleClusterMode: PropTypes.bool,
|
package/dist/services/api.d.ts
CHANGED
@@ -45,6 +45,9 @@ interface Window {
|
|
45
45
|
getHealthcheckInfo: (
|
46
46
|
database: string,
|
47
47
|
) => Promise<import('../types/api/healthcheck').HealthCheckAPIResponse>;
|
48
|
+
getTenantInfo: (params: {
|
49
|
+
path: string;
|
50
|
+
}) => Promise<import('../types/api/tenant').TTenantInfo>;
|
48
51
|
[method: string]: Function;
|
49
52
|
};
|
50
53
|
}
|
package/dist/services/api.js
CHANGED
@@ -1,8 +1,12 @@
|
|
1
|
-
import {
|
1
|
+
import type {Reducer} from 'redux';
|
2
|
+
|
2
3
|
import '../../services/api';
|
3
4
|
import {NodesUptimeFilterValues} from '../../utils/nodes';
|
5
|
+
import {INodesAction, INodesRootStateSlice, INodesState} from '../../types/store/nodes';
|
6
|
+
|
7
|
+
import {createRequestActionTypes, createApiRequest} from '../utils';
|
4
8
|
|
5
|
-
const FETCH_NODES = createRequestActionTypes('nodes', 'FETCH_NODES');
|
9
|
+
export const FETCH_NODES = createRequestActionTypes('nodes', 'FETCH_NODES');
|
6
10
|
|
7
11
|
const CLEAR_NODES = 'nodes/CLEAR_NODES';
|
8
12
|
const SET_NODES_UPTIME_FILTER = 'nodes/SET_NODES_UPTIME_FILTER';
|
@@ -14,13 +18,12 @@ const initialState = {
|
|
14
18
|
nodesUptimeFilter: NodesUptimeFilterValues.All,
|
15
19
|
};
|
16
20
|
|
17
|
-
const nodes = (state = initialState, action) => {
|
21
|
+
const nodes: Reducer<INodesState, INodesAction> = (state = initialState, action) => {
|
18
22
|
switch (action.type) {
|
19
23
|
case FETCH_NODES.REQUEST: {
|
20
24
|
return {
|
21
25
|
...state,
|
22
26
|
loading: true,
|
23
|
-
requestTime: new Date().getTime(),
|
24
27
|
};
|
25
28
|
}
|
26
29
|
case FETCH_NODES.SUCCESS: {
|
@@ -45,13 +48,15 @@ const nodes = (state = initialState, action) => {
|
|
45
48
|
loading: true,
|
46
49
|
data: undefined,
|
47
50
|
wasLoaded: false,
|
48
|
-
requestTime: new Date().getTime(),
|
49
51
|
error: undefined,
|
50
52
|
};
|
51
53
|
}
|
52
54
|
|
53
55
|
case SET_NODES_UPTIME_FILTER: {
|
54
|
-
return {
|
56
|
+
return {
|
57
|
+
...state,
|
58
|
+
nodesUptimeFilter: action.data,
|
59
|
+
};
|
55
60
|
}
|
56
61
|
case SET_DATA_WAS_NOT_LOADED: {
|
57
62
|
return {
|
@@ -64,26 +69,27 @@ const nodes = (state = initialState, action) => {
|
|
64
69
|
}
|
65
70
|
};
|
66
71
|
|
67
|
-
export function getNodes(path) {
|
72
|
+
export function getNodes(path: string) {
|
68
73
|
return createApiRequest({
|
69
74
|
request: window.api.getNodes(path),
|
70
75
|
actions: FETCH_NODES,
|
71
76
|
});
|
72
77
|
}
|
73
78
|
|
74
|
-
export const clearNodes = () => ({type: CLEAR_NODES});
|
79
|
+
export const clearNodes = () => ({type: CLEAR_NODES} as const);
|
75
80
|
|
76
|
-
export const setNodesUptimeFilter = (value) =>
|
77
|
-
|
78
|
-
|
79
|
-
|
81
|
+
export const setNodesUptimeFilter = (value: NodesUptimeFilterValues) =>
|
82
|
+
({
|
83
|
+
type: SET_NODES_UPTIME_FILTER,
|
84
|
+
data: value,
|
85
|
+
} as const);
|
80
86
|
|
81
87
|
export const setDataWasNotLoaded = () => {
|
82
88
|
return {
|
83
89
|
type: SET_DATA_WAS_NOT_LOADED,
|
84
|
-
};
|
90
|
+
} as const;
|
85
91
|
};
|
86
92
|
|
87
|
-
export const getNodesUptimeFilter = (state) => state.nodes.nodesUptimeFilter;
|
93
|
+
export const getNodesUptimeFilter = (state: INodesRootStateSlice) => state.nodes.nodesUptimeFilter;
|
88
94
|
|
89
95
|
export default nodes;
|