Skip to content

Commit 3a10460

Browse files
feat(SchemaViewer): refactor, add view schema (#910)
1 parent e71fad9 commit 3a10460

File tree

13 files changed

+453
-258
lines changed

13 files changed

+453
-258
lines changed

src/containers/Tenant/Diagnostics/Diagnostics.tsx

+8-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,14 @@ function Diagnostics(props: DiagnosticsProps) {
104104
);
105105
}
106106
case TENANT_DIAGNOSTICS_TABS_IDS.schema: {
107-
return <SchemaViewer path={currentSchemaPath} type={type} withFamilies />;
107+
return (
108+
<SchemaViewer
109+
path={currentSchemaPath}
110+
tenantName={tenantName}
111+
type={type}
112+
extended
113+
/>
114+
);
108115
}
109116
case TENANT_DIAGNOSTICS_TABS_IDS.topQueries: {
110117
return <TopQueries path={tenantNameString} type={type} />;

src/containers/Tenant/ObjectSummary/ObjectSummary.tsx

+9-9
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ import {
4545
PaneVisibilityToggleButtons,
4646
paneVisibilityToggleReducerCreator,
4747
} from '../utils/paneVisibilityToggleHelpers';
48-
import {isIndexTableType, isTableType, isViewType} from '../utils/schema';
48+
import {isIndexTableType, isTableType} from '../utils/schema';
4949

5050
import './ObjectSummary.scss';
5151

@@ -64,6 +64,7 @@ const getTenantCommonInfoState = () => {
6464
interface ObjectSummaryProps {
6565
type?: EPathType;
6666
subType?: EPathSubType;
67+
tenantName?: string;
6768
onCollapseSummary: VoidFunction;
6869
onExpandSummary: VoidFunction;
6970
isCollapsed: boolean;
@@ -72,6 +73,7 @@ interface ObjectSummaryProps {
7273
export function ObjectSummary({
7374
type,
7475
subType,
76+
tenantName,
7577
onCollapseSummary,
7678
onExpandSummary,
7779
isCollapsed,
@@ -97,24 +99,20 @@ export function ObjectSummary({
9799
ignoreQueryPrefix: true,
98100
});
99101

100-
const {name: tenantName} = queryParams;
101-
102102
const pathData = tenantName ? data[tenantName.toString()]?.PathDescription?.Self : undefined;
103103
const currentObjectData = currentSchemaPath ? data[currentSchemaPath] : undefined;
104104
const currentSchemaData = currentObjectData?.PathDescription?.Self;
105105

106106
React.useEffect(() => {
107-
// TODO: enable schema tab for view when supported
108-
const isTable = isTableType(type) && !isViewType(type);
107+
const isTable = isTableType(type);
109108

110109
if (type && !isTable && !TENANT_INFO_TABS.find((el) => el.id === summaryTab)) {
111110
dispatch(setSummaryTab(TENANT_SUMMARY_TABS_IDS.overview));
112111
}
113112
}, [dispatch, type, summaryTab]);
114113

115114
const renderTabs = () => {
116-
// TODO: enable schema tab for view when supported
117-
const isTable = isTableType(type) && !isViewType(type);
115+
const isTable = isTableType(type);
118116
const tabsItems = isTable ? [...TENANT_INFO_TABS, ...TENANT_SCHEMA_TAB] : TENANT_INFO_TABS;
119117

120118
return (
@@ -126,7 +124,7 @@ export function ObjectSummary({
126124
wrapTo={({id}, node) => {
127125
const path = createHref(routes.tenant, undefined, {
128126
...queryParams,
129-
name: tenantName as string,
127+
name: tenantName,
130128
[TenantTabsGroups.summaryTab]: id,
131129
});
132130
return (
@@ -218,7 +216,9 @@ export function ObjectSummary({
218216
return <Acl />;
219217
}
220218
case TENANT_SUMMARY_TABS_IDS.schema: {
221-
return <SchemaViewer type={type} path={currentSchemaPath} />;
219+
return (
220+
<SchemaViewer type={type} path={currentSchemaPath} tenantName={tenantName} />
221+
);
222222
}
223223
default: {
224224
return renderObjectOverview();
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,94 @@
1+
import React from 'react';
2+
13
import DataTable from '@gravity-ui/react-data-table';
4+
import {skipToken} from '@reduxjs/toolkit/query';
25

36
import {ResizeableDataTable} from '../../../../components/ResizeableDataTable/ResizeableDataTable';
47
import {TableSkeleton} from '../../../../components/TableSkeleton/TableSkeleton';
8+
import {viewSchemaApi} from '../../../../store/reducers/viewSchema/viewSchema';
59
import type {EPathType} from '../../../../types/api/schema';
6-
import {cn} from '../../../../utils/cn';
710
import {DEFAULT_TABLE_SETTINGS} from '../../../../utils/constants';
811
import {useTypedSelector} from '../../../../utils/hooks';
12+
import {
13+
isColumnEntityType,
14+
isExternalTableType,
15+
isRowTableType,
16+
isViewType,
17+
} from '../../utils/schema';
918

1019
import {
1120
SCHEMA_COLUMNS_WIDTH_LS_KEY,
12-
SchemaViewerColumns,
13-
prepareColumnDescriptions,
14-
prepareFamilies,
15-
prepareSchemaTableColumns,
16-
} from './helpers';
21+
SCHEMA_TABLE_COLUMS_IDS,
22+
getColumnTableColumns,
23+
getExternalTableColumns,
24+
getRowTableColumns,
25+
getViewColumns,
26+
} from './columns';
27+
import {prepareSchemaData, prepareViewSchema} from './prepareData';
28+
import {b} from './shared';
1729

1830
import './SchemaViewer.scss';
1931

20-
const b = cn('schema-viewer');
21-
2232
interface SchemaViewerProps {
2333
type?: EPathType;
2434
path?: string;
25-
withFamilies?: boolean;
35+
tenantName?: string | null;
36+
extended?: boolean;
2637
}
2738

28-
export const SchemaViewer = ({type, path, withFamilies = false}: SchemaViewerProps) => {
29-
const {data, loading} = useTypedSelector((state) => state.schema);
30-
const currentObjectData = path ? data[path] : undefined;
31-
32-
const {columns, keyColumnIds} = prepareColumnDescriptions(type, currentObjectData);
33-
const families = prepareFamilies(currentObjectData);
34-
35-
return (
36-
<div className={b(null)}>
37-
{loading ? (
38-
<TableSkeleton />
39-
) : (
40-
<ResizeableDataTable
41-
columnsWidthLSKey={SCHEMA_COLUMNS_WIDTH_LS_KEY}
42-
data={columns}
43-
columns={prepareSchemaTableColumns({
44-
type,
45-
b,
46-
families,
47-
keyColumnIds,
48-
withFamilies,
49-
})}
50-
settings={DEFAULT_TABLE_SETTINGS}
51-
initialSortOrder={{
52-
columnId: SchemaViewerColumns.key,
53-
order: DataTable.ASCENDING,
54-
}}
55-
/>
56-
)}
57-
</div>
58-
);
39+
export const SchemaViewer = ({type, path, tenantName, extended = false}: SchemaViewerProps) => {
40+
const {data: schemaData, loading} = useTypedSelector((state) => state.schema);
41+
const currentObjectData = path ? schemaData[path] : undefined;
42+
43+
const viewSchemaRequestParams =
44+
isViewType(type) && path && tenantName ? {path, database: tenantName} : skipToken;
45+
46+
const {data: viewColumnsData, isLoading: isViewSchemaLoading} =
47+
viewSchemaApi.useGetViewSchemaQuery(viewSchemaRequestParams);
48+
49+
const tableData = React.useMemo(() => {
50+
if (isViewType(type)) {
51+
return prepareViewSchema(viewColumnsData);
52+
}
53+
54+
return prepareSchemaData(type, currentObjectData);
55+
}, [currentObjectData, type, viewColumnsData]);
56+
57+
const columns = React.useMemo(() => {
58+
if (isViewType(type)) {
59+
return getViewColumns();
60+
}
61+
if (isExternalTableType(type)) {
62+
return getExternalTableColumns();
63+
}
64+
if (isColumnEntityType(type)) {
65+
return getColumnTableColumns();
66+
}
67+
if (isRowTableType(type)) {
68+
return getRowTableColumns(extended);
69+
}
70+
71+
return [];
72+
}, [type, extended]);
73+
74+
const renderContent = () => {
75+
if (loading || isViewSchemaLoading) {
76+
return <TableSkeleton />;
77+
}
78+
79+
return (
80+
<ResizeableDataTable
81+
columnsWidthLSKey={SCHEMA_COLUMNS_WIDTH_LS_KEY}
82+
data={tableData}
83+
columns={columns}
84+
settings={DEFAULT_TABLE_SETTINGS}
85+
initialSortOrder={{
86+
columnId: SCHEMA_TABLE_COLUMS_IDS.isKeyColumn,
87+
order: DataTable.ASCENDING,
88+
}}
89+
/>
90+
);
91+
};
92+
93+
return <div className={b(null)}>{renderContent()}</div>;
5994
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import DataTable from '@gravity-ui/react-data-table';
2+
import {Icon} from '@gravity-ui/uikit';
3+
4+
import i18n from './i18n';
5+
import {b} from './shared';
6+
import type {SchemaColumn, SchemaData} from './types';
7+
8+
import keyIcon from '../../../../assets/icons/key.svg';
9+
10+
export const SCHEMA_COLUMNS_WIDTH_LS_KEY = 'schemaTableColumnsWidth';
11+
12+
export const SCHEMA_TABLE_COLUMS_IDS = {
13+
id: 'id',
14+
name: 'name',
15+
isKeyColumn: 'isKeyColumn',
16+
type: 'type',
17+
notNull: 'notNull',
18+
familyName: 'familyName',
19+
prefferedPoolKind: 'prefferedPoolKind',
20+
columnCodec: 'columnCodec',
21+
} satisfies Record<string, keyof SchemaData>;
22+
23+
const idColumn: SchemaColumn = {
24+
name: SCHEMA_TABLE_COLUMS_IDS.id,
25+
get header() {
26+
return i18n('column-title.id');
27+
},
28+
width: 60,
29+
render: ({row}) => row.id,
30+
};
31+
const nameColumn: SchemaColumn = {
32+
name: SCHEMA_TABLE_COLUMS_IDS.name,
33+
get header() {
34+
return i18n('column-title.name');
35+
},
36+
width: 100,
37+
render: ({row}) => row.name,
38+
};
39+
const keyColumn: SchemaColumn = {
40+
name: SCHEMA_TABLE_COLUMS_IDS.isKeyColumn,
41+
get header() {
42+
return i18n('column-title.key');
43+
},
44+
width: 70,
45+
resizeMinWidth: 70,
46+
// Table should start with key columns on sort click
47+
defaultOrder: DataTable.ASCENDING,
48+
sortAccessor: (row) => row.keyAccessor,
49+
render: ({row}) => {
50+
return row.isKeyColumn ? (
51+
<div className={b('key-icon')}>
52+
<Icon data={keyIcon} width={12} height={7} />
53+
</div>
54+
) : null;
55+
},
56+
};
57+
const typeColumn: SchemaColumn = {
58+
name: SCHEMA_TABLE_COLUMS_IDS.type,
59+
get header() {
60+
return i18n('column-title.type');
61+
},
62+
width: 100,
63+
render: ({row}) => row.type,
64+
};
65+
const notNullColumn: SchemaColumn = {
66+
name: SCHEMA_TABLE_COLUMS_IDS.notNull,
67+
get header() {
68+
return i18n('column-title.notNull');
69+
},
70+
width: 100,
71+
// Table should start with notNull columns on sort click
72+
defaultOrder: DataTable.DESCENDING,
73+
render: ({row}) => {
74+
if (row.notNull) {
75+
return '\u2713';
76+
}
77+
78+
return undefined;
79+
},
80+
};
81+
const familyColumn: SchemaColumn = {
82+
name: SCHEMA_TABLE_COLUMS_IDS.familyName,
83+
get header() {
84+
return i18n('column-title.family');
85+
},
86+
width: 100,
87+
render: ({row}) => row.familyName,
88+
};
89+
const mediaColumn: SchemaColumn = {
90+
name: SCHEMA_TABLE_COLUMS_IDS.prefferedPoolKind,
91+
get header() {
92+
return i18n('column-title.media');
93+
},
94+
width: 100,
95+
render: ({row}) => row.prefferedPoolKind,
96+
};
97+
const compressionColumn: SchemaColumn = {
98+
name: SCHEMA_TABLE_COLUMS_IDS.columnCodec,
99+
get header() {
100+
return i18n('column-title.compression');
101+
},
102+
width: 100,
103+
render: ({row}) => row.columnCodec,
104+
};
105+
106+
export function getViewColumns(): SchemaColumn[] {
107+
return [nameColumn, typeColumn];
108+
}
109+
export function getExternalTableColumns(): SchemaColumn[] {
110+
return [idColumn, nameColumn, typeColumn, notNullColumn];
111+
}
112+
export function getColumnTableColumns(): SchemaColumn[] {
113+
return [idColumn, keyColumn, nameColumn, typeColumn, notNullColumn];
114+
}
115+
export function getRowTableColumns(extended: boolean): SchemaColumn[] {
116+
const rowTableColumns = [idColumn, keyColumn, nameColumn, typeColumn, notNullColumn];
117+
118+
if (extended) {
119+
return rowTableColumns.concat(familyColumn, mediaColumn, compressionColumn);
120+
}
121+
122+
return rowTableColumns;
123+
}

0 commit comments

Comments
 (0)