Skip to content

Commit deaf519

Browse files
authored
feat(ObjectSummary): add link to Schema in Diagnostics (#1323)
1 parent b53487e commit deaf519

File tree

10 files changed

+182
-96
lines changed

10 files changed

+182
-96
lines changed

src/containers/Tenant/Diagnostics/DiagnosticsPages.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,9 @@ export const CDC_STREAM_PAGES = [overview, consumers, partitions, nodes, tablets
9898
export const TOPIC_PAGES = [overview, consumers, partitions, nodes, tablets, describe];
9999

100100
export const EXTERNAL_DATA_SOURCE_PAGES = [overview, describe];
101-
export const EXTERNAL_TABLE_PAGES = [overview, describe];
101+
export const EXTERNAL_TABLE_PAGES = [overview, schema, describe];
102102

103-
export const VIEW_PAGES = [overview, describe];
103+
export const VIEW_PAGES = [overview, schema, describe];
104104

105105
// verbose mapping to guarantee correct tabs for new path types
106106
// TS will error when a new type is added but not mapped here

src/containers/Tenant/ObjectSummary/ObjectSummary.scss

+6-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
@import '../../../styles/mixins.scss';
22

3-
.object-summary {
3+
.ydb-object-summary {
44
position: relative;
55

66
display: flex;
@@ -64,14 +64,13 @@
6464
padding: 8px 12px 16px;
6565
}
6666

67-
&__tab {
68-
margin-right: 40px;
67+
&__tabs-inner {
68+
--g-tabs-border-width: 0;
69+
box-shadow: inset 0 -1px 0 0 var(--g-color-line-generic);
70+
}
6971

72+
&__tab {
7073
text-decoration: none;
71-
72-
&:first-letter {
73-
text-transform: uppercase;
74-
}
7574
}
7675

7776
&__info {

src/containers/Tenant/ObjectSummary/ObjectSummary.tsx

+51-84
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22

33
import {HelpPopover} from '@gravity-ui/components';
4-
import {Tabs} from '@gravity-ui/uikit';
4+
import {Flex, Tabs} from '@gravity-ui/uikit';
55
import qs from 'qs';
66
import {Link, useLocation} from 'react-router-dom';
77
import {StringParam, useQueryParam} from 'use-query-params';
@@ -12,14 +12,12 @@ import {toFormattedSize} from '../../../components/FormattedBytes/utils';
1212
import {InfoViewer} from '../../../components/InfoViewer/InfoViewer';
1313
import type {InfoViewerItem} from '../../../components/InfoViewer/InfoViewer';
1414
import {LinkWithIcon} from '../../../components/LinkWithIcon/LinkWithIcon';
15-
import {Loader} from '../../../components/Loader';
1615
import SplitPane from '../../../components/SplitPane';
1716
import routes, {createExternalUILink, createHref} from '../../../routes';
1817
import {useGetSchemaQuery} from '../../../store/reducers/schema/schema';
1918
import {TENANT_SUMMARY_TABS_IDS} from '../../../store/reducers/tenant/constants';
2019
import {setSummaryTab} from '../../../store/reducers/tenant/tenant';
2120
import {EPathSubType, EPathType} from '../../../types/api/schema';
22-
import {cn} from '../../../utils/cn';
2321
import {
2422
DEFAULT_IS_TENANT_COMMON_INFO_COLLAPSED,
2523
DEFAULT_SIZE_TENANT_SUMMARY_KEY,
@@ -32,10 +30,8 @@ import {
3230
import {useTypedDispatch, useTypedSelector} from '../../../utils/hooks';
3331
import {Acl} from '../Acl/Acl';
3432
import {EntityTitle} from '../EntityTitle/EntityTitle';
35-
import {SchemaTree} from '../Schema/SchemaTree/SchemaTree';
3633
import {SchemaViewer} from '../Schema/SchemaViewer/SchemaViewer';
3734
import {TENANT_INFO_TABS, TENANT_SCHEMA_TAB, TenantTabsGroups} from '../TenantPages';
38-
import i18n from '../i18n';
3935
import {getSummaryControls} from '../utils/controls';
4036
import {
4137
PaneVisibilityActionTypes,
@@ -44,12 +40,14 @@ import {
4440
} from '../utils/paneVisibilityToggleHelpers';
4541
import {isIndexTableType, isTableType} from '../utils/schema';
4642

43+
import {ObjectTree} from './ObjectTree';
44+
import {SchemaActions} from './SchemaActions';
45+
import i18n from './i18n';
46+
import {b} from './shared';
4747
import {transformPath} from './transformPath';
4848

4949
import './ObjectSummary.scss';
5050

51-
const b = cn('object-summary');
52-
5351
const getTenantCommonInfoState = () => {
5452
const collapsed = Boolean(localStorage.getItem(DEFAULT_IS_TENANT_COMMON_INFO_COLLAPSED));
5553

@@ -113,24 +111,31 @@ export function ObjectSummary({
113111

114112
return (
115113
<div className={b('tabs')}>
116-
<Tabs
117-
size="l"
118-
items={tabsItems}
119-
activeTab={summaryTab}
120-
wrapTo={({id}, node) => {
121-
const path = createHref(routes.tenant, undefined, {
122-
...queryParams,
123-
name: tenantName,
124-
[TenantTabsGroups.summaryTab]: id,
125-
});
126-
return (
127-
<Link to={path} key={id} className={b('tab')}>
128-
{node}
129-
</Link>
130-
);
131-
}}
132-
allowNotSelected
133-
/>
114+
<Flex
115+
className={b('tabs-inner')}
116+
justifyContent="space-between"
117+
alignItems="center"
118+
>
119+
<Tabs
120+
size="l"
121+
items={tabsItems}
122+
activeTab={summaryTab}
123+
wrapTo={({id}, node) => {
124+
const path = createHref(routes.tenant, undefined, {
125+
...queryParams,
126+
name: tenantName,
127+
[TenantTabsGroups.summaryTab]: id,
128+
});
129+
return (
130+
<Link to={path} key={id} className={b('tab')}>
131+
{node}
132+
</Link>
133+
);
134+
}}
135+
allowNotSelected
136+
/>
137+
{summaryTab === TENANT_SUMMARY_TABS_IDS.schema && <SchemaActions />}
138+
</Flex>
134139
</div>
135140
);
136141
};
@@ -143,21 +148,21 @@ export function ObjectSummary({
143148

144149
const overview: InfoViewerItem[] = [];
145150

146-
overview.push({label: i18n('summary.type'), value: PathType?.replace(/^EPathType/, '')});
151+
overview.push({label: i18n('field_type'), value: PathType?.replace(/^EPathType/, '')});
147152

148153
if (PathSubType !== EPathSubType.EPathSubTypeEmpty) {
149154
overview.push({
150-
label: i18n('summary.subtype'),
155+
label: i18n('field_subtype'),
151156
value: PathSubType?.replace(/^EPathSubType/, ''),
152157
});
153158
}
154159

155-
overview.push({label: i18n('summary.id'), value: PathId});
160+
overview.push({label: i18n('field_id'), value: PathId});
156161

157-
overview.push({label: i18n('summary.version'), value: PathVersion});
162+
overview.push({label: i18n('field_version'), value: PathVersion});
158163

159164
overview.push({
160-
label: i18n('summary.created'),
165+
label: i18n('field_created'),
161166
value: formatDateTime(CreateStep),
162167
});
163168

@@ -168,11 +173,11 @@ export function ObjectSummary({
168173

169174
overview.push(
170175
{
171-
label: i18n('summary.data-size'),
176+
label: i18n('field_data-size'),
172177
value: toFormattedSize(DataSize),
173178
},
174179
{
175-
label: i18n('summary.row-count'),
180+
label: i18n('field_row-count'),
176181
value: formatNumber(RowCount),
177182
},
178183
);
@@ -196,11 +201,11 @@ export function ObjectSummary({
196201

197202
return [
198203
{
199-
label: i18n('summary.paths'),
204+
label: i18n('field_paths'),
200205
value: paths,
201206
},
202207
{
203-
label: i18n('summary.shards'),
208+
label: i18n('field_shards'),
204209
value: shards,
205210
},
206211
];
@@ -211,7 +216,7 @@ export function ObjectSummary({
211216
[EPathType.EPathTypeDir]: undefined,
212217
[EPathType.EPathTypeTable]: () => [
213218
{
214-
label: i18n('summary.partitions'),
219+
label: i18n('field_partitions'),
215220
value: PathDescription?.TablePartitions?.length,
216221
},
217222
],
@@ -220,13 +225,13 @@ export function ObjectSummary({
220225
[EPathType.EPathTypeExtSubDomain]: getDatabaseOverview,
221226
[EPathType.EPathTypeColumnStore]: () => [
222227
{
223-
label: i18n('summary.partitions'),
228+
label: i18n('field_partitions'),
224229
value: PathDescription?.ColumnStoreDescription?.ColumnShards?.length,
225230
},
226231
],
227232
[EPathType.EPathTypeColumnTable]: () => [
228233
{
229-
label: i18n('summary.partitions'),
234+
label: i18n('field_partitions'),
230235
value: PathDescription?.ColumnTableDescription?.Sharding?.ColumnShards?.length,
231236
},
232237
],
@@ -235,11 +240,11 @@ export function ObjectSummary({
235240

236241
return [
237242
{
238-
label: i18n('summary.mode'),
243+
label: i18n('field_mode'),
239244
value: Mode?.replace(/^ECdcStreamMode/, ''),
240245
},
241246
{
242-
label: i18n('summary.format'),
247+
label: i18n('field_format'),
243248
value: Format?.replace(/^ECdcStreamFormat/, ''),
244249
},
245250
];
@@ -250,11 +255,11 @@ export function ObjectSummary({
250255

251256
return [
252257
{
253-
label: i18n('summary.partitions'),
258+
label: i18n('field_partitions'),
254259
value: pqGroup?.Partitions?.length,
255260
},
256261
{
257-
label: i18n('summary.retention'),
262+
label: i18n('field_retention'),
258263
value: value && formatSecondsToHours(value),
259264
},
260265
];
@@ -271,9 +276,9 @@ export function ObjectSummary({
271276
const dataSourceName = DataSourcePath?.match(/([^/]*)\/*$/)?.[1] || '';
272277

273278
return [
274-
{label: i18n('summary.source-type'), value: SourceType},
279+
{label: i18n('field_source-type'), value: SourceType},
275280
{
276-
label: i18n('summary.data-source'),
281+
label: i18n('field_data-source'),
277282
value: DataSourcePath && (
278283
<span title={DataSourcePath}>
279284
<LinkWithIcon title={dataSourceName || ''} url={pathToDataSource} />
@@ -284,7 +289,7 @@ export function ObjectSummary({
284289
},
285290
[EPathType.EPathTypeExternalDataSource]: () => [
286291
{
287-
label: i18n('summary.source-type'),
292+
label: i18n('field_source-type'),
288293
value: PathDescription?.ExternalDataSourceDescription?.SourceType,
289294
},
290295
],
@@ -298,7 +303,7 @@ export function ObjectSummary({
298303

299304
return [
300305
{
301-
label: i18n('summary.state'),
306+
label: i18n('field_state'),
302307
value: <AsyncReplicationState state={state} />,
303308
},
304309
];
@@ -351,7 +356,7 @@ export function ObjectSummary({
351356
<ClipboardButton
352357
text={path}
353358
view="flat-secondary"
354-
title={i18n('summary.copySchemaPath')}
359+
title={i18n('action_copySchemaPath')}
355360
/>
356361
<PaneVisibilityToggleButtons
357362
onCollapse={onCollapseInfoHandler}
@@ -426,41 +431,3 @@ export function ObjectSummary({
426431

427432
return renderContent();
428433
}
429-
430-
function ObjectTree({tenantName, path}: {tenantName: string; path?: string}) {
431-
const {data: tenantData = {}, isLoading} = useGetSchemaQuery({
432-
path: tenantName,
433-
database: tenantName,
434-
});
435-
const pathData = tenantData?.PathDescription?.Self;
436-
437-
const [, setCurrentPath] = useQueryParam('schema', StringParam);
438-
439-
if (!pathData && isLoading) {
440-
// If Loader isn't wrapped with div, SplitPane doesn't calculate panes height correctly
441-
return (
442-
<div>
443-
<Loader />
444-
</div>
445-
);
446-
}
447-
448-
return (
449-
<div className={b('tree-wrapper')}>
450-
<div className={b('tree-header')}>{i18n('summary.navigation')}</div>
451-
<div className={b('tree')}>
452-
{pathData ? (
453-
<SchemaTree
454-
rootPath={tenantName}
455-
// for the root pathData.Name contains the same string as tenantName,
456-
// but without the leading slash
457-
rootName={pathData.Name || tenantName}
458-
rootType={pathData.PathType}
459-
currentPath={path}
460-
onActivePathUpdate={setCurrentPath}
461-
/>
462-
) : null}
463-
</div>
464-
</div>
465-
);
466-
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import {StringParam, useQueryParam} from 'use-query-params';
2+
3+
import {Loader} from '../../../components/Loader';
4+
import {useGetSchemaQuery} from '../../../store/reducers/schema/schema';
5+
import {SchemaTree} from '../Schema/SchemaTree/SchemaTree';
6+
7+
import i18n from './i18n';
8+
import {b} from './shared';
9+
10+
interface ObjectTreeProps {
11+
tenantName: string;
12+
path?: string;
13+
}
14+
15+
export function ObjectTree({tenantName, path}: ObjectTreeProps) {
16+
const {data: tenantData = {}, isLoading} = useGetSchemaQuery({
17+
path: tenantName,
18+
database: tenantName,
19+
});
20+
const pathData = tenantData?.PathDescription?.Self;
21+
22+
const [, setCurrentPath] = useQueryParam('schema', StringParam);
23+
24+
if (!pathData && isLoading) {
25+
// If Loader isn't wrapped with div, SplitPane doesn't calculate panes height correctly
26+
return (
27+
<div>
28+
<Loader />
29+
</div>
30+
);
31+
}
32+
33+
return (
34+
<div className={b('tree-wrapper')}>
35+
<div className={b('tree-header')}>{i18n('title_navigation')}</div>
36+
<div className={b('tree')}>
37+
{pathData ? (
38+
<SchemaTree
39+
rootPath={tenantName}
40+
// for the root pathData.Name contains the same string as tenantName,
41+
// but without the leading slash
42+
rootName={pathData.Name || tenantName}
43+
rootType={pathData.PathType}
44+
currentPath={path}
45+
onActivePathUpdate={setCurrentPath}
46+
/>
47+
) : null}
48+
</div>
49+
</div>
50+
);
51+
}

0 commit comments

Comments
 (0)