Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ 仓库登记页面结构优化调整 #662

Merged
merged 9 commits into from
Oct 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion web/packages/login/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"react-i18next": "^11.17.3",
"react-redux": "^7.2.5",
"react-router-dom": "^5.3.0",
"tdesign-react": "0.36.4",
"tdesign-react": "0.42.3",
"universal-cookie": "^4.0.4"
},
"devDependencies": {
Expand Down
6 changes: 6 additions & 0 deletions web/packages/shared/component/authority/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ export const AUTH_TYPE_TXT = {
OAUTH: 'OAuth',
};

export const AUTH_TYPE_CHOICES = {
[AUTH_TYPE.HTTP]: AUTH_TYPE_TXT.HTTP,
[AUTH_TYPE.SSH]: AUTH_TYPE_TXT.SSH,
[AUTH_TYPE.OAUTH]: AUTH_TYPE_TXT.OAUTH,
};

// 凭证映射,对应 api 返回的字段名
export const SCM_MAP = {
[AUTH_TYPE.HTTP]: 'scm_account',
Expand Down
17 changes: 11 additions & 6 deletions web/packages/shared/component/authority/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import PlusIcon from 'coding-oa-uikit/lib/icon/Plus';
import RefreshIcon from 'coding-oa-uikit/lib/icon/Refresh';

import { AUTH_TYPE, AUTH_TYPE_TXT, SCM_MAP, SCM_PLATFORM_CHOICES } from './constants';
import { FormInstance } from 'coding-oa-uikit/lib/form';

import { FormInstance } from 'rc-field-form';
const { Option, OptGroup } = Select;

export interface RestfulListAPIParams {
Expand All @@ -30,10 +30,14 @@ interface AuthorityProps {
placeholder?: string;
required?: boolean;
allowClear?: boolean;
formLayout?: any;
/** 新增凭证路由 */
addAuthRouter?: string
}

const Authority = (props: AuthorityProps) => {
const { form, name, label, initAuth, getAuthList, selectStyle = {}, placeholder, required, allowClear } = props;
const { form, name, label, initAuth, getAuthList, selectStyle = {},
placeholder, required, allowClear, formLayout, addAuthRouter } = props;
const [sshAuthList, setSshAuthList] = useState<any>([]);
const [httpAuthList, setHttpAuthList] = useState<any>([]);
const [oauthAuthList, setOauthAuthList] = useState<any>([]);
Expand Down Expand Up @@ -105,7 +109,7 @@ const Authority = (props: AuthorityProps) => {
}, [initAuth, authLoading]);

return (
<Form.Item label={label} required={required}>
<Form.Item label={label} required={required} {...formLayout}>
<Form.Item name={name} noStyle rules={[{ required, message: '请选择仓库凭证' }]}>
<Select
style={selectStyle}
Expand All @@ -120,9 +124,10 @@ const Authority = (props: AuthorityProps) => {
<Option
key={`${AUTH_TYPE.OAUTH}#${auth.id}`}
value={`${AUTH_TYPE.OAUTH}#${auth.id}`}
label={`${get(SCM_PLATFORM_CHOICES, auth.scm_platform)}: ${AUTH_TYPE_TXT.OAUTH}`}
label={`${get(SCM_PLATFORM_CHOICES, auth.scm_platform)}: ${auth.user?.username || auth.user}`}
>
{get(SCM_PLATFORM_CHOICES, auth.scm_platform)}
{get(SCM_PLATFORM_CHOICES, auth.scm_platform)}: {auth.user?.username || auth.user}
<small style={{ marginLeft: 8, color: '#8592a6' }}>(在 {auth.auth_origin} 创建)</small>
</Option>
))}
</OptGroup>
Expand Down Expand Up @@ -163,7 +168,7 @@ const Authority = (props: AuthorityProps) => {
right: 10,
}}>
<Tooltip title='新增凭证' placement='top' getPopupContainer={() => document.body}>
<Button type='link' className="ml-12" href='/user/auth' target='_blank'><PlusIcon /></Button>
<Button type='link' className="ml-12" href={addAuthRouter || '/user/auth'} target='_blank'><PlusIcon /></Button>
</Tooltip>
<Tooltip title='刷新凭证' placement='top' getPopupContainer={() => document.body}>
<Button
Expand Down
1 change: 1 addition & 0 deletions web/packages/shared/component/route/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as RouteListener } from './listener';
110 changes: 110 additions & 0 deletions web/packages/shared/component/route/listener/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/**
* 用于父子页面路由监听
*/
import React, { useEffect } from 'react';
import { useHistory, useLocation } from 'react-router-dom';
import { LogMgr } from '../../../util';
/** 跨页面通信消息状态码 */
export enum PostMessageCode {
SUCCESS = 200,
}

