Skip to content

Commit b0e764c

Browse files
author
gaoyuanhan.duty
committed
feat(oauth): add oauth consent confirmation page and api
Implement oauth consent confirmation page with plugin info display and confirmation flow Add new developer api endpoints for oauth confirmation and info retrieval Update package dependencies to support new oauth functionality
1 parent 0987eca commit b0e764c

7 files changed

Lines changed: 328 additions & 0 deletions

File tree

common/config/subspaces/default/pnpm-lock.yaml

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

frontend/packages/arch/idl/src/auto-generated/developer_api/index.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4112,5 +4112,29 @@ export default class DeveloperApiService<T> {
41124112
};
41134113
return this.request({ url, method, data }, options);
41144114
}
4115+
4116+
/** POST /api/plugin/oauth/confirm */
4117+
PluginOauthConfirm(
4118+
req?: developer_api.PluginOauthConfirmReq,
4119+
options?: T,
4120+
): Promise<developer_api.PluginOauthConfirmResp> {
4121+
const _req = req || {};
4122+
const url = this.genBaseURL('/api/plugin/oauth/confirm');
4123+
const method = 'POST';
4124+
const data = { confirm_code: _req['confirm_code'] };
4125+
return this.request({ url, method, data }, options);
4126+
}
4127+
4128+
/** GET /api/plugin/oauth/get_oauth_info */
4129+
PluginOauthInfo(
4130+
req?: developer_api.PluginOauthInfoReq,
4131+
options?: T,
4132+
): Promise<developer_api.PluginOauthInfoResp> {
4133+
const _req = req || {};
4134+
const url = this.genBaseURL('/api/plugin/oauth/get_oauth_info');
4135+
const method = 'GET';
4136+
const params = { confirm_code: _req['confirm_code'] };
4137+
return this.request({ url, method, params }, options);
4138+
}
41154139
}
41164140
/* eslint-enable */

frontend/packages/arch/idl/src/auto-generated/developer_api/namespaces/developer_api.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6876,4 +6876,33 @@ export interface WorkInfo {
68766876
/** workflow模式编排数据 */
68776877
layout_info?: LayoutInfo;
68786878
}
6879+
6880+
export interface PluginOauthConfirmReq {
6881+
confirm_code?: string;
6882+
}
6883+
6884+
export interface PluginOauthConfirmResp {
6885+
code?: Int64;
6886+
msg?: string;
6887+
}
6888+
6889+
export interface PluginOauthInfo {
6890+
connector_id?: string;
6891+
plugin_id?: string;
6892+
plugin_name?: string;
6893+
plugin_icon?: string;
6894+
username?: string;
6895+
plugin_url?: string;
6896+
connector_name?: string;
6897+
}
6898+
6899+
export interface PluginOauthInfoReq {
6900+
confirm_code?: string;
6901+
}
6902+
6903+
export interface PluginOauthInfoResp {
6904+
code?: Int64;
6905+
msg?: string;
6906+
data?: PluginOauthInfo;
6907+
}
68796908
/* eslint-enable */

