From 06dd7fa6216860344e04a02d22af6efe33defa21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BF=A1=E9=91=AB-King?= Date: Mon, 23 Mar 2020 10:19:21 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20features:=20use=20umi=203=20(#6039)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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: chenshuai2144 --- .github/workflows/deploy.yml | 5 +- .prettierignore | 1 + config/config.ts | 153 ++++++------------ config/themePluginConfig.ts | 115 ------------- jest-puppeteer.config.js | 12 -- jest.config.js | 1 - .../_mock.ts => mock/listTableList.ts | 18 +-- package.json | 34 ++-- src/components/Authorized/Authorized.tsx | 2 +- .../GlobalHeader/AvatarDropdown.tsx | 9 +- .../GlobalHeader/NoticeIconView.tsx | 6 +- src/components/GlobalHeader/RightContent.tsx | 6 +- src/components/SelectLang/index.tsx | 2 +- src/e2e/baseLayout.e2e.js | 14 ++ src/e2e/getBrowser.js | 16 ++ src/e2e/topMenu.e2e.js | 21 +++ src/global.tsx | 2 +- src/layouts/BasicLayout.tsx | 7 +- src/layouts/SecurityLayout.tsx | 5 +- src/layouts/UserLayout.tsx | 9 +- src/models/connect.d.ts | 9 -- src/models/global.ts | 3 +- src/models/login.ts | 8 +- src/models/setting.ts | 2 +- src/models/user.ts | 3 +- src/pages/404.tsx | 4 +- src/pages/Authorized.tsx | 5 +- .../user/login/components/Login/index.tsx | 3 +- src/pages/user/login/index.tsx | 6 +- src/utils/authority.test.ts | 16 -- tsconfig.json | 16 +- 31 files changed, 162 insertions(+), 351 deletions(-) delete mode 100644 config/themePluginConfig.ts delete mode 100644 jest-puppeteer.config.js rename src/pages/ListTableList/_mock.ts => mock/listTableList.ts (89%) create mode 100644 src/e2e/getBrowser.js delete mode 100644 src/utils/authority.test.ts diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index be2fb600..1af65871 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -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 diff --git a/.prettierignore b/.prettierignore index 87715a7d..5456c4fd 100644 --- a/.prettierignore +++ b/.prettierignore @@ -19,3 +19,4 @@ LICENSE yarn-error.log .history CNAME +/build diff --git a/config/config.ts b/config/config.ts index 4b2b9911..bbea2fcd 100644 --- a/config/config.ts +++ b/config/config.ts @@ -1,87 +1,32 @@ -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; +}); diff --git a/config/themePluginConfig.ts b/config/themePluginConfig.ts deleted file mode 100644 index af48f534..00000000 --- a/config/themePluginConfig.ts +++ /dev/null @@ -1,115 +0,0 @@ -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', - }, - }, - ], -}; diff --git a/jest-puppeteer.config.js b/jest-puppeteer.config.js deleted file mode 100644 index 21b41e4a..00000000 --- a/jest-puppeteer.config.js +++ /dev/null @@ -1,12 +0,0 @@ -// ps https://github.com/GoogleChrome/puppeteer/issues/3120 -module.exports = { - launch: { - args: [ - '--disable-gpu', - '--disable-dev-shm-usage', - '--no-first-run', - '--no-zygote', - '--no-sandbox', - ], - }, -}; diff --git a/jest.config.js b/jest.config.js index 832d1936..c82d7f10 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,6 +1,5 @@ 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, diff --git a/src/pages/ListTableList/_mock.ts b/mock/listTableList.ts similarity index 89% rename from src/pages/ListTableList/_mock.ts rename to mock/listTableList.ts index 308ca8e8..c5784681 100644 --- a/src/pages/ListTableList/_mock.ts +++ b/mock/listTableList.ts @@ -1,7 +1,7 @@ // 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; diff --git a/package.json b/package.json index e4b0ae6a..17aa2067 100644 --- a/package.json +++ b/package.json @@ -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" diff --git a/src/components/Authorized/Authorized.tsx b/src/components/Authorized/Authorized.tsx index 36af4c63..d91b7b55 100644 --- a/src/components/Authorized/Authorized.tsx +++ b/src/components/Authorized/Authorized.tsx @@ -21,7 +21,7 @@ const Authorized: React.FunctionComponent = ({ authority, noMatch = ( diff --git a/src/components/GlobalHeader/AvatarDropdown.tsx b/src/components/GlobalHeader/AvatarDropdown.tsx index aedf473f..65db2724 100644 --- a/src/components/GlobalHeader/AvatarDropdown.tsx +++ b/src/components/GlobalHeader/AvatarDropdown.tsx @@ -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 { currentUser?: CurrentUser; menu?: boolean; } @@ -30,7 +29,7 @@ class AvatarDropdown extends React.Component { return; } - router.push(`/account/${key}`); + history.push(`/account/${key}`); }; render(): React.ReactNode { diff --git a/src/components/GlobalHeader/NoticeIconView.tsx b/src/components/GlobalHeader/NoticeIconView.tsx index c7102d99..7658896a 100644 --- a/src/components/GlobalHeader/NoticeIconView.tsx +++ b/src/components/GlobalHeader/NoticeIconView.tsx @@ -1,15 +1,15 @@ 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 { notices?: NoticeItem[]; currentUser?: CurrentUser; fetchingNotices?: boolean; diff --git a/src/components/GlobalHeader/RightContent.tsx b/src/components/GlobalHeader/RightContent.tsx index 3040cebd..90e4dcb9 100644 --- a/src/components/GlobalHeader/RightContent.tsx +++ b/src/components/GlobalHeader/RightContent.tsx @@ -1,15 +1,15 @@ 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 { theme?: SiderTheme; layout: 'sidemenu' | 'topmenu'; } diff --git a/src/components/SelectLang/index.tsx b/src/components/SelectLang/index.tsx index 95df015e..b23b5eb0 100644 --- a/src/components/SelectLang/index.tsx +++ b/src/components/SelectLang/index.tsx @@ -1,6 +1,6 @@ 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'; diff --git a/src/e2e/baseLayout.e2e.js b/src/e2e/baseLayout.e2e.js index 2e9a291d..21dc245d 100644 --- a/src/e2e/baseLayout.e2e.js +++ b/src/e2e/baseLayout.e2e.js @@ -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(); +}); diff --git a/src/e2e/getBrowser.js b/src/e2e/getBrowser.js new file mode 100644 index 00000000..f6eb1f41 --- /dev/null +++ b/src/e2e/getBrowser.js @@ -0,0 +1,16 @@ +import puppeteer from 'puppeteer'; + +const getBrowser = async () => { + const browser = await puppeteer.launch({ + args: [ + '--disable-gpu', + '--disable-dev-shm-usage', + '--no-first-run', + '--no-zygote', + '--no-sandbox', + ], + }); + return browser; +}; + +module.exports = getBrowser; diff --git a/src/e2e/topMenu.e2e.js b/src/e2e/topMenu.e2e.js index a2b221c5..fe5b472c 100644 --- a/src/e2e/topMenu.e2e.js +++ b/src/e2e/topMenu.e2e.js @@ -1,5 +1,22 @@ +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(); +}); diff --git a/src/global.tsx b/src/global.tsx index 626399fb..21d4138a 100644 --- a/src/global.tsx +++ b/src/global.tsx @@ -1,7 +1,7 @@ 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; diff --git a/src/layouts/BasicLayout.tsx b/src/layouts/BasicLayout.tsx index d2057106..e3d4e9c3 100644 --- a/src/layouts/BasicLayout.tsx +++ b/src/layouts/BasicLayout.tsx @@ -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 = props => { const authorized = getAuthorityFromRouter(props.route.routes, location.pathname || '/') || { authority: undefined, }; + const { formatMessage } = useIntl(); + return ( { breadcrumbNameMap: { [path: string]: MenuDataItem; }; @@ -28,6 +26,7 @@ const UserLayout: React.FC = props => { pathname: '', }, } = props; + const { formatMessage } = useIntl(); const { breadcrumb } = getMenuData(routes); const title = getPageTitle({ pathname: location.pathname, diff --git a/src/models/connect.d.ts b/src/models/connect.d.ts index 3fc53f6d..a0696dc0 100644 --- a/src/models/connect.d.ts +++ b/src/models/connect.d.ts @@ -1,6 +1,4 @@ -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 extends Partial> { - dispatch?: Dispatch; -} diff --git a/src/models/global.ts b/src/models/global.ts index e1434020..3200a7fa 100644 --- a/src/models/global.ts +++ b/src/models/global.ts @@ -1,5 +1,4 @@ -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'; diff --git a/src/models/login.ts b/src/models/login.ts index 671a15a7..2a323c18 100644 --- a/src/models/login.ts +++ b/src/models/login.ts @@ -1,7 +1,5 @@ -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, diff --git a/src/models/setting.ts b/src/models/setting.ts index 22d9f384..59fa70a6 100644 --- a/src/models/setting.ts +++ b/src/models/setting.ts @@ -1,4 +1,4 @@ -import { Reducer } from 'redux'; +import { Reducer } from 'umi'; import defaultSettings, { DefaultSettings } from '../../config/defaultSettings'; export interface SettingModelType { diff --git a/src/models/user.ts b/src/models/user.ts index 360ba8e6..ff5160df 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -1,5 +1,4 @@ -import { Effect } from 'dva'; -import { Reducer } from 'redux'; +import { Effect, Reducer } from 'umi'; import { queryCurrent, query as queryUsers } from '@/services/user'; diff --git a/src/pages/404.tsx b/src/pages/404.tsx index 8c74e250..7e65e2b4 100644 --- a/src/pages/404.tsx +++ b/src/pages/404.tsx @@ -1,6 +1,6 @@ import { Button, Result } from 'antd'; import React from 'react'; -import { router } from 'umi'; +import { history } from 'umi'; const NoFoundPage: React.FC<{}> = () => ( = () => ( title="404" subTitle="Sorry, the page you visited does not exist." extra={ - } diff --git a/src/pages/Authorized.tsx b/src/pages/Authorized.tsx index d685a797..468543d6 100644 --- a/src/pages/Authorized.tsx +++ b/src/pages/Authorized.tsx @@ -1,9 +1,8 @@ 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; diff --git a/src/pages/user/login/components/Login/index.tsx b/src/pages/user/login/components/Login/index.tsx index 4148c252..8e9f680b 100644 --- a/src/pages/user/login/components/Login/index.tsx +++ b/src/pages/user/login/components/Login/index.tsx @@ -33,7 +33,7 @@ interface LoginType extends React.FC { const Login: LoginType = props => { const { className } = props; const [tabs, setTabs] = useState([]); - 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 { diff --git a/src/pages/user/login/index.tsx b/src/pages/user/login/index.tsx index a5533152..5502e7c9 100644 --- a/src/pages/user/login/index.tsx +++ b/src/pages/user/login/index.tsx @@ -1,9 +1,7 @@ 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; + dispatch: Dispatch; userLogin: StateType; submitting?: boolean; } diff --git a/src/utils/authority.test.ts b/src/utils/authority.test.ts deleted file mode 100644 index 44d74bbd..00000000 --- a/src/utils/authority.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -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']); - }); -}); diff --git a/tsconfig.json b/tsconfig.json index 0f89889e..d50aa7d2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -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"] }