未验证 提交 06dd7fa6 编写于 作者: 信鑫-King 提交者: GitHub

features: use umi 3 (#6039)

* refactor: use umi 3

* fix: lint

* fix: d.ts

* fix: ignoreMomentLocale

* feat: add preset ui

* fix: preset

* fix: plugins

* fix: plugin

* fix: config

* fix: antd locale

* 🐛 bugfix: update types

* 🐛 bugfix:fix types error

* feat: add @umijs/plugin-blocks

* block support umi@3

* update deps

* update deps

* remove umi-plugin-antd-icon-config

* lint: fix ts error

* ignore: ignore build

* 🚀 Deploy: do not run yarn lint

* fix e2e test

* fix e2e test

* fix lgmt error

* 🚀 Deploy: add GA_KEY
Co-authored-by: Nchenshuai2144 <qixian.cs@outlook.com>
上级 b60aa50f
......@@ -11,11 +11,12 @@ jobs:
uses: actions/checkout@master
- run: yarn
- run: yarn run lint
- run: yarn run tsc
# - run: yarn run tsc
- name: Build and Deploy
uses: JamesIves/github-pages-deploy-action@master
env:
CI: true
GA_KEY: UA-72788897-6
PROGRESS: none
GIT_CONFIG_NAME: qixian.cs
GIT_CONFIG_EMAIL: qixian.cs@outlook.com
......@@ -24,4 +25,4 @@ jobs:
GITHUB_TOKEN: ${{ secrets.ACTION_TOKEN }}
BRANCH: gh-pages
FOLDER: 'dist/'
BUILD_SCRIPT: yarn && npm uninstall husky && npm run site && git checkout . && git clean -df
BUILD_SCRIPT: yarn && npm uninstall husky && yarn add umi-plugin-antd-theme umi-plugin-pro && npm run site && git checkout . && git clean -df
......@@ -19,3 +19,4 @@ LICENSE
yarn-error.log
.history
CNAME
/build
import { IConfig, IPlugin } from 'umi-types';
import defaultSettings from './defaultSettings'; // https://umijs.org/config/
import slash from 'slash2';
import themePluginConfig from './themePluginConfig';
// https://umijs.org/config/
import { defineConfig, utils } from 'umi';
import defaultSettings from './defaultSettings';
import proxy from './proxy';
import webpackPlugin from './plugin.config';
const { pwa } = defaultSettings;
const { winPath } = utils;
// preview.pro.ant.design only do not use in your production ;
// preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。
const { ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION, REACT_APP_ENV } = process.env;
const isAntDesignProPreview = ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site';
const plugins: IPlugin[] = [
['umi-plugin-antd-icon-config', {}],
[
'umi-plugin-react',
{
antd: true,
dva: {
hmr: true,
},
locale: {
// default false
enable: true,
// default zh-CN
default: 'zh-CN',
// default true, when it is true, will use `navigator.language` overwrite default
baseNavigator: true,
},
dynamicImport: {
loadingComponent: './components/PageLoading/index',
webpackChunkName: true,
level: 3,
},
pwa: pwa
? {
workboxPluginMode: 'InjectManifest',
workboxOptions: {
importWorkboxFrom: 'local',
},
}
: false,
// default close dll, because issue https://github.com/ant-design/ant-design-pro/issues/4665
// dll features https://webpack.js.org/plugins/dll-plugin/
// dll: {
// include: ['dva', 'dva/router', 'dva/saga', 'dva/fetch'],
// exclude: ['@babel/runtime'],
// },
},
],
[
'umi-plugin-pro-block',
{
moveMock: false,
moveService: false,
modifyRequest: true,
autoAddMenu: true,
},
],
];
const { ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION, REACT_APP_ENV, GA_KEY } = process.env;
if (isAntDesignProPreview) {
// 针对 preview.pro.ant.design 的 GA 统计代码
plugins.push([
'umi-plugin-ga',
{
code: 'UA-72788897-6',
},
]);
plugins.push([
'umi-plugin-pro',
{
serverUrl: 'https://proapi.azurewebsites.net',
},
]);
plugins.push(['umi-plugin-antd-theme', themePluginConfig]);
}
export default {
plugins,
export default defineConfig({
hash: true,
antd: {},
analytics: GA_KEY ? { ga: GA_KEY } : false,
dva: {
hmr: true,
},
locale: {
// default zh-CN
default: 'zh-CN',
// default true, when it is true, will use `navigator.language` overwrite default
antd: true,
baseNavigator: true,
},
dynamicImport: {
loading: '@/components/PageLoading/index',
},
targets: {
ie: 11,
},
......@@ -164,36 +109,36 @@ export default {
ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION || '', // preview.pro.ant.design only do not use in your production ; preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。
},
ignoreMomentLocale: true,
lessLoaderOptions: {
lessLoader: {
javascriptEnabled: true,
},
disableRedirectHoist: true,
cssLoaderOptions: {
modules: true,
getLocalIdent: (
context: {
resourcePath: string;
},
_: string,
localName: string,
) => {
if (
context.resourcePath.includes('node_modules') ||
context.resourcePath.includes('ant.design.pro.less') ||
context.resourcePath.includes('global.less')
) {
cssLoader: {
modules: {
getLocalIdent: (
context: {
resourcePath: string;
},
_: string,
localName: string,
) => {
if (
context.resourcePath.includes('node_modules') ||
context.resourcePath.includes('ant.design.pro.less') ||
context.resourcePath.includes('global.less')
) {
return localName;
}
const match = context.resourcePath.match(/src(.*)/);
if (match && match[1]) {
const antdProPath = match[1].replace('.less', '');
const arr = winPath(antdProPath)
.split('/')
.map((a: string) => a.replace(/([A-Z])/g, '-$1'))
.map((a: string) => a.toLowerCase());
return `antd-pro${arr.join('-')}-${localName}`.replace(/--/g, '-');
}
return localName;
}
const match = context.resourcePath.match(/src(.*)/);
if (match && match[1]) {
const antdProPath = match[1].replace('.less', '');
const arr = slash(antdProPath)
.split('/')
.map((a: string) => a.replace(/([A-Z])/g, '-$1'))
.map((a: string) => a.toLowerCase());
return `antd-pro${arr.join('-')}-${localName}`.replace(/--/g, '-');
}
return localName;
},
},
},
manifest: {
......@@ -201,4 +146,4 @@ export default {
},
proxy: proxy[REACT_APP_ENV || 'dev'],
chainWebpack: webpackPlugin,
} as IConfig;
});
export default {
theme: [
{
key: 'dark',
fileName: 'dark.css',
theme: 'dark',
},
{
key: 'dust',
fileName: 'dust.css',
modifyVars: {
'@primary-color': '#F5222D',
},
},
{
key: 'volcano',
fileName: 'volcano.css',
modifyVars: {
'@primary-color': '#FA541C',
},
},
{
key: 'sunset',
fileName: 'sunset.css',
modifyVars: {
'@primary-color': '#FAAD14',
},
},
{
key: 'cyan',
fileName: 'cyan.css',
modifyVars: {
'@primary-color': '#13C2C2',
},
},
{
key: 'green',
fileName: 'green.css',
modifyVars: {
'@primary-color': '#52C41A',
},
},
{
key: 'geekblue',
fileName: 'geekblue.css',
modifyVars: {
'@primary-color': '#2F54EB',
},
},
{
key: 'purple',
fileName: 'purple.css',
modifyVars: {
'@primary-color': '#722ED1',
},
},
{
key: 'dust',
theme: 'dark',
fileName: 'dark-dust.css',
modifyVars: {
'@primary-color': '#F5222D',
},
},
{
key: 'volcano',
theme: 'dark',
fileName: 'dark-volcano.css',
modifyVars: {
'@primary-color': '#FA541C',
},
},
{
key: 'sunset',
theme: 'dark',
fileName: 'dark-sunset.css',
modifyVars: {
'@primary-color': '#FAAD14',
},
},
{
key: 'cyan',
theme: 'dark',
fileName: 'dark-cyan.css',
modifyVars: {
'@primary-color': '#13C2C2',
},
},
{
key: 'green',
theme: 'dark',
fileName: 'dark-green.css',
modifyVars: {
'@primary-color': '#52C41A',
},
},
{
key: 'geekblue',
theme: 'dark',
fileName: 'dark-geekblue.css',
modifyVars: {
'@primary-color': '#2F54EB',
},
},
{
key: 'purple',
theme: 'dark',
fileName: 'dark-purple.css',
modifyVars: {
'@primary-color': '#722ED1',
},
},
],
};
module.exports = {
testURL: 'http://localhost:8000',
preset: 'jest-puppeteer',
extraSetupFiles: ['./tests/setupTests.js'],
globals: {
ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: false,
......
// eslint-disable-next-line import/no-extraneous-dependencies
import { Request, Response } from 'express';
import { parse } from 'url';
import { TableListItem, TableListParams } from './data.d';
import { TableListItem, TableListParams } from '@/pages/ListTableList/data';
// mock tableListDataSource
const genList = (current: number, pageSize: number) => {
......@@ -34,13 +34,12 @@ const genList = (current: number, pageSize: number) => {
let tableListDataSource = genList(1, 100);
function getRule(req: Request, res: Response, u: string) {
let url = u;
if (!url || Object.prototype.toString.call(url) !== '[object String]') {
// eslint-disable-next-line prefer-destructuring
url = req.url;
let realUrl = u;
if (!realUrl || Object.prototype.toString.call(realUrl) !== '[object String]') {
realUrl = req.url;
}
const { current = 1, pageSize = 10 } = req.query;
const params = (parse(url, true).query as unknown) as TableListParams;
const params = (parse(realUrl, true).query as unknown) as TableListParams;
let dataSource = [...tableListDataSource].slice((current - 1) * pageSize, current * pageSize);
if (params.sorter) {
......@@ -84,10 +83,9 @@ function getRule(req: Request, res: Response, u: string) {
}
function postRule(req: Request, res: Response, u: string, b: Request) {
let url = u;
if (!url || Object.prototype.toString.call(url) !== '[object String]') {
// eslint-disable-next-line prefer-destructuring
url = req.url;
let realUrl = u;
if (!realUrl || Object.prototype.toString.call(realUrl) !== '[object String]') {
realUrl = req.url;
}
const body = (b && b.body) || req.body;
......
......@@ -14,10 +14,10 @@
"docker:dev": "docker-compose -f ./docker/docker-compose.dev.yml up",
"docker:push": "npm run docker-hub:build && npm run docker:tag && docker push antdesign/ant-design-pro",
"docker:tag": "docker tag ant-design-pro antdesign/ant-design-pro",
"fetch:blocks": "pro fetch-blocks && npm run prettier",
"fetch:blocks": "pro fetch-blocks --branch=umi@3 && npm run prettier",
"gh-pages": "cp CNAME ./dist/ && gh-pages -d dist",
"i18n-remove": "pro i18n-remove --locale=zh-CN --write",
"lint": "npm run lint:js && npm run lint:style && npm run lint:prettier",
"lint": "umi g tmp && npm run lint:js && npm run lint:style && npm run lint:prettier",
"lint:prettier": "prettier --check \"**/*\" --end-of-line auto",
"lint-staged": "lint-staged",
"lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx ",
......@@ -36,8 +36,7 @@
"test": "umi test",
"test:all": "node ./tests/run-tests.js",
"test:component": "umi test ./src/components",
"tsc": "tsc",
"ui": "umi ui"
"tsc": "tsc"
},
"husky": {
"hooks": {
......@@ -57,28 +56,20 @@
"not ie <= 10"
],
"dependencies": {
"@ant-design/icons": "^4.0.0-alpha.19",
"@ant-design/icons": "^4.0.0",
"@ant-design/pro-layout": "^5.0.0",
"@ant-design/pro-table": "^2.0.0",
"@antv/data-set": "^0.11.1",
"antd": "^4.0.2",
"antd": "^4.0.0",
"classnames": "^2.2.6",
"dva": "^2.6.0-beta.16",
"lodash": "^4.17.11",
"moment": "^2.24.0",
"omit.js": "^1.0.2",
"path-to-regexp": "2.4.0",
"qs": "^6.9.0",
"react": "^16.8.6",
"react-copy-to-clipboard": "^5.0.1",
"react-dom": "^16.8.6",
"react-helmet": "^5.2.1",
"redux": "^4.0.1",
"umi": "^2.13.0",
"umi-plugin-antd-icon-config": "^1.0.2",
"umi-plugin-antd-theme": "1.2.0-0",
"umi-plugin-pro-block": "^1.3.2",
"umi-plugin-react": "^1.14.10",
"umi": "^3.0.0",
"umi-request": "^1.0.8",
"use-merge-value": "^1.0.1"
},
......@@ -94,6 +85,10 @@
"@types/react-dom": "^16.8.4",
"@types/react-helmet": "^5.0.13",
"@umijs/fabric": "^2.0.2",
"@umijs/plugin-blocks": "^2.0.5",
"@umijs/preset-ant-design-pro": "^1.0.1",
"@umijs/preset-react": "^1.3.0",
"@umijs/preset-ui": "^2.0.9",
"chalk": "^3.0.0",
"cross-env": "^7.0.0",
"cross-port-killer": "^1.1.1",
......@@ -101,19 +96,12 @@
"express": "^4.17.1",
"gh-pages": "^2.0.1",
"husky": "^4.0.7",
"jest-puppeteer": "^4.2.0",
"jsdom-global": "^3.0.2",
"lint-staged": "^10.0.0",
"mockjs": "^1.0.1-beta3",
"node-fetch": "^2.6.0",
"prettier": "^1.19.1",
"pro-download": "1.0.1",
"serverless-http": "^2.0.2",
"stylelint": "^13.0.0",
"umi-plugin-antd-icon-config": "^1.0.2",
"umi-plugin-ga": "^1.1.3",
"umi-plugin-pro": "^1.0.3",
"umi-types": "^0.5.9"
"stylelint": "^13.0.0"
},
"optionalDependencies": {
"puppeteer": "^2.0.0"
......
......@@ -21,7 +21,7 @@ const Authorized: React.FunctionComponent<AuthorizedProps> = ({
authority,
noMatch = (
<Result
status={403}
status="403"
title="403"
subTitle="Sorry, you are not authorized to access this page."
/>
......
......@@ -2,14 +2,13 @@ import { LogoutOutlined, SettingOutlined, UserOutlined } from '@ant-design/icons
import { Avatar, Menu, Spin } from 'antd';
import { ClickParam } from 'antd/es/menu';
import React from 'react';
import { connect } from 'dva';
import { router } from 'umi';
import { ConnectProps, ConnectState } from '@/models/connect';
import { history, ConnectProps, connect } from 'umi';
import { ConnectState } from '@/models/connect';
import { CurrentUser } from '@/models/user';
import HeaderDropdown from '../HeaderDropdown';
import styles from './index.less';
export interface GlobalHeaderRightProps extends ConnectProps {
export interface GlobalHeaderRightProps extends Partial<ConnectProps> {
currentUser?: CurrentUser;
menu?: boolean;
}
......@@ -30,7 +29,7 @@ class AvatarDropdown extends React.Component<GlobalHeaderRightProps> {
return;
}
router.push(`/account/${key}`);
history.push(`/account/${key}`);
};
render(): React.ReactNode {
......
import React, { Component } from 'react';
import { connect, ConnectProps } from 'umi';
import { Tag, message } from 'antd';
import { connect } from 'dva';
import groupBy from 'lodash/groupBy';
import moment from 'moment';
import { NoticeItem } from '@/models/global';
import { CurrentUser } from '@/models/user';
import { ConnectProps, ConnectState } from '@/models/connect';
import { ConnectState } from '@/models/connect';
import NoticeIcon from '../NoticeIcon';
import styles from './index.less';
export interface GlobalHeaderRightProps extends ConnectProps {
export interface GlobalHeaderRightProps extends Partial<ConnectProps> {
notices?: NoticeItem[];
currentUser?: CurrentUser;
fetchingNotices?: boolean;
......
import { Tooltip, Tag } from 'antd';
import { QuestionCircleOutlined } from '@ant-design/icons';
import React from 'react';
import { connect } from 'dva';
import { ConnectProps, ConnectState } from '@/models/connect';
import { connect, ConnectProps } from 'umi';
import { ConnectState } from '@/models/connect';
import Avatar from './AvatarDropdown';
import HeaderSearch from '../HeaderSearch';
import SelectLang from '../SelectLang';
import styles from './index.less';
export type SiderTheme = 'light' | 'dark';
export interface GlobalHeaderRightProps extends ConnectProps {
export interface GlobalHeaderRightProps extends Partial<ConnectProps> {
theme?: SiderTheme;
layout: 'sidemenu' | 'topmenu';
}
......
import { GlobalOutlined } from '@ant-design/icons';
import { Menu } from 'antd';
import { getLocale, setLocale } from 'umi-plugin-react/locale';
import { getLocale, setLocale } from 'umi';
import { ClickParam } from 'antd/es/menu';
import React from 'react';
import classNames from 'classnames';
......
......@@ -3,6 +3,8 @@ const RouterConfig = require('../../config/config').default.routes;
const BASE_URL = `http://localhost:${process.env.PORT || 8000}`;
const getBrowser = require('./getBrowser');
function formatter(routes, parentPath = '') {
const fixedParentPath = parentPath.replace(/\/{1,}/g, '/');
let result = [];
......@@ -19,7 +21,15 @@ function formatter(routes, parentPath = '') {
return uniq(result.filter(item => !!item));
}
let browser;
let page;
beforeAll(async () => {
browser = await getBrowser();
});
beforeEach(async () => {
page = await browser.newPage();
await page.goto(`${BASE_URL}`);
await page.evaluate(() => {
localStorage.setItem('antd-pro-authority', '["admin"]');
......@@ -43,3 +53,7 @@ describe('Ant Design Pro E2E test', () => {
it(`test pages ${route}`, testPage(route));
});
});
afterAll(() => {
browser.close();
});
// ps https://github.com/GoogleChrome/puppeteer/issues/3120
module.exports = {
launch: {
import puppeteer from 'puppeteer';
const getBrowser = async () => {
const browser = await puppeteer.launch({
args: [
'--disable-gpu',
'--disable-dev-shm-usage',
......@@ -8,5 +9,8 @@ module.exports = {
'--no-zygote',
'--no-sandbox',
],
},
});
return browser;
};
module.exports = getBrowser;
const getBrowser = require('./getBrowser');
const BASE_URL = `http://localhost:${process.env.PORT || 8000}`;
let browser;
let page;
beforeAll(async () => {
browser = await getBrowser();
});
beforeEach(async () => {
page = await browser.newPage();
await page.goto(`${BASE_URL}`);
await page.evaluate(() => {
localStorage.setItem('antd-pro-authority', '["admin"]');
});
});
describe('Homepage', () => {
it('topmenu should have footer', async () => {
const params = '?navTheme=light&layout=topmenu';
......@@ -13,3 +30,7 @@ describe('Homepage', () => {
expect(haveFooter).toBeTruthy();
});
});
afterAll(() => {
browser.close();
});
import { Button, message, notification } from 'antd';
import React from 'react';
import { formatMessage } from 'umi-plugin-react/locale';
import { formatMessage } from 'umi';
import defaultSettings from '../config/defaultSettings';
const { pwa } = defaultSettings;
......
......@@ -9,11 +9,8 @@ import ProLayout, {
Settings,
DefaultFooter,
} from '@ant-design/pro-layout';
import { formatMessage } from 'umi-plugin-react/locale';
import React, { useEffect } from 'react';
import { Link } from 'umi';
import { Dispatch } from 'redux';
import { connect } from 'dva';
import { Link, useIntl, connect, Dispatch } from 'umi';
import { GithubOutlined } from '@ant-design/icons';
import { Result, Button } from 'antd';
import Authorized from '@/utils/Authorized';
......@@ -121,6 +118,8 @@ const BasicLayout: React.FC<BasicLayoutProps> = props => {
const authorized = getAuthorityFromRouter(props.route.routes, location.pathname || '/') || {
authority: undefined,
};
const { formatMessage } = useIntl();
return (
<ProLayout
logo={logo}
......
import React from 'react';
import { connect } from 'dva';
import { PageLoading } from '@ant-design/pro-layout';
import { Redirect } from 'umi';
import { Redirect, connect, ConnectProps } from 'umi';
import { stringify } from 'querystring';
import { ConnectState, ConnectProps } from '@/models/connect';
import { ConnectState } from '@/models/connect';
import { CurrentUser } from '@/models/user';
interface SecurityLayoutProps extends ConnectProps {
......
import { DefaultFooter, MenuDataItem, getMenuData, getPageTitle } from '@ant-design/pro-layout';
import { Helmet } from 'react-helmet';
import { Link } from 'umi';
import { Link, useIntl, ConnectProps, connect } from 'umi';
import React from 'react';
import { formatMessage } from 'umi-plugin-react/locale';
import { connect } from 'dva';
import SelectLang from '@/components/SelectLang';
import { ConnectProps, ConnectState } from '@/models/connect';
import { ConnectState } from '@/models/connect';
import logo from '../assets/logo.svg';
import styles from './UserLayout.less';
export interface UserLayoutProps extends ConnectProps {
export interface UserLayoutProps extends Partial<ConnectProps> {
breadcrumbNameMap: {
[path: string]: MenuDataItem;
};
......@@ -28,6 +26,7 @@ const UserLayout: React.FC<UserLayoutProps> = props => {
pathname: '',
},
} = props;
const { formatMessage } = useIntl();
const { breadcrumb } = getMenuData(routes);
const title = getPageTitle({
pathname: location.pathname,
......
import { AnyAction } from 'redux';
import { MenuDataItem } from '@ant-design/pro-layout';
import { RouterTypes } from 'umi';
import { GlobalModelState } from './global';
import { DefaultSettings as SettingModelState } from '../../config/defaultSettings';
import { UserModelState } from './user';
......@@ -31,10 +29,3 @@ export interface ConnectState {
export interface Route extends MenuDataItem {
routes?: Route[];
}
/**
* @type T: Params matched in dynamic routing
*/
export interface ConnectProps<T = {}> extends Partial<RouterTypes<Route, T>> {
dispatch?: Dispatch<AnyAction>;
}
import { Reducer } from 'redux';
import { Subscription, Effect } from 'dva';
import { Subscription, Reducer, Effect } from 'umi';
import { NoticeIconData } from '@/components/NoticeIcon';
import { queryNotices } from '@/services/user';
......
import { Reducer } from 'redux';
import { Effect } from 'dva';
import { stringify } from 'querystring';
import { router } from 'umi';
import { history, Reducer, Effect } from 'umi';
import { fakeAccountLogin } from '@/services/login';
import { setAuthority } from '@/utils/authority';
......@@ -56,7 +54,7 @@ const Model: LoginModelType = {
return;
}
}
router.replace(redirect || '/');
history.replace(redirect || '/');
}
},
......@@ -64,7 +62,7 @@ const Model: LoginModelType = {
const { redirect } = getPageQuery();
// Note: There may be security issues, please note
if (window.location.pathname !== '/user/login' && !redirect) {
router.replace({
history.replace({
pathname: '/user/login',
search: stringify({
redirect: window.location.href,
......
import { Reducer } from 'redux';
import { Reducer } from 'umi';
import defaultSettings, { DefaultSettings } from '../../config/defaultSettings';
export interface SettingModelType {
......
import { Effect } from 'dva';
import { Reducer } from 'redux';
import { Effect, Reducer } from 'umi';
import { queryCurrent, query as queryUsers } from '@/services/user';
......
import { Button, Result } from 'antd';
import React from 'react';
import { router } from 'umi';
import { history } from 'umi';
const NoFoundPage: React.FC<{}> = () => (
<Result
......@@ -8,7 +8,7 @@ const NoFoundPage: React.FC<{}> = () => (
title="404"
subTitle="Sorry, the page you visited does not exist."
extra={
<Button type="primary" onClick={() => router.push('/')}>
<Button type="primary" onClick={() => history.push('/')}>
Back Home
</Button>
}
......
import React from 'react';
import { Redirect } from 'umi';
import { connect } from 'dva';
import { Redirect, connect, ConnectProps } from 'umi';
import Authorized from '@/utils/Authorized';
import { getRouteAuthority } from '@/utils/utils';
import { ConnectProps, ConnectState, UserModelState } from '@/models/connect';
import { ConnectState, UserModelState } from '@/models/connect';
interface AuthComponentProps extends ConnectProps {
user: UserModelState;
......
......@@ -33,7 +33,7 @@ interface LoginType extends React.FC<LoginProps> {
const Login: LoginType = props => {
const { className } = props;
const [tabs, setTabs] = useState<string[]>([]);
const [active, setActive] = useState();
const [active, setActive] = useState({});
const [type, setType] = useMergeValue('', {
value: props.activeKey,
onChange: props.onTabChange,
......@@ -65,6 +65,7 @@ const Login: LoginType = props => {
},
},
updateActive: activeItem => {
if (!active) return;
if (active[type]) {
active[type].push(activeItem);
} else {
......
import { AlipayCircleOutlined, TaobaoCircleOutlined, WeiboCircleOutlined } from '@ant-design/icons';
import { Alert, Checkbox } from 'antd';
import React, { useState } from 'react';
import { Dispatch, AnyAction } from 'redux';
import { Link } from 'umi';
import { connect } from 'dva';
import { Link, connect, Dispatch } from 'umi';
import { StateType } from '@/models/login';
import { LoginParamsType } from '@/services/login';
import { ConnectState } from '@/models/connect';
......@@ -13,7 +11,7 @@ import styles from './style.less';
const { Tab, UserName, Password, Mobile, Captcha, Submit } = LoginFrom;
interface LoginProps {
dispatch: Dispatch<AnyAction>;
dispatch: Dispatch;
userLogin: StateType;
submitting?: boolean;
}
......
import { getAuthority } from './authority';
describe('getAuthority should be strong', () => {
it('string', () => {
expect(getAuthority('admin')).toEqual(['admin']);
});
it('array with double quotes', () => {
expect(getAuthority('"admin"')).toEqual(['admin']);
});
it('array with single item', () => {
expect(getAuthority('["admin"]')).toEqual(['admin']);
});
it('array with multiple items', () => {
expect(getAuthority('["admin", "guest"]')).toEqual(['admin', 'guest']);
});
});
......@@ -18,19 +18,9 @@
"experimentalDecorators": true,
"strict": true,
"paths": {
"@/*": ["./src/*"]
"@/*": ["./src/*"],
"@@/*": ["./src/.umi/*"]
}
},
"exclude": [
"node_modules",
"build",
"dist",
"scripts",
"acceptance-tests",
"webpack",
"jest",
"src/setupTests.ts",
"tslint:latest",
"tslint-config-prettier"
]
"exclude": ["node_modules", "build", "dist", "scripts", "src/.umi/*", "webpack", "jest"]
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册