/** 跨页面通信消息数据结构 */
export interface PostMessageData {
code: number;
type: string;
data: string;
}

/** route接收消息数据结构 */
export interface RouteReceiveMessage {
/** 接受消息来源 */
eventOrigin?: string;
/** 接收消息类型 */
messageType?: string;
/** history 路由跳转类型 */
jumpType?: 'push' | 'replace';
/** 路由前缀,接收路由时会增加路由前缀再执行跳转发送 */
prefix?: string;
/** 自定义处理 */
customHandler?: (event: MessageEvent<PostMessageData>) => void;
}

/** route发送消息数据结构 */
export interface RoutePostMessage {
/** 自定义操作 */
customHandler?: (urlPath: string) => void
/** 发送消息目标源,不存在customHandler时必传 */
targetOrigin?: string;
/** 发送消息类型,不存在customHandler时必传 */
messageType?: string;
/** 是否处于 iframe 内 */
inIframe?: boolean;
/** 路由前缀,发送路由时会替换路由前缀再发送 */
prefix?: string;
}

interface RouteListenerProps {
postMessage?: RoutePostMessage;
receiveMessage?: RouteReceiveMessage;
children: React.ReactNode;
}

const RouteListener = ({ receiveMessage, postMessage, children }: RouteListenerProps) => {
const history = useHistory();

const { pathname, search, hash } = useLocation();
// 获取url path
const urlPath = `${pathname}${search}${hash}`;

useEffect(() => {
if (postMessage?.customHandler) {
// 存在自定义操作
postMessage.customHandler(urlPath);
} else if (postMessage?.targetOrigin && postMessage.messageType) {
// 存在目标源以及消息类型
// 路由变更时发送消息
const msg: PostMessageData = {
code: PostMessageCode.SUCCESS,
type: postMessage.messageType,
// 存在前缀则先替换前缀
data: postMessage.prefix ? urlPath.replace(postMessage.prefix, '') : urlPath,
};
if (postMessage.inIframe && window.self !== window.top) {
// 在iframe内,对iframe父页面发送路由变更消息
window.top?.postMessage(msg, postMessage.targetOrigin);
} else {
LogMgr.warn('route 路由变更,未发送消息');
}
}
}, [urlPath, postMessage]);

useEffect(() => {
const receiveRouteHandler = (event: MessageEvent<PostMessageData>) => {
if (receiveMessage?.customHandler) {
// 存在自定义操作
receiveMessage.customHandler(event);
} else if (
receiveMessage?.eventOrigin && receiveMessage.messageType
&& receiveMessage.jumpType && event.origin === receiveMessage.eventOrigin) {
// 存在发送源、消息类型、路由调整类型,且来自发送源消息
const { code, type, data } = event.data;
if (code === PostMessageCode.SUCCESS && type === receiveMessage.messageType) {
// 默认匹配
const urlPath = receiveMessage.prefix ? `${receiveMessage.prefix}${data}` : data;
history[receiveMessage.jumpType](urlPath);
} else {
LogMgr.warn('接收到 route 消息,未匹配成功,未进行任何处理');
}
}
};
receiveMessage && window.addEventListener('message', receiveRouteHandler, false);
return () => {
receiveMessage && window.removeEventListener('message', receiveRouteHandler);
};
}, [receiveMessage]);

return <>{children}</>;
};

