Skip to content

Commit 966ff4b

Browse files
authored
feat: support transfer (#1995)
1 parent 5dc37e0 commit 966ff4b

20 files changed

+288
-6
lines changed

package-lock.json

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
"use-query-params": "^2.2.1",
5959
"uuid": "^10.0.0",
6060
"web-vitals": "^1.1.2",
61-
"ydb-ui-components": "^4.5.0",
61+
"ydb-ui-components": "^4.6.0",
6262
"zod": "^3.24.1"
6363
},
6464
"scripts": {

src/containers/Tenant/Diagnostics/DiagnosticsPages.ts

+3
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ const operations = {
8282

8383
const ASYNC_REPLICATION_PAGES = [overview, tablets, describe];
8484

85+
const TRANSFER_PAGES = [overview, tablets, describe];
86+
8587
const DATABASE_PAGES = [
8688
overview,
8789
topQueries,
@@ -133,6 +135,7 @@ const pathTypeToPages: Record<EPathType, Page[] | undefined> = {
133135
[EPathType.EPathTypeView]: VIEW_PAGES,
134136

135137
[EPathType.EPathTypeReplication]: ASYNC_REPLICATION_PAGES,
138+
[EPathType.EPathTypeTransfer]: TRANSFER_PAGES,
136139
[EPathType.EPathTypeResourcePool]: DIR_PAGES,
137140
};
138141

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

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {AsyncReplicationInfo} from './AsyncReplicationInfo';
2020
import {ChangefeedInfo} from './ChangefeedInfo';
2121
import {TableInfo} from './TableInfo';
2222
import {TopicInfo} from './TopicInfo';
23+
import {TransferInfo} from './TransferInfo';
2324

2425
interface OverviewProps {
2526
type?: EPathType;
@@ -94,6 +95,7 @@ function Overview({type, path, database}: OverviewProps) {
9495
[EPathType.EPathTypeExternalDataSource]: () => <ExternalDataSourceInfo data={data} />,
9596
[EPathType.EPathTypeView]: () => <ViewInfo data={data} />,
9697
[EPathType.EPathTypeReplication]: () => <AsyncReplicationInfo data={data} />,
98+
[EPathType.EPathTypeTransfer]: () => <TransferInfo data={data} />,
9799
};
98100

99101
return (type && pathTypeToComponent[type]?.()) || <TableInfo data={data} type={type} />;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import {Label} from '@gravity-ui/uikit';
2+
3+
import type {TConnectionParams} from '../../../../../types/api/schema/replication';
4+
5+
interface CredentialsProps {
6+
connection?: TConnectionParams;
7+
}
8+
9+
export function Credentials({connection}: CredentialsProps) {
10+
if (!connection) {
11+
return null;
12+
}
13+
14+
if (connection.StaticCredentials) {
15+
return (
16+
<Label value={connection.StaticCredentials.User} theme="normal">
17+
user
18+
</Label>
19+
);
20+
}
21+
22+
if ('OAuthToken' in connection) {
23+
return 'OAuth';
24+
}
25+
26+
return 'unknown';
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import type {DefinitionListItem} from '@gravity-ui/components';
2+
import {Flex, Text} from '@gravity-ui/uikit';
3+
4+
import {AsyncReplicationState} from '../../../../../components/AsyncReplicationState';
5+
import {YDBDefinitionList} from '../../../../../components/YDBDefinitionList/YDBDefinitionList';
6+
import {YqlHighlighter} from '../../../../../components/YqlHighlighter/YqlHighlighter';
7+
import type {TEvDescribeSchemeResult} from '../../../../../types/api/schema';
8+
import {getEntityName} from '../../../utils';
9+
10+
import {Credentials} from './Credentials';
11+
import i18n from './i18n';
12+
13+
interface TransferProps {
14+
data?: TEvDescribeSchemeResult;
15+
}
16+
17+
/** Displays overview for Transfer EPathType */
18+
export function TransferInfo({data}: TransferProps) {
19+
const entityName = getEntityName(data?.PathDescription);
20+
21+
if (!data) {
22+
return (
23+
<div className="error">
24+
{i18n('noData')} {entityName}
25+
</div>
26+
);
27+
}
28+
29+
const transferItems = prepareTransferItems(data);
30+
31+
return (
32+
<Flex direction="column" gap="4">
33+
<YDBDefinitionList title={entityName} items={transferItems} />
34+
</Flex>
35+
);
36+
}
37+
38+
function prepareTransferItems(data: TEvDescribeSchemeResult) {
39+
const transferDescription = data.PathDescription?.ReplicationDescription || {};
40+
const state = transferDescription.State;
41+
const srcConnectionParams = transferDescription.Config?.SrcConnectionParams || {};
42+
const {Endpoint, Database} = srcConnectionParams;
43+
const target = transferDescription.Config?.TransferSpecific?.Targets[0];
44+
const srcPath = target?.SrcPath;
45+
const dstPath = target?.DstPath;
46+
const transformLambda = target?.TransformLambda;
47+
48+
const info: DefinitionListItem[] = [];
49+
50+
if (state) {
51+
info.push({
52+
name: i18n('state.label'),
53+
content: <AsyncReplicationState state={state} />,
54+
});
55+
}
56+
57+
if (Endpoint) {
58+
info.push({
59+
name: i18n('srcConnection.endpoint.label'),
60+
copyText: Endpoint,
61+
content: <Text variant="code-inline-2">{Endpoint}</Text>,
62+
});
63+
}
64+
65+
if (Database) {
66+
info.push({
67+
name: i18n('srcConnection.database.label'),
68+
copyText: Database,
69+
content: <Text variant="code-inline-2">{Database}</Text>,
70+
});
71+
}
72+
73+
if (srcConnectionParams) {
74+
info.push({
75+
name: i18n('credentials.label'),
76+
content: <Credentials connection={srcConnectionParams} />,
77+
});
78+
}
79+
80+
info.push({
81+
name: i18n('srcPath.label'),
82+
copyText: srcPath,
83+
content: <Text variant="code-inline-2">{srcPath}</Text>,
84+
});
85+
86+
info.push({
87+
name: i18n('dstPath.label'),
88+
copyText: dstPath,
89+
content: <Text variant="code-inline-2">{dstPath}</Text>,
90+
});
91+
92+
info.push({
93+
name: i18n('transformLambda.label'),
94+
copyText: transformLambda,
95+
content: transformLambda ? <YqlHighlighter>{transformLambda}</YqlHighlighter> : null,
96+
});
97+
98+
return info;
99+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"credentials.label": "Credentials",
3+
"noData": "No data for entity:",
4+
"srcConnection.database.label": "Source Database Path",
5+
"srcConnection.endpoint.label": "Source Cluster Endpoint",
6+
"state.label": "State",
7+
"srcPath.label": "Source Topic",
8+
"dstPath.label": "Destination Table",
9+
"transformLambda.label": "Transformation Lambda"
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import {registerKeysets} from '../../../../../../utils/i18n';
2+
3+
import en from './en.json';
4+
5+
const COMPONENT = 'ydb-diagnostics-transfer-info';
6+
7+
export default registerKeysets(COMPONENT, {en});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './TransferInfo';

src/containers/Tenant/ObjectSummary/ObjectSummary.tsx

+14
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,20 @@ export function ObjectSummary({
310310
return [];
311311
}
312312

313+
return [
314+
{
315+
name: i18n('field_state'),
316+
content: <AsyncReplicationState state={state} />,
317+
},
318+
];
319+
},
320+
[EPathType.EPathTypeTransfer]: () => {
321+
const state = PathDescription?.ReplicationDescription?.State;
322+
323+
if (!state) {
324+
return [];
325+
}
326+
313327
return [
314328
{
315329
name: i18n('field_state'),

src/containers/Tenant/Query/NewSQL/NewSQL.tsx

+17
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,23 @@ export function NewSQL() {
106106
},
107107
],
108108
},
109+
{
110+
text: i18n('menu.transfer'),
111+
items: [
112+
{
113+
text: i18n('action.create-transfer'),
114+
action: actions.createTransfer,
115+
},
116+
{
117+
text: i18n('action.alter-transfer'),
118+
action: actions.alterTransfer,
119+
},
120+
{
121+
text: i18n('action.drop-transfer'),
122+
action: actions.dropTransfer,
123+
},
124+
],
125+
},
109126
{
110127
text: i18n('menu.capture'),
111128
items: [

src/containers/Tenant/Query/NewSQL/i18n/en.json

+5-1
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,22 @@
1616
"menu.topics": "Topics",
1717
"menu.capture": "Change data capture",
1818
"menu.replication": "Async replication",
19+
"menu.transfer": "Transfer",
1920
"menu.users": "Users",
2021
"action.create-topic": "Create Topic",
2122
"action.drop-topic": "Drop Topic",
2223
"action.alter-topic": "Alter Topic",
2324
"action.create-cdc-stream": "Create changefeed",
2425
"action.create-async-replication": "Create async replication",
26+
"action.create-transfer": "Create transfer",
2527
"action.create-user": "Create user",
2628
"action.create-group": "Create group",
2729
"action.drop-user": "Drop user",
2830
"action.drop-group": "Drop group",
2931
"action.grant-privilege": "Grant privilege",
3032
"action.revoke-privilege": "Revoke privilege",
3133
"action.alter-async-replication": "Alter async replication",
32-
"action.drop-async-replication": "Drop async replication"
34+
"action.drop-async-replication": "Drop async replication",
35+
"action.alter-transfer": "Alter transfer",
36+
"action.drop-transfer": "Drop transfer"
3337
}

src/containers/Tenant/i18n/en.json

+3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"actions.createTopic": "Create topic...",
3434
"actions.createColumnTable": "Create column table...",
3535
"actions.createAsyncReplication": "Create async replication...",
36+
"actions.createTransfer": "Create transfer...",
3637
"actions.createView": "Create view...",
3738
"actions.dropTable": "Drop table...",
3839
"actions.dropTopic": "Drop topic...",
@@ -46,7 +47,9 @@
4647
"actions.selectQuery": "Select query...",
4748
"actions.upsertQuery": "Upsert query...",
4849
"actions.alterReplication": "Alter async replicaton...",
50+
"actions.alterTransfer": "Alter transfer...",
4951
"actions.dropReplication": "Drop async replicaton...",
52+
"actions.dropTransfer": "Drop transfer...",
5053
"actions.createDirectory": "Create directory",
5154
"schema.tree.dialog.placeholder": "Relative path",
5255
"schema.tree.dialog.invalid": "Invalid path",

src/containers/Tenant/utils/controls.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export const getSchemaControls =
6161

6262
const nodeTypeToControls: Record<NavigationTreeNodeType, Controls> = {
6363
async_replication: undefined,
64+
transfer: undefined,
6465

6566
database: undefined,
6667
directory: undefined,

src/containers/Tenant/utils/newSQLQueryActions.ts

+6
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ import {
33
alterAsyncReplicationTemplate,
44
alterTableTemplate,
55
alterTopicTemplate,
6+
alterTransferTemplate,
67
createAsyncReplicationTemplate,
78
createCdcStreamTemplate,
89
createColumnTableTemplate,
910
createExternalTableTemplate,
1011
createGroupTemplate,
1112
createTableTemplate,
1213
createTopicTemplate,
14+
createTransferTemplate,
1315
createUserTemplate,
1416
createViewTemplate,
1517
deleteRowsTemplate,
@@ -19,6 +21,7 @@ import {
1921
dropTableIndex,
2022
dropTableTemplate,
2123
dropTopicTemplate,
24+
dropTransferTemplate,
2225
dropUserTemplate,
2326
grantPrivilegeTemplate,
2427
revokePrivilegeTemplate,
@@ -38,6 +41,9 @@ export const bindActions = (changeUserInput: (input: string) => void) => {
3841
createAsyncReplication: inputQuery(createAsyncReplicationTemplate),
3942
alterAsyncReplication: inputQuery(alterAsyncReplicationTemplate),
4043
dropAsyncReplication: inputQuery(dropAsyncReplicationTemplate),
44+
createTransfer: inputQuery(createTransferTemplate),
45+
alterTransfer: inputQuery(alterTransferTemplate),
46+
dropTransfer: inputQuery(dropTransferTemplate),
4147
alterTable: inputQuery(alterTableTemplate),
4248
selectQuery: inputQuery(selectQueryTemplate),
4349
upsertQuery: inputQuery(upsertQueryTemplate),

src/containers/Tenant/utils/schema.ts

+7
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const pathTypeToNodeType: Record<EPathType, NavigationTreeNodeType | undefined>
3939
[EPathType.EPathTypeView]: 'view',
4040

4141
[EPathType.EPathTypeReplication]: 'async_replication',
42+
[EPathType.EPathTypeTransfer]: 'transfer',
4243
[EPathType.EPathTypeResourcePool]: 'resource_pool',
4344
};
4445

@@ -87,6 +88,7 @@ const pathTypeToEntityName: Record<EPathType, string | undefined> = {
8788
[EPathType.EPathTypeView]: 'View',
8889

8990
[EPathType.EPathTypeReplication]: 'Async Replication',
91+
[EPathType.EPathTypeTransfer]: 'Transfer',
9092
[EPathType.EPathTypeResourcePool]: 'Resource Pool',
9193
};
9294

@@ -128,6 +130,7 @@ const pathTypeToIsTable: Record<EPathType, boolean> = {
128130
[EPathType.EPathTypePersQueueGroup]: false,
129131
[EPathType.EPathTypeExternalDataSource]: false,
130132
[EPathType.EPathTypeReplication]: false,
133+
[EPathType.EPathTypeTransfer]: false,
131134
[EPathType.EPathTypeResourcePool]: false,
132135
};
133136

@@ -169,6 +172,7 @@ const pathTypeToIsColumn: Record<EPathType, boolean> = {
169172
[EPathType.EPathTypeView]: false,
170173

171174
[EPathType.EPathTypeReplication]: false,
175+
[EPathType.EPathTypeTransfer]: false,
172176
[EPathType.EPathTypeResourcePool]: false,
173177
};
174178

@@ -195,6 +199,7 @@ const pathTypeToIsDatabase: Record<EPathType, boolean> = {
195199
[EPathType.EPathTypeView]: false,
196200

197201
[EPathType.EPathTypeReplication]: false,
202+
[EPathType.EPathTypeTransfer]: false,
198203
[EPathType.EPathTypeResourcePool]: false,
199204
};
200205

@@ -226,6 +231,7 @@ const pathTypeToEntityWithMergedImplementation: Record<EPathType, boolean> = {
226231
[EPathType.EPathTypeView]: false,
227232

228233
[EPathType.EPathTypeReplication]: false,
234+
[EPathType.EPathTypeTransfer]: false,
229235
[EPathType.EPathTypeResourcePool]: false,
230236
};
231237

@@ -253,6 +259,7 @@ const pathTypeToChildless: Record<EPathType, boolean> = {
253259
[EPathType.EPathTypeResourcePool]: true,
254260

255261
[EPathType.EPathTypeReplication]: true,
262+
[EPathType.EPathTypeTransfer]: true,
256263

257264
[EPathType.EPathTypeInvalid]: false,
258265
[EPathType.EPathTypeColumnStore]: false,

0 commit comments

Comments
 (0)