frontend/packages/studio/open-platform/open-auth/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
"dependencies": {
1919
"@coze-arch/bot-api": "workspace:*",
2020
"@coze-arch/bot-semi": "workspace:*",
21+
"@coze-arch/bot-utils": "workspace:*",
2122
"@coze-arch/coze-design": "0.0.6-alpha.346d77",
23+
"@coze-arch/hooks": "workspace:*",
2224
"@coze-arch/i18n": "workspace:*",
2325
"@coze-arch/logger": "workspace:*",
2426
"@coze-arch/report-events": "workspace:*",
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
/*
2+
* Copyright 2025 coze-dev Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
// start_aigc
18+
import { useEffect, useState } from 'react';
19+
20+
import { I18n, type I18nKeysNoOptionsType } from '@coze-arch/i18n';
21+
import { IconCozWarningCircleFillPalette } from '@coze-arch/coze-design/icons';
22+
import { Image, Spin, Button, Typography } from '@coze-arch/coze-design';
23+
import { type PluginOauthInfo } from '@coze-arch/bot-api/developer_api';
24+
import { DeveloperApi } from '@coze-arch/bot-api';
25+
26+
interface IConfirmCardProps {
27+
confirmCode: string;
28+
}
29+
30+
const PluginOauthInfoContent = ({
31+
pluginOauthInfo,
32+
confirmCode,
33+
}: {
34+
pluginOauthInfo: PluginOauthInfo;
35+
confirmCode: string;
36+
}) => {
37+
const [confirmLoading, setConfirmLoading] = useState(false);
38+
const getPluginUrl = () => {
39+
if (!pluginOauthInfo?.plugin_url) {
40+
return '';
41+
}
42+
if (pluginOauthInfo?.plugin_url?.startsWith('http')) {
43+
return pluginOauthInfo?.plugin_url;
44+
}
45+
return `https://${pluginOauthInfo?.plugin_url}`;
46+
};
47+
48+
const handleCancel = () => {
49+
window.close();
50+
};
51+
52+
const handleConfirm = async () => {
53+
setConfirmLoading(true);
54+
const pluginOauthConfirm = await DeveloperApi.PluginOauthConfirm({
55+
confirm_code: confirmCode,
56+
});
57+
setConfirmLoading(false);
58+
if (pluginOauthConfirm.code === 0) {
59+
window.location.replace('/information/auth/success');
60+
}
61+
};
62+
63+
return (
64+
<div className="w-full h-full flex flex-col justify-between">
65+
<div className="flex flex-col items-center gap-[32px]">
66+
<Image
67+
src={pluginOauthInfo?.plugin_icon}
68+
width={56}
69+
height={56}
70+
className="border border-solid coz-stroke-plus"
71+
/>
72+
<div className="w-full flex flex-col items-center gap-[20px]">
73+
<Typography.Text
74+
className="w-full text-[20px] leading-[28px] !font-medium text-center !coz-fg-primary"
75+
ellipsis={{
76+
showTooltip: true,
77+
rows: 1,
78+
}}
79+
>
80+
{I18n.t(
81+
'plugin_oauth_info_confirm_page_title' as I18nKeysNoOptionsType,
82+
{
83+
plugin_name: pluginOauthInfo?.plugin_name,
84+
},
85+
)}
86+
</Typography.Text>
87+
<div className="w-full flex flex-col gap-[8px] items-center">
88+
<div className="w-full flex items-center justify-center">
89+
<Typography.Text className="flex-shrink-0 text-[14px] leading-[20px] text-center font-normal coz-fg-secondary">
90+
{I18n.t(
91+
'plugin_oauth_info_confirm_page_plugin_url' as I18nKeysNoOptionsType,
92+
)}
93+
</Typography.Text>
94+
<Typography.Text
95+
className="text-[14px] leading-[20px] text-center font-normal coz-fg-secondary "
96+
ellipsis={{
97+
showTooltip: true,
98+
rows: 1,
99+
}}
100+
link={{
101+
target: '_blank',
102+
href: getPluginUrl(),
103+
className: '!coz-fg-secondary !underline',
104+
}}
105+
underline={true}
106+
>
107+
{pluginOauthInfo?.plugin_url}
108+
</Typography.Text>
109+
</div>
110+
<Typography.Text
111+
className="text-[14px] leading-[20px] text-center font-normal coz-fg-secondary"
112+
ellipsis={{
113+
showTooltip: true,
114+
rows: 1,
115+
}}
116+
>
117+
{I18n.t(
118+
'plugin_oauth_info_confirm_page_to_acct' as I18nKeysNoOptionsType,
119+
)}
120+
{pluginOauthInfo?.username}
121+
</Typography.Text>
122+
<Typography.Text
123+
className="text-[14px] leading-[20px] text-center font-normal coz-fg-secondary"
124+
ellipsis={{
125+
showTooltip: true,
126+
rows: 1,
127+
}}
128+
>
129+
{I18n.t(
130+
'plugin_oauth_info_confirm_page_channel' as I18nKeysNoOptionsType,
131+
)}
132+
{pluginOauthInfo?.connector_name}
133+
</Typography.Text>
134+
</div>
135+
</div>
136+
</div>
137+
<div className="w-full flex flex-col gap-[32px]">
138+
<p className="w-full flex items-center justify-center gap-[4px]">
139+
<IconCozWarningCircleFillPalette
140+
width="16"
141+
height="16"
142+
color="var(--coz-fg-hglt-yellow)"
143+
/>
144+
<span className="text-[14px] leading-[20px] text-center coz-fg-secondary">
145+
{I18n.t(
146+
'plugin_oauth_info_confirm_page_tips' as I18nKeysNoOptionsType,
147+
)}
148+
</span>
149+
</p>
150+
<div className="flex justify-between items-center">
151+
<Button
152+
color="primary"
153+
size="large"
154+
className="w-[200px]"
155+
onClick={handleCancel}
156+
>
157+
{I18n.t(
158+
'plugin_oauth_info_confirm_page_cancel' as I18nKeysNoOptionsType,
159+
)}
160+
</Button>
161+
<Button
162+
color="hgltplus"
163+
size="large"
164+
className="w-[200px]"
165+
onClick={handleConfirm}
166+
loading={confirmLoading}
167+
>
168+
{I18n.t(
169+
'plugin_oauth_info_confirm_page_confirm' as I18nKeysNoOptionsType,
170+
)}
171+
</Button>
172+
</div>
173+
</div>
174+
</div>
175+
);
176+
};
177+
178+
export const ConfirmCard = ({ confirmCode }: IConfirmCardProps) => {
179+
const [pluginOauthInfo, setPluginOauthInfo] = useState<PluginOauthInfo>();
180+
181+
useEffect(() => {
182+
if (!confirmCode) {
183+
return;
184+
}
185+
186+
const getPluginOauthInfo = async (code: string) => {
187+
const pluginOauthInfoResp = await DeveloperApi.PluginOauthInfo({
188+
confirm_code: code,
189+
});
190+
if (pluginOauthInfoResp.data) {
191+
setPluginOauthInfo(pluginOauthInfoResp.data);
192+
}
193+
};
194+
195+
getPluginOauthInfo(confirmCode);
196+
197+
return () => {
198+
setPluginOauthInfo(undefined);
199+
};
200+
}, [confirmCode]);
201+
202+
const renderContent = () => {
203+
if (!pluginOauthInfo) {
204+
return (
205+
<div className="flex justify-center items-center w-full h-full">
206+
<Spin />
207+
</div>
208+
);
209+
}
210+
211+
return (
212+
<PluginOauthInfoContent
213+
pluginOauthInfo={pluginOauthInfo}
214+
confirmCode={confirmCode}
215+
/>
216+
);
217+
};
218+
219+
return (
220+
<div className="flex flex-col w-[492px] h-[547px] px-[40px] pt-[100px] pb-[60px] border border-solid coz-stroke-primary rounded-xl">
221+
{renderContent()}
222+
</div>
223+
);
224+
};
225+
// end_aigc
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2025 coze-dev Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { I18n } from '@coze-arch/i18n';
18+
import { useUrlParams } from '@coze-arch/hooks';
19+
import { renderHtmlTitle } from '@coze-arch/bot-utils';
20+
import { UILayout } from '@coze-arch/bot-semi';
21+
22+
import { ConfirmCard } from './confirm-card';
23+
24+
export const ConsentConfirmPage = () => {
25+
const {
26+
value: { code },
27+
} = useUrlParams<{ code: string }>();
28+
return (
29+
<UILayout
30+
title={renderHtmlTitle(I18n.t('plugin_oauth_info_confirm_page'))}
31+
className="coz-bg-max flex justify-center items-center"
32+
>
33+
<ConfirmCard confirmCode={code} />
34+
</UILayout>
35+
);
36+
};

frontend/packages/studio/open-platform/open-auth/tsconfig.build.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@
2020
{
2121
"path": "../../../arch/bot-typings/tsconfig.build.json"
2222
},
23+
{
24+
"path": "../../../arch/bot-utils/tsconfig.build.json"
25+
},
26+
{
27+
"path": "../../../arch/hooks/tsconfig.build.json"
28+
},
2329
{
2430
"path": "../../../arch/i18n/tsconfig.build.json"
2531
},

0 commit comments

Comments
 (0)