export default RouteListener;
9 changes: 9 additions & 0 deletions web/packages/shared/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,12 @@ interface WindowMicroHook {
interface Window {
microHook: WindowMicroHook;
}


// drf restful list api
interface RestfulListAPIParams {
results: any[];
count: number;
next: string;
previous: string
}
6 changes: 3 additions & 3 deletions web/packages/shared/hooks/useFetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export interface UseFetchOptions {
/** 失败的回调 */
onFail?: (error: any) => void
/** 最终的回调 */
onFinnaly?: () => void
onFinally?: () => void
}

/**
Expand All @@ -78,7 +78,7 @@ const useFetch = <ApiArgs extends any[]>(
apiArgs: ApiArgs,
options: UseFetchOptions = {},
): [State, () => void] => {
const { initData = null, onPreHandler, onSuccess, onFail, onFinnaly } = options;
const { initData = null, onPreHandler, onSuccess, onFail, onFinally } = options;
const [state, dispatch] = useReducer(fetchReducer, {
isLoading: false,
isError: false,
Expand Down Expand Up @@ -117,7 +117,7 @@ const useFetch = <ApiArgs extends any[]>(
dispatch({ type: 'FETCH_FAILURE', payload: error });
onFail?.(error);
} finally {
onFinnaly?.();
onFinally?.();
}
};
fetchData();
Expand Down
2 changes: 1 addition & 1 deletion web/packages/shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"react-router-dom": "^5.3.0",
"react-copy-to-clipboard": "^5.0.4",
"react-i18next": "^11.17.3",
"tdesign-react": "0.36.4",
"tdesign-react": "0.42.3",
"typescript": "^4.5.5"
}
}
7 changes: 7 additions & 0 deletions web/packages/shared/tca/user-auth/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# 用户个人凭证管理

- index: 用户个人凭证管理页面

- git-oauth: git oauth 授权回调页面

- auth-form-item: 凭证选择组件
58 changes: 58 additions & 0 deletions web/packages/shared/tca/user-auth/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { FetchAPIManager } from '../../util/fetch';
import { AuthTypeEnum, SCM_PLATFORM_NAME_CHOICES } from './constant';
import { OAuthResult, UserAuthAPI } from './types';

export const formatUserAuthAPI = (
/** ssh 凭证接口 */
ssh: FetchAPIManager,
/** account 凭证接口 */
account: FetchAPIManager,
/** oauth 凭证接口 */
oauth: FetchAPIManager,
/** oauth 凭证后台配置项接口 */
oauthSetting: FetchAPIManager,
/** oauth 凭证个人认证项接口 */
oauthStatus: FetchAPIManager,
/** oauth 认证回调接口 */
oauthCallback: FetchAPIManager,
): UserAuthAPI => ({
getAuths: () => Promise.all([
ssh.get({ limit: 200 }),
account.get({ limit: 200 }),
oauthSetting.get(),
oauthStatus.get(),
]).then(([sshInfo, accountInfo, oauthSettings, oauthStatus]) => {
const sshList = (sshInfo as RestfulListAPIParams).results.map(item => ({ ...item, auth_type: AuthTypeEnum.SSH }));
const accountList = (accountInfo as RestfulListAPIParams).results.map(item => ({
...item, auth_type: AuthTypeEnum.HTTP,
}));
const oauthList = Object.keys(SCM_PLATFORM_NAME_CHOICES).filter(scmPlatformName => (
oauthSettings as OAuthResult
)[scmPlatformName])
.map(scmPlatformName => ({
...SCM_PLATFORM_NAME_CHOICES[scmPlatformName],
platform_status: true,
oauth_status: (oauthStatus as OAuthResult)[scmPlatformName] || false,
}));
return [...oauthList, ...sshList, ...accountList];
}),
getAuthInfos: () => Promise.all([
ssh.get({ limit: 200 }),
account.get({ limit: 200 }),
oauth.get(),
oauthStatus.get(),
]).then(([sshInfo, accountInfo, oauthInfo, oauthStatus]) => {
const sshList = (sshInfo as RestfulListAPIParams).results;
const accountList = (accountInfo as RestfulListAPIParams).results;
const oauthList = (oauthInfo as RestfulListAPIParams).results.filter(item => (
oauthStatus as OAuthResult
)[item.scm_platform_name]);
return { oauthList, sshList, accountList };
}),
ssh,
account,
oauth,
oauthSetting,
oauthStatus,
oauthCallback,
});
Loading