Skip to content

Commit cf96f9a

Browse files
feat: support external objects in schema tree (#485)
1 parent f6b01c3 commit cf96f9a

File tree

11 files changed

+86
-33
lines changed

11 files changed

+86
-33
lines changed

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"reselect": "4.1.6",
4141
"sass": "1.32.8",
4242
"web-vitals": "1.1.2",
43-
"ydb-ui-components": "^3.1.0"
43+
"ydb-ui-components": "^3.2.0"
4444
},
4545
"scripts": {
4646
"start": "react-app-rewired start",

src/containers/Tenant/Diagnostics/DiagnosticsPages.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ export const DIR_PAGES = [overview, topShards, nodes, describe];
8383
export const CDC_STREAM_PAGES = [overview, consumers, partitions, nodes, describe];
8484
export const TOPIC_PAGES = [overview, consumers, partitions, nodes, describe];
8585

86+
export const EXTERNAL_DATA_SOURCE_PAGES = [overview, describe];
87+
export const EXTERNAL_TABLE_PAGES = [overview, describe];
88+
8689
// verbose mapping to guarantee correct tabs for new path types
8790
// TS will error when a new type is added but not mapped here
8891
const pathTypeToPages: Record<EPathType, Page[] | undefined> = {
@@ -101,6 +104,9 @@ const pathTypeToPages: Record<EPathType, Page[] | undefined> = {
101104
[EPathType.EPathTypeCdcStream]: CDC_STREAM_PAGES,
102105

103106
[EPathType.EPathTypePersQueueGroup]: TOPIC_PAGES,
107+
108+
[EPathType.EPathTypeExternalDataSource]: EXTERNAL_DATA_SOURCE_PAGES,
109+
[EPathType.EPathTypeExternalTable]: EXTERNAL_TABLE_PAGES,
104110
};
105111

106112
export const getPagesByType = (type?: EPathType) => (type && pathTypeToPages[type]) || DIR_PAGES;

src/containers/Tenant/Diagnostics/Overview/Overview.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ function Overview({type, tenantName}: OverviewProps) {
124124
<ChangefeedInfo data={data} topic={additionalData?.[0]} />
125125
),
126126
[EPathType.EPathTypePersQueueGroup]: () => <TopicInfo data={data} />,
127+
[EPathType.EPathTypeExternalTable]: undefined,
128+
[EPathType.EPathTypeExternalDataSource]: undefined,
127129
};
128130

129131
return (

src/containers/Tenant/Diagnostics/Overview/utils/prepareTopicSchemaInfo.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,8 @@ export const prepareTopicSchemaInfo = (data?: TEvDescribeSchemeResult): Array<In
2121

2222
const {Partitions = [], PQTabletConfig = {PartitionConfig: {LifetimeSeconds: 0}}} = pqGroupData;
2323

24-
const {Codecs, MeteringMode} = pqGroupData?.PQTabletConfig;
25-
const {WriteSpeedInBytesPerSecond, StorageLimitBytes} =
26-
pqGroupData?.PQTabletConfig?.PartitionConfig;
24+
const {Codecs, MeteringMode} = PQTabletConfig;
25+
const {WriteSpeedInBytesPerSecond, StorageLimitBytes} = PQTabletConfig.PartitionConfig;
2726

2827
const pqGeneralInfo = formatObject<TPersQueueGroupDescription>(formatPQGroupItem, {
2928
Partitions,

src/containers/Tenant/ObjectSummary/ObjectSummary.tsx

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import {Loader} from '../../../components/Loader';
2020
import {
2121
EPathSubType,
2222
EPathType,
23+
TColumnDescription,
2324
TColumnTableDescription,
24-
TTableDescription,
2525
} from '../../../types/api/schema';
2626
import routes, {createHref} from '../../../routes';
2727
import {formatDateTime} from '../../../utils';
@@ -48,7 +48,7 @@ import {
4848
paneVisibilityToggleReducerCreator,
4949
PaneVisibilityToggleButtons,
5050
} from '../utils/paneVisibilityToggleHelpers';
51-
import {isColumnEntityType, isIndexTable, isTableType} from '../utils/schema';
51+
import {isColumnEntityType, isExternalTable, isIndexTable, isTableType} from '../utils/schema';
5252

5353
import './ObjectSummary.scss';
5454
import i18n from '../i18n';
@@ -130,15 +130,20 @@ export function ObjectSummary({
130130
const currentObjectData = currentSchemaPath ? data[currentSchemaPath] : undefined;
131131
const currentSchemaData = currentObjectData?.PathDescription?.Self;
132132

133-
const tableSchema =
134-
currentObjectData?.PathDescription?.Table ||
135-
currentObjectData?.PathDescription?.ColumnTableDescription;
136-
137-
const schema =
138-
isTableType(type) && isColumnEntityType(type)
139-
? // process data for ColumnTable
140-
prepareOlapTableSchema(tableSchema)
141-
: (tableSchema as TTableDescription | undefined);
133+
let keyColumnIds: number[] | undefined;
134+
let columns: TColumnDescription[] | undefined;
135+
136+
if (isTableType(type) && isColumnEntityType(type)) {
137+
const description = currentObjectData?.PathDescription?.ColumnTableDescription;
138+
const columnTableSchema = prepareOlapTableSchema(description);
139+
keyColumnIds = columnTableSchema.KeyColumnIds;
140+
columns = columnTableSchema.Columns;
141+
} else if (isExternalTable(type)) {
142+
columns = currentObjectData?.PathDescription?.ExternalTableDescription?.Columns;
143+
} else {
144+
keyColumnIds = currentObjectData?.PathDescription?.Table?.KeyColumnIds;
145+
columns = currentObjectData?.PathDescription?.Table?.Columns;
146+
}
142147

143148
useEffect(() => {
144149
const isTable = isTableType(type);
@@ -192,6 +197,8 @@ export function ObjectSummary({
192197
[EPathType.EPathTypePersQueueGroup]: () => (
193198
<PersQueueGroupOverview data={currentObjectData} />
194199
),
200+
[EPathType.EPathTypeExternalTable]: undefined,
201+
[EPathType.EPathTypeExternalDataSource]: undefined,
195202
};
196203

197204
let component =
@@ -224,10 +231,7 @@ export function ObjectSummary({
224231
renderLoader()
225232
) : (
226233
<div className={b('schema')}>
227-
<SchemaViewer
228-
keyColumnIds={schema?.KeyColumnIds}
229-
columns={schema?.Columns}
230-
/>
234+
<SchemaViewer keyColumnIds={keyColumnIds} columns={columns} type={type} />
231235
</div>
232236
);
233237
}

src/containers/Tenant/Query/Preview/Preview.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import Fullscreen from '../../../../components/Fullscreen/Fullscreen';
1515
import {QueryResultTable} from '../../../../components/QueryResultTable';
1616
import EnableFullscreenButton from '../../../../components/EnableFullscreenButton/EnableFullscreenButton';
1717

18-
import {isTableType} from '../../utils/schema';
18+
import {isExternalTable, isTableType} from '../../utils/schema';
1919

2020
import i18n from '../i18n';
2121

@@ -56,7 +56,7 @@ export const Preview = ({database, type}: PreviewProps) => {
5656
sendQuery({
5757
query,
5858
database,
59-
action: 'execute-scan',
59+
action: isExternalTable(type) ? 'execute-query' : 'execute-scan',
6060
}),
6161
);
6262
},
@@ -103,7 +103,7 @@ export const Preview = ({database, type}: PreviewProps) => {
103103
if (!isTableType(type)) {
104104
message = <div className={b('message-container')}>{i18n('preview.not-available')}</div>;
105105
} else if (error) {
106-
message = <div className={b('message-container')}>{prepareQueryError(error)}</div>;
106+
message = <div className={b('message-container', 'error')}>{prepareQueryError(error)}</div>;
107107
}
108108

109109
const content = message ?? (

src/containers/Tenant/Schema/SchemaViewer/SchemaViewer.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ import cn from 'bem-cn-lite';
22

33
import DataTable, {Column} from '@gravity-ui/react-data-table';
44

5-
import type {TColumnDescription} from '../../../../types/api/schema';
5+
import type {EPathType, TColumnDescription} from '../../../../types/api/schema';
66
import {DEFAULT_TABLE_SETTINGS} from '../../../../utils/constants';
77

88
import {Icon} from '../../../../components/Icon';
99

10+
import {isExternalTable} from '../../utils/schema';
11+
1012
import './SchemaViewer.scss';
1113

1214
const b = cn('schema-viewer');
@@ -22,10 +24,11 @@ const SchemaViewerColumns = {
2224
interface SchemaViewerProps {
2325
keyColumnIds?: number[];
2426
columns?: TColumnDescription[];
27+
type?: EPathType;
2528
}
2629

27-
export const SchemaViewer = ({keyColumnIds = [], columns = []}: SchemaViewerProps) => {
28-
const dataTableColumns: Column<TColumnDescription>[] = [
30+
export const SchemaViewer = ({keyColumnIds = [], columns = [], type}: SchemaViewerProps) => {
31+
let dataTableColumns: Column<TColumnDescription>[] = [
2932
{
3033
name: SchemaViewerColumns.id,
3134
width: 40,
@@ -65,6 +68,13 @@ export const SchemaViewer = ({keyColumnIds = [], columns = []}: SchemaViewerProp
6568
},
6669
];
6770

71+
if (isExternalTable(type)) {
72+
// External tables don't have key columns
73+
dataTableColumns = dataTableColumns.filter(
74+
(column) => column.name !== SchemaViewerColumns.key,
75+
);
76+
}
77+
6878
// Display key columns first
6979
const tableData = columns.sort((column) => {
7080
if (column.Id && keyColumnIds.includes(column.Id)) {

src/containers/Tenant/utils/schema.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ const pathTypeToNodeType: Record<EPathType, NavigationTreeNodeType | undefined>
3232

3333
[EPathType.EPathTypeCdcStream]: 'topic',
3434
[EPathType.EPathTypePersQueueGroup]: 'topic',
35+
36+
[EPathType.EPathTypeExternalDataSource]: 'external_data_source',
37+
[EPathType.EPathTypeExternalTable]: 'external_table',
3538
};
3639

3740
export const mapPathTypeToNavigationTreeType = (
@@ -64,6 +67,8 @@ const pathTypeToEntityName: Record<EPathType, string | undefined> = {
6467
[EPathType.EPathTypeColumnTable]: 'Columntable',
6568
[EPathType.EPathTypeCdcStream]: 'Changefeed',
6669
[EPathType.EPathTypePersQueueGroup]: 'Topic',
70+
[EPathType.EPathTypeExternalDataSource]: 'External Data Source',
71+
[EPathType.EPathTypeExternalTable]: 'External Table',
6772
};
6873

6974
export const mapPathTypeToEntityName = (
@@ -90,6 +95,8 @@ const pathTypeToIsTable: Record<EPathType, boolean> = {
9095
[EPathType.EPathTypeTable]: true,
9196
[EPathType.EPathTypeColumnTable]: true,
9297

98+
[EPathType.EPathTypeExternalTable]: true,
99+
93100
[EPathType.EPathTypeInvalid]: false,
94101
[EPathType.EPathTypeDir]: false,
95102
[EPathType.EPathTypeSubDomain]: false,
@@ -98,6 +105,7 @@ const pathTypeToIsTable: Record<EPathType, boolean> = {
98105
[EPathType.EPathTypeColumnStore]: false,
99106
[EPathType.EPathTypeCdcStream]: false,
100107
[EPathType.EPathTypePersQueueGroup]: false,
108+
[EPathType.EPathTypeExternalDataSource]: false,
101109
};
102110

103111
export const isTableType = (pathType?: EPathType) =>
@@ -130,6 +138,8 @@ const pathTypeToIsColumn: Record<EPathType, boolean> = {
130138
[EPathType.EPathTypeExtSubDomain]: false,
131139
[EPathType.EPathTypeCdcStream]: false,
132140
[EPathType.EPathTypePersQueueGroup]: false,
141+
[EPathType.EPathTypeExternalDataSource]: false,
142+
[EPathType.EPathTypeExternalTable]: false,
133143
};
134144

135145
export const isColumnEntityType = (type?: EPathType) => (type && pathTypeToIsColumn[type]) ?? false;
@@ -148,6 +158,8 @@ const pathTypeToIsDatabase: Record<EPathType, boolean> = {
148158
[EPathType.EPathTypeTableIndex]: false,
149159
[EPathType.EPathTypeCdcStream]: false,
150160
[EPathType.EPathTypePersQueueGroup]: false,
161+
[EPathType.EPathTypeExternalDataSource]: false,
162+
[EPathType.EPathTypeExternalTable]: false,
151163
};
152164

153165
export const isDatabaseEntityType = (type?: EPathType) =>
@@ -171,6 +183,8 @@ const pathTypeToEntityWithMergedImplementation: Record<EPathType, boolean> = {
171183
[EPathType.EPathTypeSubDomain]: false,
172184
[EPathType.EPathTypeTableIndex]: false,
173185
[EPathType.EPathTypeExtSubDomain]: false,
186+
[EPathType.EPathTypeExternalDataSource]: false,
187+
[EPathType.EPathTypeExternalTable]: false,
174188
};
175189

176190
export const isEntityWithMergedImplementation = (type?: EPathType) =>
@@ -190,6 +204,9 @@ const pathTypeToChildless: Record<EPathType, boolean> = {
190204
[EPathType.EPathTypeCdcStream]: true,
191205
[EPathType.EPathTypePersQueueGroup]: true,
192206

207+
[EPathType.EPathTypeExternalDataSource]: true,
208+
[EPathType.EPathTypeExternalTable]: true,
209+
193210
[EPathType.EPathTypeInvalid]: false,
194211
[EPathType.EPathTypeColumnStore]: false,
195212
[EPathType.EPathTypeColumnTable]: false,
@@ -217,7 +234,14 @@ const mapPathTypeToIsWithTopic: Record<EPathType, boolean> = {
217234
[EPathType.EPathTypeSubDomain]: false,
218235
[EPathType.EPathTypeTableIndex]: false,
219236
[EPathType.EPathTypeExtSubDomain]: false,
237+
238+
[EPathType.EPathTypeExternalDataSource]: false,
239+
[EPathType.EPathTypeExternalTable]: false,
220240
};
221241

222242
export const isPathTypeWithTopic = (type?: EPathType) =>
223243
(type && mapPathTypeToIsWithTopic[type]) ?? false;
244+
245+
// ====================
246+
247+
export const isExternalTable = (type?: EPathType) => type === EPathType.EPathTypeExternalTable;

src/containers/Tenant/utils/schemaActions.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,23 +83,25 @@ export const getActions =
8383
(path: string, type: NavigationTreeNodeType) => {
8484
const actions = bindActions(path, dispatch, setActivePath);
8585
const copyItem = {text: 'Copy path', action: actions.copyPath};
86+
const openPreview = {text: 'Open preview', action: actions.openPreview};
87+
const selectQuery = {text: 'Select query...', action: actions.selectQuery};
8688

8789
const DIR_SET: ActionsSet = [
8890
[copyItem],
8991
[{text: 'Create table...', action: actions.createTable}],
9092
];
9193
const TABLE_SET: ActionsSet = [
92-
[{text: 'Open preview', action: actions.openPreview}, copyItem],
94+
[openPreview, copyItem],
9395
[
9496
{text: 'Alter table...', action: actions.alterTable},
95-
{text: 'Select query...', action: actions.selectQuery},
97+
selectQuery,
9698
{text: 'Upsert query...', action: actions.upsertQuery},
9799
],
98100
];
99101

100-
const JUST_COPY: ActionsSet = [copyItem];
102+
const EXTERNAL_TABLE_SET = [[openPreview, copyItem], [selectQuery]];
101103

102-
const EMPTY_SET: ActionsSet = [];
104+
const JUST_COPY: ActionsSet = [copyItem];
103105

104106
// verbose mapping to guarantee a correct actions set for new node types
105107
// TS will error when a new type is added in the lib but is not mapped here
@@ -113,7 +115,10 @@ export const getActions =
113115
index_table: JUST_COPY,
114116
topic: JUST_COPY,
115117

116-
index: EMPTY_SET,
118+
index: JUST_COPY,
119+
120+
external_table: EXTERNAL_TABLE_SET,
121+
external_data_source: JUST_COPY,
117122
};
118123

119124
return nodeTypeToActions[type];

0 commit comments

Comments
 (0)