Skip to content

Commit 6367ffd

Browse files
authored
feat: support protobuf on Web (#2320)
1 parent 2aadeff commit 6367ffd

File tree

14 files changed

+613
-18
lines changed

14 files changed

+613
-18
lines changed

web/config/routes.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ const routes = [
9999
path: '/service/:serviceId/edit',
100100
component: './Service/Create',
101101
},
102+
{
103+
path: '/proto/list',
104+
component: './Proto/List',
105+
},
102106
{
103107
path: '/settings',
104108
component: './Setting',
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
/* eslint-disable no-undef */
18+
19+
context('Create and Delete Proto', () => {
20+
const selector = {
21+
id: '#id',
22+
description: '#desc',
23+
content: '.view-lines',
24+
draw: '.ant-drawer-content',
25+
notification: '.ant-notification-notice-message',
26+
};
27+
28+
const data = {
29+
id: 'test_id',
30+
description: 'test_description',
31+
content: `message Person {
32+
required string name = 1;
33+
required int32 id = 2;
34+
optional string email = 3;
35+
}`,
36+
description2: 'test_description2',
37+
content2: `message Person2 {
38+
required string name = 1;
39+
required int32 id = 2;
40+
optional string email = 3;
41+
}`,
42+
createProtoSuccess: 'Create proto Successfully',
43+
configureProtoSuccess: 'Configure proto Successfully',
44+
deleteProtoSuccess: 'Delete Upstream Successfully',
45+
};
46+
47+
beforeEach(() => {
48+
cy.login();
49+
});
50+
51+
it('should create proto', () => {
52+
cy.visit('/');
53+
cy.contains('Proto').click();
54+
cy.contains('Create').click();
55+
cy.get(selector.draw)
56+
.should('be.visible')
57+
.within(() => {
58+
cy.get(selector.id).type(data.id);
59+
cy.get(selector.description).type(data.description);
60+
cy.get(selector.content).type(data.content);
61+
62+
cy.contains('Submit').click();
63+
});
64+
cy.get(selector.notification).should('contain', data.createProtoSuccess);
65+
cy.get('.ant-notification-close-x').click();
66+
});
67+
68+
it('should edit the proto', () => {
69+
cy.visit('/');
70+
cy.contains('Proto').click();
71+
cy.contains(data.id).siblings().contains('Configure').click();
72+
cy.get(selector.draw)
73+
.should('be.visible')
74+
.within(() => {
75+
cy.get(selector.description).clear().type(data.description2);
76+
cy.get(selector.content).type(data.content2);
77+
78+
cy.contains('Submit').click();
79+
});
80+
cy.get(selector.notification).should('contain', data.configureProtoSuccess);
81+
cy.get('.ant-notification-close-x').click();
82+
});
83+
84+
it('should delete the proto', () => {
85+
cy.visit('/');
86+
cy.contains('Proto').click();
87+
cy.contains(data.id).siblings().contains('Delete').click();
88+
cy.contains('button', 'Confirm').click();
89+
cy.get(selector.notification).should('contain', data.deleteProtoSuccess);
90+
cy.get('.ant-notification-close-x').click();
91+
});
92+
});

web/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
"@ant-design/pro-table": "2.30.1",
5656
"@antv/x6": "^1.18.5",
5757
"@antv/x6-react-components": "^1.1.7",
58-
"@monaco-editor/react": "^4.1.3",
58+
"@monaco-editor/react": "^4.3.1",
5959
"@rjsf/antd": "2.2.0",
6060
"@rjsf/core": "2.2.0",
6161
"@types/js-yaml": "^4.0.0",
@@ -131,7 +131,7 @@
131131
"husky": "^6.0.0",
132132
"lint-staged": "^10.0.0",
133133
"mockjs": "^1.0.1-beta3",
134-
"monaco-editor": "^0.24.0",
134+
"monaco-editor": "^0.32.1",
135135
"pinst": "^2.1.1",
136136
"prettier": "^2.0.1",
137137
"pro-download": "1.0.1",

web/src/helpers.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import React from 'react';
1818
import { notification } from 'antd';
1919
import type { MenuDataItem } from '@ant-design/pro-layout';
20-
import { InfoCircleOutlined } from '@ant-design/icons';
20+
import { InfoCircleOutlined, FileTextOutlined } from '@ant-design/icons';
2121
import { history } from 'umi';
2222
import moment from 'moment';
2323
import YAML from 'yaml';
@@ -53,6 +53,11 @@ export const getMenuData = (): MenuDataItem[] => {
5353
path: '/consumer/list',
5454
icon: <IconFont name="iconconsumer" />,
5555
},
56+
{
57+
name: 'proto',
58+
path: '/proto/list',
59+
icon: <FileTextOutlined />,
60+
},
5661
{
5762
name: 'plugin',
5863
path: '/plugin/list',

web/src/locales/en-US/menu.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export default {
7070
'menu.consumer': 'Consumer',
7171
'menu.plugin': 'Plugin',
7272
'menu.service': 'Service',
73+
'menu.proto': 'Protocol Buffers',
7374
'menu.setting': 'Settings',
7475
'menu.serverinfo': 'System Info',
7576
'menu.advanced-feature': 'Advanced',

web/src/locales/zh-CN/menu.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ export default {
6767
'menu.consumer': '消费者',
6868
'menu.plugin': '插件',
6969
'menu.service': '服务',
70+
'menu.proto': 'Protocol Buffers',
7071
'menu.setting': '系统设置',
7172
'menu.serverinfo': '系统信息',
7273
'menu.advanced-feature': '高级特性',

web/src/pages/Proto/List.tsx

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
import React, { useRef, useState } from 'react';
18+
import { PageHeaderWrapper } from '@ant-design/pro-layout';
19+
import ProTable, { ProColumns, ActionType } from '@ant-design/pro-table';
20+
import ProtoDrawer from './components/ProtoDrawer';
21+
import { Button, notification, Popconfirm, Space } from 'antd';
22+
import { useIntl } from 'umi';
23+
import usePagination from '@/hooks/usePagination';
24+
25+
import { PlusOutlined } from '@ant-design/icons';
26+
27+
import { timestampToLocaleString } from '@/helpers';
28+
import { fetchList, remove } from './service';
29+
30+
const Page: React.FC = () => {
31+
const ref = useRef<ActionType>();
32+
const { formatMessage } = useIntl();
33+
const [drawerVisible, setDrawerVisible] = useState(false);
34+
const { paginationConfig, savePageList } = usePagination();
35+
const emptyProtoData = {
36+
id: null,
37+
content: '',
38+
desc: '',
39+
};
40+
const [protoData, setProtoData] = useState<ProtoModule.ProtoData>(emptyProtoData);
41+
const [editMode, setEditMode] = useState<ProtoModule.EditMode>('create');
42+
43+
const refreshTable = () => {
44+
ref.current?.reload();
45+
};
46+
47+
const showDrawer = (data: ProtoModule.ProtoData, mode: ProtoModule.EditMode) => {
48+
setDrawerVisible(true);
49+
setProtoData(data);
50+
setEditMode(mode);
51+
};
52+
53+
const columns: ProColumns<ProtoModule.ResponseBody>[] = [
54+
{
55+
title: formatMessage({ id: 'component.global.id' }),
56+
hideInSearch: true,
57+
dataIndex: 'id',
58+
width: 100,
59+
},
60+
{
61+
title: formatMessage({ id: 'page.proto.desc' }),
62+
dataIndex: 'desc',
63+
ellipsis: true,
64+
width: 200,
65+
},
66+
{
67+
title: formatMessage({ id: 'page.proto.content' }),
68+
hideInSearch: true,
69+
dataIndex: 'content',
70+
ellipsis: true,
71+
},
72+
{
73+
title: formatMessage({ id: 'component.global.updateTime' }),
74+
dataIndex: 'update_time',
75+
hideInSearch: true,
76+
render: (text) => timestampToLocaleString(text as number),
77+
width: 200,
78+
},
79+
{
80+
title: formatMessage({ id: 'component.global.operation' }),
81+
valueType: 'option',
82+
fixed: 'right',
83+
hideInSearch: true,
84+
render: (_, record) => (
85+
<Space align="baseline">
86+
<Button
87+
type="primary"
88+
onClick={() =>
89+
showDrawer({ id: record.id, content: record.content, desc: record.desc }, 'update')
90+
}
91+
>
92+
{formatMessage({ id: 'component.global.edit' })}
93+
</Button>
94+
<Popconfirm
95+
title={formatMessage({ id: 'page.upstream.list.confirm.delete' })}
96+
okText={formatMessage({ id: 'page.upstream.list.confirm' })}
97+
cancelText={formatMessage({ id: 'page.upstream.list.cancel' })}
98+
onConfirm={() => {
99+
remove(record.id).then(() => {
100+
notification.success({
101+
message: formatMessage({ id: 'page.upstream.list.delete.successfully' }),
102+
});
103+
/* eslint-disable no-unused-expressions */
104+
ref.current?.reload();
105+
});
106+
}}
107+
>
108+
<Button type="primary" danger>
109+
{formatMessage({ id: 'page.upstream.list.delete' })}
110+
</Button>
111+
</Popconfirm>
112+
</Space>
113+
),
114+
},
115+
];
116+
117+
return (
118+
<PageHeaderWrapper
119+
title={formatMessage({ id: 'page.proto.list' })}
120+
content={formatMessage({ id: 'page.proto.list.description' })}
121+
>
122+
<ProtoDrawer
123+
protoData={protoData as ProtoModule.ProtoData}
124+
setProtoData={setProtoData}
125+
visible={drawerVisible}
126+
setVisible={setDrawerVisible}
127+
editMode={editMode}
128+
refreshTable={refreshTable}
129+
/>
130+
<ProTable<ProtoModule.ResponseBody>
131+
actionRef={ref}
132+
rowKey="id"
133+
columns={columns}
134+
request={fetchList}
135+
pagination={{
136+
onChange: (page, pageSize?) => savePageList(page, pageSize),
137+
pageSize: paginationConfig.pageSize,
138+
current: paginationConfig.current,
139+
}}
140+
search={{
141+
searchText: formatMessage({ id: 'component.global.search' }),
142+
resetText: formatMessage({ id: 'component.global.reset' }),
143+
}}
144+
toolBarRender={() => [
145+
<Button type="primary" onClick={() => showDrawer(emptyProtoData, 'create')}>
146+
<PlusOutlined />
147+
{formatMessage({ id: 'component.global.create' })}
148+
</Button>,
149+
]}
150+
tableAlertRender={false}
151+
scroll={{ x: 1300 }}
152+
/>
153+
</PageHeaderWrapper>
154+
);
155+
};
156+
157+
export default Page;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
@import '~antd/es/style/themes/default.less';
18+
19+
.formItemEditor {
20+
flex-flow: column;
21+
22+
:global {
23+
.ant-form-item-explain-error {
24+
padding-left: 30px;
25+
}
26+
27+
.ant-form-item-control-input {
28+
margin-top: 20px;
29+
}
30+
}
31+
}

0 commit comments

Comments
 (0)