未验证 提交 0e8d2331 编写于 作者: 陈帅 提交者: GitHub

💥 feat: @umijs/route-utils replace getAuthorityFromRouter (#7319)

* 💥 feat: @umijs/route-utils replace getAuthorityFromRouter

* fix test

* remove unuse code
上级 9046670f
...@@ -9,14 +9,14 @@ import ProLayout, { ...@@ -9,14 +9,14 @@ import ProLayout, {
Settings, Settings,
DefaultFooter, DefaultFooter,
} from '@ant-design/pro-layout'; } from '@ant-design/pro-layout';
import React, { useEffect } from 'react'; import React, { useEffect, useMemo, useRef } from 'react';
import { Link, useIntl, connect, Dispatch, history } from 'umi'; import { Link, useIntl, connect, Dispatch, history } from 'umi';
import { GithubOutlined } from '@ant-design/icons'; import { GithubOutlined } from '@ant-design/icons';
import { Result, Button } from 'antd'; import { Result, Button } from 'antd';
import Authorized from '@/utils/Authorized'; import Authorized from '@/utils/Authorized';
import RightContent from '@/components/GlobalHeader/RightContent'; import RightContent from '@/components/GlobalHeader/RightContent';
import { ConnectState } from '@/models/connect'; import { ConnectState } from '@/models/connect';
import { getAuthorityFromRouter } from '@/utils/utils'; import { getMatchMenu } from '@umijs/route-utils';
import logo from '../assets/logo.svg'; import logo from '../assets/logo.svg';
const noMatch = ( const noMatch = (
...@@ -94,9 +94,8 @@ const BasicLayout: React.FC<BasicLayoutProps> = (props) => { ...@@ -94,9 +94,8 @@ const BasicLayout: React.FC<BasicLayoutProps> = (props) => {
pathname: '/', pathname: '/',
}, },
} = props; } = props;
/**
* constructor const menuDataRef = useRef<MenuDataItem[]>([]);
*/
useEffect(() => { useEffect(() => {
if (dispatch) { if (dispatch) {
...@@ -116,11 +115,16 @@ const BasicLayout: React.FC<BasicLayoutProps> = (props) => { ...@@ -116,11 +115,16 @@ const BasicLayout: React.FC<BasicLayoutProps> = (props) => {
payload, payload,
}); });
} }
}; // get children authority
const authorized = getAuthorityFromRouter(props.route.routes, location.pathname || '/') || {
authority: undefined,
}; };
// get children authority
const authorized = useMemo(
() =>
getMatchMenu(location.pathname || '/', menuDataRef.current).pop() || {
authority: undefined,
},
[location.pathname],
);
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
return ( return (
...@@ -153,6 +157,10 @@ const BasicLayout: React.FC<BasicLayoutProps> = (props) => { ...@@ -153,6 +157,10 @@ const BasicLayout: React.FC<BasicLayoutProps> = (props) => {
footerRender={() => defaultFooterDom} footerRender={() => defaultFooterDom}
menuDataRender={menuDataRender} menuDataRender={menuDataRender}
rightContentRender={() => <RightContent />} rightContentRender={() => <RightContent />}
postMenuData={(menuData) => {
menuDataRef.current = menuData || [];
return menuData || [];
}}
{...props} {...props}
{...settings} {...settings}
> >
......
import React from 'react';
import { Redirect, connect, ConnectProps } from 'umi';
import Authorized from '@/utils/Authorized';
import { getRouteAuthority } from '@/utils/utils';
import { ConnectState, UserModelState } from '@/models/connect';
interface AuthComponentProps extends ConnectProps {
user: UserModelState;
}
const AuthComponent: React.FC<AuthComponentProps> = ({
children,
route = {
routes: [],
},
location = {
pathname: '',
},
user,
}) => {
const { currentUser } = user;
const { routes = [] } = route;
const isLogin = currentUser && currentUser.name;
return (
<Authorized
authority={getRouteAuthority(location.pathname, routes) || ''}
noMatch={isLogin ? <Redirect to="/exception/403" /> : <Redirect to="/user/login" />}
>
{children}
</Authorized>
);
};
export default connect(({ user }: ConnectState) => ({
user,
}))(AuthComponent);
import { isUrl, getRouteAuthority } from './utils'; import { isUrl } from './utils';
describe('isUrl tests', (): void => { describe('isUrl tests', (): void => {
it('should return false for invalid and corner case inputs', (): void => { it('should return false for invalid and corner case inputs', (): void => {
...@@ -35,42 +35,3 @@ describe('isUrl tests', (): void => { ...@@ -35,42 +35,3 @@ describe('isUrl tests', (): void => {
expect(isUrl('https://www.example.com/test/123?foo=bar')).toBeTruthy(); expect(isUrl('https://www.example.com/test/123?foo=bar')).toBeTruthy();
}); });
}); });
describe('getRouteAuthority tests', () => {
it('should return authority for each route', (): void => {
const routes = [
{ path: '/user', name: 'user', authority: ['user'], exact: true },
{ path: '/admin', name: 'admin', authority: ['admin'], exact: true },
];
expect(getRouteAuthority('/user', routes)).toEqual(['user']);
expect(getRouteAuthority('/admin', routes)).toEqual(['admin']);
});
it('should return inherited authority for unconfigured route', (): void => {
const routes = [
{ path: '/nested', authority: ['admin', 'user'], exact: true },
{ path: '/nested/user', name: 'user', exact: true },
];
expect(getRouteAuthority('/nested/user', routes)).toEqual(['admin', 'user']);
});
it('should return authority for configured route', (): void => {
const routes = [
{ path: '/nested', authority: ['admin', 'user'], exact: true },
{ path: '/nested/user', name: 'user', authority: ['user'], exact: true },
{ path: '/nested/admin', name: 'admin', authority: ['admin'], exact: true },
];
expect(getRouteAuthority('/nested/user', routes)).toEqual(['user']);
expect(getRouteAuthority('/nested/admin', routes)).toEqual(['admin']);
});
it('should return authority for substring route', (): void => {
const routes = [
{ path: '/nested', authority: ['user', 'users'], exact: true },
{ path: '/nested/users', name: 'users', authority: ['users'], exact: true },
{ path: '/nested/user', name: 'user', authority: ['user'], exact: true },
];
expect(getRouteAuthority('/nested/user', routes)).toEqual(['user']);
expect(getRouteAuthority('/nested/users', routes)).toEqual(['users']);
});
});
import { parse } from 'querystring'; import { parse } from 'querystring';
import pathRegexp from 'path-to-regexp';
import { Route } from '@/models/connect';
/* eslint no-useless-escape:0 import/prefer-default-export:0 */ /* eslint no-useless-escape:0 import/prefer-default-export:0 */
const reg = /(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/; const reg = /(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/;
...@@ -24,42 +22,3 @@ export const isAntDesignProOrDev = (): boolean => { ...@@ -24,42 +22,3 @@ export const isAntDesignProOrDev = (): boolean => {
}; };
export const getPageQuery = () => parse(window.location.href.split('?')[1]); export const getPageQuery = () => parse(window.location.href.split('?')[1]);
/**
* props.route.routes
* @param router [{}]
* @param pathname string
*/
export const getAuthorityFromRouter = <T extends Route>(
router: T[] = [],
pathname: string,
): T | undefined => {
const authority = router.find(
({ routes, path = '/', target = '_self' }) =>
(path && target !== '_blank' && pathRegexp(path).exec(pathname)) ||
(routes && getAuthorityFromRouter(routes, pathname)),
);
if (authority) return authority;
return undefined;
};
export const getRouteAuthority = (path: string, routeData: Route[]) => {
let authorities: string[] | string | undefined;
routeData.forEach((route) => {
// match prefix
if (pathRegexp(`${route.path}/(.*)`).test(`${path}/`)) {
if (route.authority) {
authorities = route.authority;
}
// exact match
if (route.path === path) {
authorities = route.authority || authorities;
}
// get children authority recursively
if (route.routes) {
authorities = getRouteAuthority(path, route.routes) || authorities;
}
}
});
return authorities;
};
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册