Unverified Commit 277ea601 authored by 陈帅's avatar 陈帅 Committed by GitHub

fix ts file error for eslint (#4336)

* fix ts file error for eslint

* add format-imports script

* sort all code

* remove lint:ts

* remove tslint

* remove lint:ts

* up layout

* remove a empty test

* rm tslint config

* use umi config

* prettier all code

* use @umijs/fabric

* [CodeFactor] Apply fixes to commit 69d4f9a

[ci skip] [skip ci]
parent 98be9f18
const fabric = require('@umijs/fabric');
module.exports = { module.exports = {
parser: 'babel-eslint', ...fabric.default,
extends: ['airbnb', 'prettier', 'plugin:compat/recommended'], rules: {
env: { ...fabric.default.rules,
browser: true,
node: true,
es6: true,
mocha: true,
jest: true,
jasmine: true,
}, },
globals: { globals: {
page: true,
ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true, ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true,
}, page: true,
rules: {
'react/jsx-filename-extension': [1, { extensions: ['.js'] }],
'react/jsx-wrap-multilines': 0,
'react/prop-types': 0,
'react/forbid-prop-types': 0,
'react/jsx-one-expression-per-line': 0,
'import/no-unresolved': [2, { ignore: ['^@/', '^umi/'] }],
'import/no-extraneous-dependencies': [
2,
{
optionalDependencies: true,
devDependencies: ['**/tests/**.js', '/mock/**/**.js', '**/**.test.js'],
},
],
'import/no-cycle': 0,
'jsx-a11y/no-noninteractive-element-interactions': 0,
'jsx-a11y/click-events-have-key-events': 0,
'jsx-a11y/no-static-element-interactions': 0,
'jsx-a11y/anchor-is-valid': 0,
'linebreak-style': 0,
},
settings: {
// support import modules from TypeScript files in JavaScript files
'import/resolver': { node: { extensions: ['.js', '.ts', '.tsx'] } },
polyfills: ['fetch', 'promises', 'url', 'object-assign'],
}, },
}; };
...@@ -34,4 +34,5 @@ functions/* ...@@ -34,4 +34,5 @@ functions/*
# screenshot # screenshot
screenshot screenshot
.firebase .firebase
\ No newline at end of file .eslintcache
...@@ -13,4 +13,7 @@ docker ...@@ -13,4 +13,7 @@ docker
Dockerfile* Dockerfile*
.gitignore .gitignore
.prettierignore .prettierignore
LICENSE LICENSE
\ No newline at end of file .eslintcache
*.lock
yarn-error.log
\ No newline at end of file
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 100,
"proseWrap": "never",
"overrides": [
{
"files": ".prettierrc",
"options": {
"parser": "json"
}
},
{
"files": "document.ejs",
"options": {
"parser": "html"
}
}
]
}
const fabric = require('@umijs/fabric');
module.exports = {
...fabric.prettier,
};
const fabric = require('@umijs/fabric');
module.exports = {
...fabric.stylelint,
};
{
"extends": [
"stylelint-config-standard",
"stylelint-config-css-modules",
"stylelint-config-rational-order",
"stylelint-config-prettier"
],
"plugins": ["stylelint-order", "stylelint-declaration-block-no-ignored-properties"],
"rules": {
"no-descending-specificity": null,
"plugin/declaration-block-no-ignored-properties": true
}
}
import { IConfig, IPlugin } from 'umi-types';
import defaultSettings from './defaultSettings';
// https://umijs.org/config/ // https://umijs.org/config/
import os from 'os'; import os from 'os';
import slash from 'slash2'; import slash from 'slash2';
import { IPlugin, IConfig } from 'umi-types';
import defaultSettings from './defaultSettings';
import webpackPlugin from './plugin.config'; import webpackPlugin from './plugin.config';
const { pwa, primaryColor } = defaultSettings; const { pwa, primaryColor } = defaultSettings;
// preview.pro.ant.design only do not use in your production ; // preview.pro.ant.design only do not use in your production ;
......
// Change theme plugin // Change theme plugin
// eslint-disable-next-line eslint-comments/abdeils - enable - pair;
// import MergeLessPlugin from 'antd-pro-merge-less'; /* eslint-disable import/no-extraneous-dependencies */
// import AntDesignThemePlugin from 'antd-theme-webpack-plugin';
import ThemeColorReplacer from 'webpack-theme-color-replacer'; import ThemeColorReplacer from 'webpack-theme-color-replacer';
import path from 'path';
import generate from '@ant-design/colors/lib/generate'; import generate from '@ant-design/colors/lib/generate';
import path from 'path';
function getModulePackageName(module: { context: string }) { function getModulePackageName(module: { context: string }) {
if (!module.context) return null; if (!module.context) return null;
...@@ -107,7 +106,7 @@ const getAntdSerials = (color: string) => { ...@@ -107,7 +106,7 @@ const getAntdSerials = (color: string) => {
const lightNum = 9; const lightNum = 9;
const devide10 = 10; const devide10 = 10;
// 淡化(即less的tint) // 淡化(即less的tint)
const lightens = new Array(lightNum).fill().map((t, i) => { const lightens = new Array(lightNum).fill(undefined).map((_, i: number) => {
return ThemeColorReplacer.varyColor.lighten(color, i / devide10); return ThemeColorReplacer.varyColor.lighten(color, i / devide10);
}); });
const colorPalettes = generate(color); const colorPalettes = generate(color);
......
...@@ -14,25 +14,23 @@ ...@@ -14,25 +14,23 @@
"docker:push": "npm run docker-hub:build && npm run docker:tag && docker push antdesign/ant-design-pro", "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", "docker:tag": "docker tag ant-design-pro antdesign/ant-design-pro",
"fetch:blocks": "node ./scripts/fetch-blocks.js", "fetch:blocks": "node ./scripts/fetch-blocks.js",
"format-imports": "import-sort --write '**/*.{js,jsx,ts,tsx}'",
"functions:build": "netlify-lambda build ./lambda", "functions:build": "netlify-lambda build ./lambda",
"functions:run": "cross-env NODE_ENV=dev netlify-lambda serve ./lambda", "functions:run": "cross-env NODE_ENV=dev netlify-lambda serve ./lambda",
"lint": "npm run lint:js && npm run lint:ts && npm run lint:style && npm run lint:prettier", "lint": "npm run lint:js && npm run lint:style && npm run lint:prettier",
"lint-staged": "lint-staged", "lint-staged": "lint-staged",
"lint-staged:js": "eslint --ext .js", "lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx ",
"lint-staged:ts": "tslint", "lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src && npm run lint:style",
"lint:fix": "eslint --fix --ext .js src tests && npm run lint:style && npm run tslint:fix", "lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src",
"lint:js": "eslint --ext .js src tests",
"lint:prettier": "check-prettier lint", "lint:prettier": "check-prettier lint",
"lint:style": "stylelint --fix \"src/**/*.less\" --syntax less", "lint:style": "stylelint --fix \"src/**/*.less\" --syntax less",
"lint:ts": "tslint -p . -c tslint.yml", "prettier": "prettier -c --write **/*",
"prettier": "prettier -c --write '**/*'",
"site": "npm run fetch:blocks && npm run functions:build && umi build", "site": "npm run fetch:blocks && npm run functions:build && umi build",
"start": "umi dev", "start": "umi dev",
"start:no-mock": "cross-env MOCK=none umi dev", "start:no-mock": "cross-env MOCK=none umi dev",
"test": "umi test", "test": "umi test",
"test:all": "node ./tests/run-tests.js", "test:all": "node ./tests/run-tests.js",
"test:component": "umi test ./src/components", "test:component": "umi test ./src/components"
"tslint:fix": "tslint --fix \"src/**/*.ts*\""
}, },
"husky": { "husky": {
"hooks": { "hooks": {
...@@ -41,12 +39,12 @@ ...@@ -41,12 +39,12 @@
}, },
"lint-staged": { "lint-staged": {
"**/*.less": "stylelint --syntax less", "**/*.less": "stylelint --syntax less",
"**/*.{js,jsx}": "npm run lint-staged:js",
"**/*.{js,jsx,tsx,ts,less,md,json}": [ "**/*.{js,jsx,tsx,ts,less,md,json}": [
"prettier --write", "prettier --write",
"git add" "git add"
], ],
"**/*.{ts,tsx}": "npm run lint-staged:ts" "**/*.{js,jsx}": "npm run lint-staged:js",
"**/*.{js,ts,tsx}": "npm run lint-staged:js"
}, },
"browserslist": [ "browserslist": [
"> 1%", "> 1%",
...@@ -54,7 +52,7 @@ ...@@ -54,7 +52,7 @@
"not ie <= 10" "not ie <= 10"
], ],
"dependencies": { "dependencies": {
"@ant-design/pro-layout": "^4.4.2", "@ant-design/pro-layout": "^4.5.0",
"@antv/data-set": "^0.10.2", "@antv/data-set": "^0.10.2",
"antd": "^3.19.1", "antd": "^3.19.1",
"classnames": "^2.2.6", "classnames": "^2.2.6",
...@@ -75,6 +73,7 @@ ...@@ -75,6 +73,7 @@
"react-dom": "^16.8.6", "react-dom": "^16.8.6",
"react-media": "^1.9.2", "react-media": "^1.9.2",
"react-media-hook2": "^1.0.5", "react-media-hook2": "^1.0.5",
"redux": "^4.0.1",
"umi": "^2.7.2", "umi": "^2.7.2",
"umi-plugin-ga": "^1.1.3", "umi-plugin-ga": "^1.1.3",
"umi-plugin-pro-block": "^1.3.2", "umi-plugin-pro-block": "^1.3.2",
...@@ -82,6 +81,7 @@ ...@@ -82,6 +81,7 @@
"umi-request": "^1.0.7" "umi-request": "^1.0.7"
}, },
"devDependencies": { "devDependencies": {
"@ant-design/colors": "^3.1.0",
"@types/classnames": "^2.2.7", "@types/classnames": "^2.2.7",
"@types/history": "^4.7.2", "@types/history": "^4.7.2",
"@types/jest": "^24.0.13", "@types/jest": "^24.0.13",
...@@ -90,8 +90,7 @@ ...@@ -90,8 +90,7 @@
"@types/react": "^16.8.19", "@types/react": "^16.8.19",
"@types/react-document-title": "^2.0.3", "@types/react-document-title": "^2.0.3",
"@types/react-dom": "^16.8.4", "@types/react-dom": "^16.8.4",
"antd-pro-merge-less": "^1.0.0", "@umijs/fabric": "^1.0.4",
"@ant-design/colors": "^3.1.0",
"babel-eslint": "^10.0.1", "babel-eslint": "^10.0.1",
"chalk": "^2.4.2", "chalk": "^2.4.2",
"check-prettier": "^1.0.3", "check-prettier": "^1.0.3",
...@@ -99,20 +98,15 @@ ...@@ -99,20 +98,15 @@
"cross-port-killer": "^1.1.1", "cross-port-killer": "^1.1.1",
"enzyme": "^3.9.0", "enzyme": "^3.9.0",
"eslint": "^5.16.0", "eslint": "^5.16.0",
"eslint-config-airbnb": "^17.1.0",
"eslint-config-prettier": "^4.3.0",
"eslint-plugin-babel": "^5.3.0",
"eslint-plugin-compat": "^3.1.1",
"eslint-plugin-import": "^2.17.3",
"eslint-plugin-jsx-a11y": "^6.2.1",
"eslint-plugin-markdown": "^1.0.0",
"eslint-plugin-react": "^7.13.0",
"express": "^4.17.1", "express": "^4.17.1",
"gh-pages": "^2.0.1", "gh-pages": "^2.0.1",
"husky": "^2.3.0", "husky": "^2.3.0",
"import-sort-cli": "^6.0.0",
"import-sort-parser-babylon": "^6.0.0",
"import-sort-parser-typescript": "^6.0.0",
"import-sort-style-module": "^6.0.0",
"jest-puppeteer": "^4.2.0", "jest-puppeteer": "^4.2.0",
"jsdom-global": "^3.0.2", "jsdom-global": "^3.0.2",
"less": "^3.9.0",
"lint-staged": "^8.1.7", "lint-staged": "^8.1.7",
"mockjs": "^1.0.1-beta3", "mockjs": "^1.0.1-beta3",
"netlify-lambda": "^1.4.13", "netlify-lambda": "^1.4.13",
...@@ -120,17 +114,6 @@ ...@@ -120,17 +114,6 @@
"prettier": "^1.17.1", "prettier": "^1.17.1",
"serverless-http": "^2.0.2", "serverless-http": "^2.0.2",
"slash2": "^2.0.0", "slash2": "^2.0.0",
"stylelint": "^10.0.1",
"stylelint-config-css-modules": "^1.4.0",
"stylelint-config-prettier": "^5.2.0",
"stylelint-config-rational-order": "^0.1.2",
"stylelint-config-standard": "^18.3.0",
"stylelint-declaration-block-no-ignored-properties": "^2.1.0",
"stylelint-order": "^3.0.0",
"tslint": "^5.17.0",
"tslint-config-prettier": "^1.18.0",
"tslint-eslint-rules": "^5.4.0",
"tslint-react": "^4.0.0",
"webpack-theme-color-replacer": "^1.1.5" "webpack-theme-color-replacer": "^1.1.5"
}, },
"optionalDependencies": { "optionalDependencies": {
...@@ -174,4 +157,4 @@ ...@@ -174,4 +157,4 @@
"create-umi" "create-umi"
] ]
} }
} }
\ No newline at end of file
import CheckPermissions from './CheckPermissions';
import { IAuthorityType } from './CheckPermissions';
import Secured from './Secured';
import check from './CheckPermissions';
import AuthorizedRoute from './AuthorizedRoute';
import React from 'react'; import React from 'react';
import check, { IAuthorityType } from './CheckPermissions';
import AuthorizedRoute from './AuthorizedRoute';
import Secured from './Secured';
interface IAuthorizedProps { interface AuthorizedProps {
authority: IAuthorityType; authority: IAuthorityType;
noMatch?: React.ReactNode; noMatch?: React.ReactNode;
} }
type IAuthorizedType = React.FunctionComponent<IAuthorizedProps> & { type IAuthorizedType = React.FunctionComponent<AuthorizedProps> & {
Secured: typeof Secured; Secured: typeof Secured;
check: typeof check; check: typeof check;
AuthorizedRoute: typeof AuthorizedRoute; AuthorizedRoute: typeof AuthorizedRoute;
}; };
const Authorized: React.FunctionComponent<IAuthorizedProps> = ({ const Authorized: React.FunctionComponent<AuthorizedProps> = ({
children, children,
authority, authority,
noMatch = null, noMatch = null,
}) => { }) => {
const childrenRender: React.ReactNode = typeof children === 'undefined' ? null : children; const childrenRender: React.ReactNode = typeof children === 'undefined' ? null : children;
const dom = CheckPermissions(authority, childrenRender, noMatch); const dom = check(authority, childrenRender, noMatch);
return <>{dom}</>; return <>{dom}</>;
}; };
......
import { Redirect, Route } from 'umi';
import React from 'react'; import React from 'react';
import { Route, Redirect } from 'umi';
import Authorized from './Authorized'; import Authorized from './Authorized';
import { IAuthorityType } from './CheckPermissions'; import { IAuthorityType } from './CheckPermissions';
interface IAuthorizedRoutePops { interface AuthorizedRoutePops {
currentAuthority: string; currentAuthority: string;
component: React.ComponentClass<any, any>; component: React.ComponentClass<any, any>;
render: (props: any) => React.ReactNode; render: (props: any) => React.ReactNode;
...@@ -11,7 +12,7 @@ interface IAuthorizedRoutePops { ...@@ -11,7 +12,7 @@ interface IAuthorizedRoutePops {
authority: IAuthorityType; authority: IAuthorityType;
} }
const AuthorizedRoute: React.SFC<IAuthorizedRoutePops> = ({ const AuthorizedRoute: React.SFC<AuthorizedRoutePops> = ({
component: Component, component: Component,
render, render,
authority, authority,
......
import React from 'react'; import React from 'react';
import { CURRENT } from './renderAuthorize';
// eslint-disable-next-line import/no-cycle // eslint-disable-next-line import/no-cycle
import PromiseRender from './PromiseRender'; import PromiseRender from './PromiseRender';
import { CURRENT } from './renderAuthorize';
export type IAuthorityType = export type IAuthorityType =
| undefined | undefined
| string | string
| string[] | string[]
| Promise<any> | Promise<boolean>
| ((currentAuthority: string | string[]) => IAuthorityType); | ((currentAuthority: string | string[]) => IAuthorityType);
/** /**
......
import React from 'react';
import { Spin } from 'antd'; import { Spin } from 'antd';
import isEqual from 'lodash/isEqual'; import isEqual from 'lodash/isEqual';
import React from 'react';
// eslint-disable-next-line import/no-cycle
import { isComponentClass } from './Secured'; import { isComponentClass } from './Secured';
// eslint-disable-next-line import/no-cycle
interface IPromiseRenderProps<T, K> { interface PromiseRenderProps<T, K> {
ok: T; ok: T;
error: K; error: K;
promise: Promise<any>; promise: Promise<boolean>;
} }
interface IPromiseRenderState { interface PromiseRenderState {
component: React.ComponentClass<any, any> | React.FunctionComponent<any>; component: React.ComponentClass | React.FunctionComponent;
} }
export default class PromiseRender<T, K> extends React.Component< export default class PromiseRender<T, K> extends React.Component<
IPromiseRenderProps<T, K>, PromiseRenderProps<T, K>,
IPromiseRenderState PromiseRenderState
> { > {
state: IPromiseRenderState = { state: PromiseRenderState = {
component: () => null, component: () => null,
}; };
...@@ -26,10 +26,7 @@ export default class PromiseRender<T, K> extends React.Component< ...@@ -26,10 +26,7 @@ export default class PromiseRender<T, K> extends React.Component<
this.setRenderComponent(this.props); this.setRenderComponent(this.props);
} }
shouldComponentUpdate = ( shouldComponentUpdate = (nextProps: PromiseRenderProps<T, K>, nextState: PromiseRenderState) => {
nextProps: IPromiseRenderProps<T, K>,
nextState: IPromiseRenderState,
) => {
const { component } = this.state; const { component } = this.state;
if (!isEqual(nextProps, this.props)) { if (!isEqual(nextProps, this.props)) {
this.setRenderComponent(nextProps); this.setRenderComponent(nextProps);
...@@ -39,7 +36,7 @@ export default class PromiseRender<T, K> extends React.Component< ...@@ -39,7 +36,7 @@ export default class PromiseRender<T, K> extends React.Component<
}; };
// set render Component : ok or error // set render Component : ok or error
setRenderComponent(props: IPromiseRenderProps<T, K>) { setRenderComponent(props: PromiseRenderProps<T, K>) {
const ok = this.checkIsInstantiation(props.ok); const ok = this.checkIsInstantiation(props.ok);
const error = this.checkIsInstantiation(props.error); const error = this.checkIsInstantiation(props.error);
props.promise props.promise
...@@ -47,6 +44,7 @@ export default class PromiseRender<T, K> extends React.Component< ...@@ -47,6 +44,7 @@ export default class PromiseRender<T, K> extends React.Component<
this.setState({ this.setState({
component: ok, component: ok,
}); });
return true;
}) })
.catch(() => { .catch(() => {
this.setState({ this.setState({
...@@ -60,10 +58,10 @@ export default class PromiseRender<T, K> extends React.Component< ...@@ -60,10 +58,10 @@ export default class PromiseRender<T, K> extends React.Component<
// Authorized render is already instantiated, children is no instantiated // Authorized render is already instantiated, children is no instantiated
// Secured is not instantiated // Secured is not instantiated
checkIsInstantiation = ( checkIsInstantiation = (
target: React.ReactNode | React.ComponentClass<any, any>, target: React.ReactNode | React.ComponentClass,
): React.FunctionComponent<any> => { ): React.FunctionComponent => {
if (isComponentClass(target)) { if (isComponentClass(target)) {
const Target = target as React.ComponentClass<any, any>; const Target = target as React.ComponentClass;
return (props: any) => <Target {...props} />; return (props: any) => <Target {...props} />;
} }
if (React.isValidElement(target)) { if (React.isValidElement(target)) {
...@@ -75,6 +73,7 @@ export default class PromiseRender<T, K> extends React.Component< ...@@ -75,6 +73,7 @@ export default class PromiseRender<T, K> extends React.Component<
render() { render() {
const { component: Component } = this.state; const { component: Component } = this.state;
const { ok, error, promise, ...rest } = this.props; const { ok, error, promise, ...rest } = this.props;
return Component ? ( return Component ? (
<Component {...rest} /> <Component {...rest} />
) : ( ) : (
......
...@@ -7,9 +7,7 @@ import CheckPermissions from './CheckPermissions'; ...@@ -7,9 +7,7 @@ import CheckPermissions from './CheckPermissions';
*/ */
const Exception403 = () => 403; const Exception403 = () => 403;
export const isComponentClass = ( export const isComponentClass = (component: React.ComponentClass | React.ReactNode): boolean => {
component: React.ComponentClass<any, any> | React.ReactNode,
): boolean => {
if (!component) return false; if (!component) return false;
const proto = Object.getPrototypeOf(component); const proto = Object.getPrototypeOf(component);
if (proto === React.Component || proto === Function.prototype) return true; if (proto === React.Component || proto === Function.prototype) return true;
...@@ -20,9 +18,9 @@ export const isComponentClass = ( ...@@ -20,9 +18,9 @@ export const isComponentClass = (
// AuthorizedRoute is already instantiated // AuthorizedRoute is already instantiated
// Authorized render is already instantiated, children is no instantiated // Authorized render is already instantiated, children is no instantiated
// Secured is not instantiated // Secured is not instantiated
const checkIsInstantiation = (target: React.ComponentClass<any, any> | React.ReactNode) => { const checkIsInstantiation = (target: React.ComponentClass | React.ReactNode) => {
if (isComponentClass(target)) { if (isComponentClass(target)) {
const Target = target as React.ComponentClass<any, any>; const Target = target as React.ComponentClass;
return (props: any) => <Target {...props} />; return (props: any) => <Target {...props} />;
} }
if (React.isValidElement(target)) { if (React.isValidElement(target)) {
...@@ -52,14 +50,14 @@ const authorize = (authority: string, error?: React.ReactNode) => { ...@@ -52,14 +50,14 @@ const authorize = (authority: string, error?: React.ReactNode) => {
* 防止传入字符串时找不到staticContext造成报错 * 防止传入字符串时找不到staticContext造成报错
* String parameters can cause staticContext not found error * String parameters can cause staticContext not found error
*/ */
let classError: boolean | React.FunctionComponent<any> = false; let classError: boolean | React.FunctionComponent = false;
if (error) { if (error) {
classError = (() => error) as React.FunctionComponent<any>; classError = (() => error) as React.FunctionComponent;
} }
if (!authority) { if (!authority) {
throw new Error('authority is required'); throw new Error('authority is required');
} }
return function decideAuthority(target: React.ComponentClass<any, any> | React.ReactNode) { return function decideAuthority(target: React.ComponentClass | React.ReactNode) {
const component = CheckPermissions(authority, target, classError || Exception403); const component = CheckPermissions(authority, target, classError || Exception403);
return checkIsInstantiation(component); return checkIsInstantiation(component);
}; };
......
/* eslint-disable eslint-comments/disable-enable-pair */
/* eslint-disable import/no-mutable-exports */
let CURRENT: string | string[] = 'NULL'; let CURRENT: string | string[] = 'NULL';
type CurrentAuthorityType = string | string[] | (() => typeof CURRENT); type CurrentAuthorityType = string | string[] | (() => typeof CURRENT);
/** /**
* use authority or getAuthority * use authority or getAuthority
...@@ -6,7 +9,7 @@ type CurrentAuthorityType = string | string[] | (() => typeof CURRENT); ...@@ -6,7 +9,7 @@ type CurrentAuthorityType = string | string[] | (() => typeof CURRENT);
*/ */
const renderAuthorize = <T>(Authorized: T): ((currentAuthority: CurrentAuthorityType) => T) => ( const renderAuthorize = <T>(Authorized: T): ((currentAuthority: CurrentAuthorityType) => T) => (
currentAuthority: CurrentAuthorityType, currentAuthority: CurrentAuthorityType,
) => { ): T => {
if (currentAuthority) { if (currentAuthority) {
if (typeof currentAuthority === 'function') { if (typeof currentAuthority === 'function') {
CURRENT = currentAuthority(); CURRENT = currentAuthority();
......
import { Icon, Popover, Typography } from 'antd';
import { FormattedMessage } from 'umi-plugin-react/locale';
import React from 'react'; import React from 'react';
import { Icon, Typography, Popover } from 'antd';
import styles from './index.less';
import { connect } from 'dva'; import { connect } from 'dva';
import * as H from 'history';
import { FormattedMessage } from 'umi-plugin-react/locale';
import { isAntDesignPro } from '@/utils/utils'; import { isAntDesignPro } from '@/utils/utils';
import styles from './index.less';
const firstUpperCase = (pathString: string) => { const firstUpperCase = (pathString: string): string =>
return pathString pathString
.replace('.', '') .replace('.', '')
.split(/\/|\-/) .split(/\/|-/)
.map(s => s.toLowerCase().replace(/( |^)[a-z]/g, L => L.toUpperCase())) .map((s): string => s.toLowerCase().replace(/( |^)[a-z]/g, L => L.toUpperCase()))
.filter(s => s) .filter((s): boolean => !!s)
.join(''); .join('');
};
// when click block copy, send block url to ga // when click block copy, send block url to ga
const onBlockCopy = (label: string) => { const onBlockCopy = (label: string) => {
if (!isAntDesignPro()) { if (!isAntDesignPro()) {
return; return;
} }
const ga = window && (window as any).ga; const ga = window && (window as any).ga;
if (ga) { if (ga) {
ga('send', 'event', { ga('send', 'event', {
...@@ -48,7 +48,11 @@ const BlockCodeView: React.SFC<{ ...@@ -48,7 +48,11 @@ const BlockCodeView: React.SFC<{
); );
}; };
type RoutingType = { location: H.Location }; interface RoutingType {
location: {
pathname: string;
};
}
export default connect(({ routing }: { routing: RoutingType }) => ({ export default connect(({ routing }: { routing: RoutingType }) => ({
location: routing.location, location: routing.location,
......
import React from 'react'; import { Avatar, Icon, Menu, Spin } from 'antd';
import { Avatar, Menu, Spin, Icon } from 'antd';
import { FormattedMessage } from 'umi-plugin-react/locale';
import { ClickParam } from 'antd/es/menu';
import { ConnectProps, ConnectState } from '@/models/connect'; import { ConnectProps, ConnectState } from '@/models/connect';
import { ClickParam } from 'antd/es/menu';
import { CurrentUser } from '@/models/user'; import { CurrentUser } from '@/models/user';
import { FormattedMessage } from 'umi-plugin-react/locale';
import React from 'react';
import { connect } from 'dva'; import { connect } from 'dva';
import router from 'umi/router'; import router from 'umi/router';
import HeaderDropdown from '../HeaderDropdown'; import HeaderDropdown from '../HeaderDropdown';
...@@ -30,7 +30,8 @@ class AvatarDropdown extends React.Component<GlobalHeaderRightProps> { ...@@ -30,7 +30,8 @@ class AvatarDropdown extends React.Component<GlobalHeaderRightProps> {
} }
router.push(`/account/${key}`); router.push(`/account/${key}`);
}; };
render() {
render(): React.ReactNode {
const { currentUser = {}, menu } = this.props; const { currentUser = {}, menu } = this.props;
if (!menu) { if (!menu) {
return ( return (
......
import { ConnectProps, ConnectState } from '@/models/connect'; import { ConnectProps, ConnectState } from '@/models/connect';
import { NoticeItem } from '@/models/global';
import { CurrentUser } from '@/models/user';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Tag, message } from 'antd'; import { Tag, message } from 'antd';
import { CurrentUser } from '@/models/user';
import NoticeIcon from '../NoticeIcon';
import { NoticeItem } from '@/models/global';
import { connect } from 'dva';
import { formatMessage } from 'umi-plugin-react/locale'; import { formatMessage } from 'umi-plugin-react/locale';
import moment from 'moment';
import groupBy from 'lodash/groupBy'; import groupBy from 'lodash/groupBy';
import NoticeIcon from '../NoticeIcon'; import moment from 'moment';
import styles from './index.less'; import styles from './index.less';
import { connect } from 'dva';
export interface GlobalHeaderRightProps extends ConnectProps { export interface GlobalHeaderRightProps extends ConnectProps {
notices?: NoticeItem[]; notices?: NoticeItem[];
...@@ -19,6 +20,37 @@ export interface GlobalHeaderRightProps extends ConnectProps { ...@@ -19,6 +20,37 @@ export interface GlobalHeaderRightProps extends ConnectProps {
} }
class GlobalHeaderRight extends Component<GlobalHeaderRightProps> { class GlobalHeaderRight extends Component<GlobalHeaderRightProps> {
componentDidMount() {
const { dispatch } = this.props;
if (dispatch) {
dispatch({
type: 'global/fetchNotices',
});
}
}
changeReadState = (clickedItem: NoticeItem): void => {
const { id } = clickedItem;
const { dispatch } = this.props;
if (dispatch) {
dispatch({
type: 'global/changeNoticeReadState',
payload: id,
});
}
};
handleNoticeClear = (title: string, key: string) => {
const { dispatch } = this.props;
message.success(`${formatMessage({ id: 'component.noticeIcon.cleared' })} ${title}`);
if (dispatch) {
dispatch({
type: 'global/clearNotices',
payload: key,
});
}
};
getNoticeData = (): { [key: string]: NoticeItem[] } => { getNoticeData = (): { [key: string]: NoticeItem[] } => {
const { notices = [] } = this.props; const { notices = [] } = this.props;
if (notices.length === 0) { if (notices.length === 0) {
...@@ -52,7 +84,8 @@ class GlobalHeaderRight extends Component<GlobalHeaderRightProps> { ...@@ -52,7 +84,8 @@ class GlobalHeaderRight extends Component<GlobalHeaderRightProps> {
getUnreadData = (noticeData: { [key: string]: NoticeItem[] }) => { getUnreadData = (noticeData: { [key: string]: NoticeItem[] }) => {
const unreadMsg: { [key: string]: number } = {}; const unreadMsg: { [key: string]: number } = {};
Object.entries(noticeData).forEach(([key, value]) => { Object.keys(noticeData).forEach(key => {
const value = noticeData[key];
if (!unreadMsg[key]) { if (!unreadMsg[key]) {
unreadMsg[key] = 0; unreadMsg[key] = 0;
} }
...@@ -63,34 +96,6 @@ class GlobalHeaderRight extends Component<GlobalHeaderRightProps> { ...@@ -63,34 +96,6 @@ class GlobalHeaderRight extends Component<GlobalHeaderRightProps> {
return unreadMsg; return unreadMsg;
}; };
changeReadState = (clickedItem: NoticeItem) => {
const { id } = clickedItem;
const { dispatch } = this.props;
if (dispatch) {
dispatch({
type: 'global/changeNoticeReadState',
payload: id,
});
}
};
componentDidMount() {
const { dispatch } = this.props;
if (dispatch) {
dispatch({
type: 'global/fetchNotices',
});
}
}
handleNoticeClear = (title: string, key: string) => {
const { dispatch } = this.props;
message.success(`${formatMessage({ id: 'component.noticeIcon.cleared' })} ${title}`);
if (dispatch) {
dispatch({
type: 'global/clearNotices',
payload: key,
});
}
};
render() { render() {
const { currentUser, fetchingNotices, onNoticeVisibleChange } = this.props; const { currentUser, fetchingNotices, onNoticeVisibleChange } = this.props;
const noticeData = this.getNoticeData(); const noticeData = this.getNoticeData();
......
import { ConnectProps, ConnectState } from '@/models/connect'; import { ConnectProps, ConnectState } from '@/models/connect';
import React, { Component } from 'react';
import { Icon, Tooltip } from 'antd'; import { Icon, Tooltip } from 'antd';
import { formatMessage } from 'umi-plugin-react/locale';
import Avatar from './AvatarDropdown';
import HeaderSearch from '../HeaderSearch'; import HeaderSearch from '../HeaderSearch';
import React from 'react';
import SelectLang from '../SelectLang'; import SelectLang from '../SelectLang';
import styles from './index.less';
import Avatar from './AvatarDropdown';
import { connect } from 'dva'; import { connect } from 'dva';
import { formatMessage } from 'umi-plugin-react/locale';
import styles from './index.less';
export type SiderTheme = 'light' | 'dark'; export type SiderTheme = 'light' | 'dark';
export interface GlobalHeaderRightProps extends ConnectProps { export interface GlobalHeaderRightProps extends ConnectProps {
...@@ -14,60 +15,58 @@ export interface GlobalHeaderRightProps extends ConnectProps { ...@@ -14,60 +15,58 @@ export interface GlobalHeaderRightProps extends ConnectProps {
layout: 'sidemenu' | 'topmenu'; layout: 'sidemenu' | 'topmenu';
} }
class GlobalHeaderRight extends Component<GlobalHeaderRightProps> { const GlobalHeaderRight: React.SFC<GlobalHeaderRightProps> = props => {
render() { const { theme, layout } = props;
const { theme, layout } = this.props; let className = styles.right;
let className = styles.right;
if (theme === 'dark' && layout === 'topmenu') { if (theme === 'dark' && layout === 'topmenu') {
className = `${styles.right} ${styles.dark}`; className = `${styles.right} ${styles.dark}`;
} }
return ( return (
<div className={className}> <div className={className}>
<HeaderSearch <HeaderSearch
className={`${styles.action} ${styles.search}`} className={`${styles.action} ${styles.search}`}
placeholder={formatMessage({ placeholder={formatMessage({
id: 'component.globalHeader.search', id: 'component.globalHeader.search',
})} })}
dataSource={[ dataSource={[
formatMessage({ formatMessage({
id: 'component.globalHeader.search.example1', id: 'component.globalHeader.search.example1',
}), }),
formatMessage({ formatMessage({
id: 'component.globalHeader.search.example2', id: 'component.globalHeader.search.example2',
}), }),
formatMessage({ formatMessage({
id: 'component.globalHeader.search.example3', id: 'component.globalHeader.search.example3',
}), }),
]} ]}
onSearch={value => { onSearch={value => {
console.log('input', value); // tslint:disable-line no-console console.log('input', value);
}} }}
onPressEnter={value => { onPressEnter={value => {
console.log('enter', value); // tslint:disable-line no-console console.log('enter', value);
}} }}
/> />
<Tooltip <Tooltip
title={formatMessage({ title={formatMessage({
id: 'component.globalHeader.help', id: 'component.globalHeader.help',
})} })}
>
<a
target="_blank"
href="https://pro.ant.design/docs/getting-started"
rel="noopener noreferrer"
className={styles.action}
> >
<a <Icon type="question-circle-o" />
target="_blank" </a>
href="https://pro.ant.design/docs/getting-started" </Tooltip>
rel="noopener noreferrer" <Avatar />
className={styles.action} <SelectLang className={styles.action} />
> </div>
<Icon type="question-circle-o" /> );
</a> };
</Tooltip>
<Avatar />
<SelectLang className={styles.action} />
</div>
);
}
}
export default connect(({ settings }: ConnectState) => ({ export default connect(({ settings }: ConnectState) => ({
theme: settings.navTheme, theme: settings.navTheme,
......
import React from 'react';
import { Dropdown } from 'antd';
import { DropDownProps } from 'antd/es/dropdown'; import { DropDownProps } from 'antd/es/dropdown';
import { Dropdown } from 'antd';
import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import styles from './index.less'; import styles from './index.less';
......
import { AutoComplete, Icon, Input } from 'antd';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Input, Icon, AutoComplete } from 'antd';
import { DataSourceItemType } from 'antd/es/auto-complete'; import { DataSourceItemType, AutoCompleteProps } from 'antd/es/auto-complete';
import classNames from 'classnames'; import classNames from 'classnames';
import debounce from 'lodash/debounce'; import debounce from 'lodash/debounce';
import styles from './index.less'; import styles from './index.less';
...@@ -45,7 +46,8 @@ export default class HeaderSearch extends Component<HeaderSearchProps, HeaderSea ...@@ -45,7 +46,8 @@ export default class HeaderSearch extends Component<HeaderSearchProps, HeaderSea
return null; return null;
} }
private timeout: NodeJS.Timeout = null!; private timeout: number | undefined = undefined;
private inputRef: Input | null = null; private inputRef: Input | null = null;
constructor(props: HeaderSearchProps) { constructor(props: HeaderSearchProps) {
...@@ -68,20 +70,22 @@ export default class HeaderSearch extends Component<HeaderSearchProps, HeaderSea ...@@ -68,20 +70,22 @@ export default class HeaderSearch extends Component<HeaderSearchProps, HeaderSea
if (e.key === 'Enter') { if (e.key === 'Enter') {
const { onPressEnter } = this.props; const { onPressEnter } = this.props;
const { value } = this.state; const { value } = this.state;
this.timeout = setTimeout(() => { this.timeout = window.setTimeout(() => {
onPressEnter(value); // Fix duplicate onPressEnter onPressEnter(value); // Fix duplicate onPressEnter
}, 0); }, 0);
} }
}; };
onChange = (value: string) => { onChange: AutoCompleteProps['onChange'] = value => {
const { onSearch, onChange } = this.props; if (typeof value === 'string') {
this.setState({ value }); const { onSearch, onChange } = this.props;
if (onSearch) { this.setState({ value });
onSearch(value); if (onSearch) {
} onSearch(value);
if (onChange) { }
onChange(value); if (onChange) {
onChange(value);
}
} }
}; };
...@@ -116,6 +120,7 @@ export default class HeaderSearch extends Component<HeaderSearchProps, HeaderSea ...@@ -116,6 +120,7 @@ export default class HeaderSearch extends Component<HeaderSearchProps, HeaderSea
const inputClass = classNames(styles.input, { const inputClass = classNames(styles.input, {
[styles.show]: searchMode, [styles.show]: searchMode,
}); });
return ( return (
<span <span
className={classNames(className, styles.headerSearch)} className={classNames(className, styles.headerSearch)}
...@@ -133,7 +138,7 @@ export default class HeaderSearch extends Component<HeaderSearchProps, HeaderSea ...@@ -133,7 +138,7 @@ export default class HeaderSearch extends Component<HeaderSearchProps, HeaderSea
{...restProps} {...restProps}
className={inputClass} className={inputClass}
value={value} value={value}
onChange={this.onChange as any} onChange={this.onChange}
> >
<Input <Input
ref={node => { ref={node => {
......
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
} }
.notFound { .notFound {
padding: 73px 0 88px 0; padding: 73px 0 88px;
color: @text-color-secondary; color: @text-color-secondary;
text-align: center; text-align: center;
img { img {
......
import React from 'react';
import { Avatar, List } from 'antd'; import { Avatar, List } from 'antd';
import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import styles from './NoticeList.less';
import { NoticeIconData } from './index'; import { NoticeIconData } from './index';
import styles from './NoticeList.less';
export interface NoticeIconTabProps { export interface NoticeIconTabProps {
count?: number; count?: number;
list?: NoticeIconData[];
name?: string; name?: string;
showClear?: boolean; showClear?: boolean;
showViewMore?: boolean; showViewMore?: boolean;
style?: React.CSSProperties; style?: React.CSSProperties;
title: string; title: string;
tabKey: string; tabKey: string;
data?: any[]; data?: NoticeIconData[];
onClick?: (item: any) => void; onClick?: (item: NoticeIconData) => void;
onClear?: (item: any) => void; onClear?: () => void;
emptyText?: string; emptyText?: string;
clearText?: string; clearText?: string;
viewMoreText?: string; viewMoreText?: string;
......
import { Badge, Icon, Spin, Tabs } from 'antd';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { Icon, Tabs, Badge, Spin } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import HeaderDropdown from '../HeaderDropdown';
import NoticeList, { NoticeIconTabProps } from './NoticeList'; import NoticeList, { NoticeIconTabProps } from './NoticeList';
import HeaderDropdown from '../HeaderDropdown';
import styles from './index.less'; import styles from './index.less';
const { TabPane } = Tabs; const { TabPane } = Tabs;
...@@ -40,11 +41,11 @@ export default class NoticeIcon extends Component<NoticeIconProps> { ...@@ -40,11 +41,11 @@ export default class NoticeIcon extends Component<NoticeIconProps> {
public static Tab: typeof NoticeList = NoticeList; public static Tab: typeof NoticeList = NoticeList;
static defaultProps = { static defaultProps = {
onItemClick: () => {}, onItemClick: (): void => {},
onPopupVisibleChange: () => {}, onPopupVisibleChange: (): void => {},
onTabChange: () => {}, onTabChange: (): void => {},
onClear: () => {}, onClear: (): void => {},
onViewMore: () => {}, onViewMore: (): void => {},
loading: false, loading: false,
clearClose: false, clearClose: false,
emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg', emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg',
...@@ -54,64 +55,67 @@ export default class NoticeIcon extends Component<NoticeIconProps> { ...@@ -54,64 +55,67 @@ export default class NoticeIcon extends Component<NoticeIconProps> {
visible: false, visible: false,
}; };
onItemClick = (item: NoticeIconData, tabProps: NoticeIconTabProps) => { onItemClick = (item: NoticeIconData, tabProps: NoticeIconTabProps): void => {
const { onItemClick } = this.props; const { onItemClick } = this.props;
if (onItemClick) { if (onItemClick) {
onItemClick(item, tabProps); onItemClick(item, tabProps);
} }
}; };
onClear = (name: string, key: string) => { onClear = (name: string, key: string): void => {
const { onClear } = this.props; const { onClear } = this.props;
if (onClear) { if (onClear) {
onClear(name, key); onClear(name, key);
} }
}; };
onTabChange = (tabType: string) => { onTabChange = (tabType: string): void => {
const { onTabChange } = this.props; const { onTabChange } = this.props;
if (onTabChange) { if (onTabChange) {
onTabChange(tabType); onTabChange(tabType);
} }
}; };
onViewMore = (tabProps: NoticeIconTabProps, event: MouseEvent) => { onViewMore = (tabProps: NoticeIconTabProps, event: MouseEvent): void => {
const { onViewMore } = this.props; const { onViewMore } = this.props;
if (onViewMore) { if (onViewMore) {
onViewMore(tabProps, event); onViewMore(tabProps, event);
} }
}; };
getNotificationBox() { getNotificationBox(): React.ReactNode {
const { children, loading, clearText, viewMoreText } = this.props; const { children, loading, clearText, viewMoreText } = this.props;
if (!children) { if (!children) {
return null; return null;
} }
const panes = React.Children.map(children, (child: React.ReactElement<NoticeIconTabProps>) => { const panes = React.Children.map(
if (!child) { children,
return null; (child: React.ReactElement<NoticeIconTabProps>): React.ReactNode => {
} if (!child) {
const { list, title, count, tabKey, showClear, showViewMore } = child.props; return null;
const len = list && list.length ? list.length : 0; }
const msgCount = count || count === 0 ? count : len; const { list, title, count, tabKey, showClear, showViewMore } = child.props;
const tabTitle: string = msgCount > 0 ? `${title} (${msgCount})` : title; const len = list && list.length ? list.length : 0;
return ( const msgCount = count || count === 0 ? count : len;
<TabPane tab={tabTitle} key={title}> const tabTitle: string = msgCount > 0 ? `${title} (${msgCount})` : title;
<NoticeList return (
clearText={clearText} <TabPane tab={tabTitle} key={title}>
viewMoreText={viewMoreText} <NoticeList
data={list} clearText={clearText}
onClear={() => this.onClear(title, tabKey)} viewMoreText={viewMoreText}
onClick={item => this.onItemClick(item, child.props)} data={list}
onViewMore={event => this.onViewMore(child.props, event)} onClear={(): void => this.onClear(title, tabKey)}
showClear={showClear} onClick={(item): void => this.onItemClick(item, child.props)}
showViewMore={showViewMore} onViewMore={(event): void => this.onViewMore(child.props, event)}
title={title} showClear={showClear}
{...child.props} showViewMore={showViewMore}
/> title={title}
</TabPane> {...child.props}
); />
}); </TabPane>
);
},
);
return ( return (
<Spin spinning={loading} delay={0}> <Spin spinning={loading} delay={0}>
<Tabs className={styles.tabs} onChange={this.onTabChange}> <Tabs className={styles.tabs} onChange={this.onTabChange}>
...@@ -121,7 +125,7 @@ export default class NoticeIcon extends Component<NoticeIconProps> { ...@@ -121,7 +125,7 @@ export default class NoticeIcon extends Component<NoticeIconProps> {
); );
} }
handleVisibleChange = (visible: boolean) => { handleVisibleChange = (visible: boolean): void => {
const { onPopupVisibleChange } = this.props; const { onPopupVisibleChange } = this.props;
this.setState({ visible }); this.setState({ visible });
if (onPopupVisibleChange) { if (onPopupVisibleChange) {
...@@ -129,7 +133,7 @@ export default class NoticeIcon extends Component<NoticeIconProps> { ...@@ -129,7 +133,7 @@ export default class NoticeIcon extends Component<NoticeIconProps> {
} }
}; };
render() { render(): React.ReactNode {
const { className, count, popupVisible, bell } = this.props; const { className, count, popupVisible, bell } = this.props;
const { visible } = this.state; const { visible } = this.state;
const noticeButtonClass = classNames(className, styles.noticeButton); const noticeButtonClass = classNames(className, styles.noticeButton);
......
import React from 'react'; import { Icon, Menu } from 'antd';
import { formatMessage, setLocale, getLocale } from 'umi-plugin-react/locale'; import { formatMessage, getLocale, setLocale } from 'umi-plugin-react/locale';
import { Menu, Icon } from 'antd';
import { ClickParam } from 'antd/es/menu'; import { ClickParam } from 'antd/es/menu';
import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import HeaderDropdown from '../HeaderDropdown'; import HeaderDropdown from '../HeaderDropdown';
import styles from './index.less'; import styles from './index.less';
...@@ -12,7 +12,7 @@ interface SelectLangProps { ...@@ -12,7 +12,7 @@ interface SelectLangProps {
const SelectLang: React.FC<SelectLangProps> = props => { const SelectLang: React.FC<SelectLangProps> = props => {
const { className } = props; const { className } = props;
const selectedLang = getLocale(); const selectedLang = getLocale();
const changeLang = ({ key }: ClickParam) => setLocale(key, false); const changeLang = ({ key }: ClickParam): void => setLocale(key, false);
const locales = ['zh-CN', 'zh-TW', 'en-US', 'pt-BR']; const locales = ['zh-CN', 'zh-TW', 'en-US', 'pt-BR'];
const languageLabels = { const languageLabels = {
'zh-CN': '简体中文', 'zh-CN': '简体中文',
......
// eslint-disable-next-line eslint-comments/disable-enable-pair
/* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable import/no-extraneous-dependencies */
import generate from '@ant-design/colors/lib/generate';
import client from 'webpack-theme-color-replacer/client'; import client from 'webpack-theme-color-replacer/client';
import generate from '@ant-design/colors/lib/generate';
export default { export default {
lastColor: '#1890ff',
primaryColor: '#1890ff', primaryColor: '#1890ff',
getAntdSerials(color) { getAntdSerials(color: string) {
// 淡化(即less的tint) // 淡化(即less的tint)
const lightens = new Array(9).fill().map((t, i) => { const lightens = new Array(9).fill(0).map((_, i) => client.varyColor.lighten(color, i / 10));
return client.varyColor.lighten(color, i / 10);
});
const colorPalettes = generate(color); const colorPalettes = generate(color);
return lightens.concat(colorPalettes); return lightens.concat(colorPalettes);
}, },
changeColor(newColor) { changeColor(newColor: string) {
const lastColor = this.lastColor || this.primaryColor; const lastColor = this.lastColor || this.primaryColor;
const options = { const options = {
cssUrl: '/css/theme-colors.css', // hash模式下用相对路径 // hash模式下用相对路径
oldColors: this.getAntdSerials(lastColor), // current colors array. The same as `matchColors` cssUrl: '/css/theme-colors.css',
newColors: this.getAntdSerials(newColor || this.primaryColor), // new colors array, one-to-one corresponde with `oldColors` // current colors array. The same as `matchColors`
oldColors: this.getAntdSerials(lastColor),
// new colors array, one-to-one corresponde with `oldColors`
newColors: this.getAntdSerials(newColor || this.primaryColor),
}; };
const promise = client.changer.changeColor(options, Promise); const promise = client.changer.changeColor(options, Promise);
this.lastColor = lastColor; this.lastColor = lastColor;
......
jest.mock('antd-pro-merge-less');
const RouterConfig = require('../../config/config').default.routes; const RouterConfig = require('../../config/config').default.routes;
const BASE_URL = `http://localhost:${process.env.PORT || 8000}`; const BASE_URL = `http://localhost:${process.env.PORT || 8000}`;
......
import { Button, message, notification } from 'antd';
import React from 'react'; import React from 'react';
import { notification, Button, message } from 'antd';
import { formatMessage } from 'umi-plugin-react/locale'; import { formatMessage } from 'umi-plugin-react/locale';
import defaultSettings from '../config/defaultSettings'; import defaultSettings from '../config/defaultSettings';
...@@ -19,7 +20,7 @@ if (pwa) { ...@@ -19,7 +20,7 @@ if (pwa) {
// https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration // https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration
const worker = e.detail && e.detail.waiting; const worker = e.detail && e.detail.waiting;
if (!worker) { if (!worker) {
return Promise.resolve(); return true;
} }
// Send skip-waiting event to waiting SW with MessageChannel // Send skip-waiting event to waiting SW with MessageChannel
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
...@@ -59,7 +60,12 @@ if (pwa) { ...@@ -59,7 +60,12 @@ if (pwa) {
}); });
} else if ('serviceWorker' in navigator) { } else if ('serviceWorker' in navigator) {
// eslint-disable-next-line compat/compat // eslint-disable-next-line compat/compat
navigator.serviceWorker.ready.then(registration => { navigator.serviceWorker.ready
registration.unregister(); .then(registration => {
}); registration.unregister();
return true;
})
.catch(() => {
console.log('serviceWorker unregister error');
});
} }
...@@ -4,21 +4,23 @@ ...@@ -4,21 +4,23 @@
* https://github.com/ant-design/ant-design-pro-layout * https://github.com/ant-design/ant-design-pro-layout
*/ */
import { ConnectState, ConnectProps } from '@/models/connect'; import { ConnectProps, ConnectState } from '@/models/connect';
import RightContent from '@/components/GlobalHeader/RightContent';
import { connect } from 'dva';
import React, { useState } from 'react';
import logo from '../assets/logo.svg';
import Authorized from '@/utils/Authorized';
import { formatMessage } from 'umi-plugin-react/locale';
import { isAntDesignPro } from '@/utils/utils';
import { import {
MenuDataItem,
BasicLayout as ProLayoutComponents, BasicLayout as ProLayoutComponents,
BasicLayoutProps as ProLayoutComponentsProps, BasicLayoutProps as ProLayoutComponentsProps,
MenuDataItem,
Settings, Settings,
} from '@ant-design/pro-layout'; } from '@ant-design/pro-layout';
import React, { useState } from 'react';
import Authorized from '@/utils/Authorized';
import Link from 'umi/link'; import Link from 'umi/link';
import RightContent from '@/components/GlobalHeader/RightContent';
import { connect } from 'dva';
import { formatMessage } from 'umi-plugin-react/locale';
import { isAntDesignPro } from '@/utils/utils';
import logo from '../assets/logo.svg';
export interface BasicLayoutProps extends ProLayoutComponentsProps, ConnectProps { export interface BasicLayoutProps extends ProLayoutComponentsProps, ConnectProps {
breadcrumbNameMap: { breadcrumbNameMap: {
[path: string]: MenuDataItem; [path: string]: MenuDataItem;
...@@ -30,16 +32,18 @@ export type BasicLayoutContext = { [K in 'location']: BasicLayoutProps[K] } & { ...@@ -30,16 +32,18 @@ export type BasicLayoutContext = { [K in 'location']: BasicLayoutProps[K] } & {
[path: string]: MenuDataItem; [path: string]: MenuDataItem;
}; };
}; };
/** /**
* use Authorized check all menu item * use Authorized check all menu item
*/ */
const menuDataRender = (menuList: MenuDataItem[]): MenuDataItem[] =>
const menuDataRender = (menuList: MenuDataItem[]): MenuDataItem[] => { menuList.map(item => {
return menuList.map(item => { const localItem = {
const localItem = { ...item, children: item.children ? menuDataRender(item.children) : [] }; ...item,
children: item.children ? menuDataRender(item.children) : [],
};
return Authorized.check(item.authority, localItem, null) as MenuDataItem; return Authorized.check(item.authority, localItem, null) as MenuDataItem;
}); });
};
const footerRender: BasicLayoutProps['footerRender'] = (_, defaultDom) => { const footerRender: BasicLayoutProps['footerRender'] = (_, defaultDom) => {
if (!isAntDesignPro()) { if (!isAntDesignPro()) {
...@@ -54,7 +58,7 @@ const footerRender: BasicLayoutProps['footerRender'] = (_, defaultDom) => { ...@@ -54,7 +58,7 @@ const footerRender: BasicLayoutProps['footerRender'] = (_, defaultDom) => {
textAlign: 'center', textAlign: 'center',
}} }}
> >
<a href="https://www.netlify.com" target="_blank"> <a href="https://www.netlify.com" target="_blank" rel="noopener noreferrer">
<img <img
src="https://www.netlify.com/img/global/badges/netlify-color-bg.svg" src="https://www.netlify.com/img/global/badges/netlify-color-bg.svg"
width="82px" width="82px"
...@@ -86,7 +90,7 @@ const BasicLayout: React.FC<BasicLayoutProps> = props => { ...@@ -86,7 +90,7 @@ const BasicLayout: React.FC<BasicLayoutProps> = props => {
/** /**
* init variables * init variables
*/ */
const handleMenuCollapse = (payload: boolean) => const handleMenuCollapse = (payload: boolean): void =>
dispatch && dispatch &&
dispatch({ dispatch({
type: 'global/changeLayoutCollapsed', type: 'global/changeLayoutCollapsed',
...@@ -97,21 +101,19 @@ const BasicLayout: React.FC<BasicLayoutProps> = props => { ...@@ -97,21 +101,19 @@ const BasicLayout: React.FC<BasicLayoutProps> = props => {
<ProLayoutComponents <ProLayoutComponents
logo={logo} logo={logo}
onCollapse={handleMenuCollapse} onCollapse={handleMenuCollapse}
menuItemRender={(menuItemProps, defaultDom) => { menuItemRender={(menuItemProps, defaultDom) => (
return <Link to={menuItemProps.path}>{defaultDom}</Link>; <Link to={menuItemProps.path}>{defaultDom}</Link>
}} )}
breadcrumbRender={(routers = []) => { breadcrumbRender={(routers = []) => [
return [ {
{ path: '/',
path: '/', breadcrumbName: formatMessage({
breadcrumbName: formatMessage({ id: 'menu.home',
id: 'menu.home', defaultMessage: 'Home',
defaultMessage: 'Home', }),
}), },
}, ...routers,
...routers, ]}
];
}}
footerRender={footerRender} footerRender={footerRender}
menuDataRender={menuDataRender} menuDataRender={menuDataRender}
formatMessage={formatMessage} formatMessage={formatMessage}
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
} }
.content { .content {
padding: 32px 0 24px 0; padding: 32px 0 24px;
} }
} }
......
import SelectLang from '@/components/SelectLang';
import { ConnectProps, ConnectState } from '@/models/connect'; import { ConnectProps, ConnectState } from '@/models/connect';
import { connect } from 'dva'; import { DefaultFooter, MenuDataItem, getMenuData, getPageTitle } from '@ant-design/pro-layout';
import React from 'react';
import DocumentTitle from 'react-document-title'; import DocumentTitle from 'react-document-title';
import { formatMessage } from 'umi-plugin-react/locale';
import Link from 'umi/link'; import Link from 'umi/link';
import React from 'react';
import SelectLang from '@/components/SelectLang';
import { connect } from 'dva';
import { formatMessage } from 'umi-plugin-react/locale';
import logo from '../assets/logo.svg'; import logo from '../assets/logo.svg';
import styles from './UserLayout.less'; import styles from './UserLayout.less';
import { MenuDataItem, getPageTitle, getMenuData, DefaultFooter } from '@ant-design/pro-layout';
export interface UserLayoutProps extends ConnectProps { export interface UserLayoutProps extends ConnectProps {
breadcrumbNameMap: { [path: string]: MenuDataItem }; breadcrumbNameMap: { [path: string]: MenuDataItem };
......
import component from './en-US/component';
import globalHeader from './en-US/globalHeader'; import globalHeader from './en-US/globalHeader';
import menu from './en-US/menu'; import menu from './en-US/menu';
import pwa from './en-US/pwa';
import settingDrawer from './en-US/settingDrawer'; import settingDrawer from './en-US/settingDrawer';
import settings from './en-US/settings'; import settings from './en-US/settings';
import pwa from './en-US/pwa';
import component from './en-US/component';
export default { export default {
'navBar.lang': 'Languages', 'navBar.lang': 'Languages',
......
import component from './pt-BR/component';
import globalHeader from './pt-BR/globalHeader'; import globalHeader from './pt-BR/globalHeader';
import menu from './pt-BR/menu'; import menu from './pt-BR/menu';
import pwa from './pt-BR/pwa';
import settingDrawer from './pt-BR/settingDrawer'; import settingDrawer from './pt-BR/settingDrawer';
import settings from './pt-BR/settings'; import settings from './pt-BR/settings';
import pwa from './pt-BR/pwa';
import component from './pt-BR/component';
export default { export default {
'navBar.lang': 'Idiomas', 'navBar.lang': 'Idiomas',
......
import component from './zh-CN/component';
import globalHeader from './zh-CN/globalHeader'; import globalHeader from './zh-CN/globalHeader';
import menu from './zh-CN/menu'; import menu from './zh-CN/menu';
import pwa from './zh-CN/pwa';
import settingDrawer from './zh-CN/settingDrawer'; import settingDrawer from './zh-CN/settingDrawer';
import settings from './zh-CN/settings'; import settings from './zh-CN/settings';
import pwa from './zh-CN/pwa';
import component from './zh-CN/component';
export default { export default {
'navBar.lang': '语言', 'navBar.lang': '语言',
......
import component from './zh-TW/component';
import globalHeader from './zh-TW/globalHeader'; import globalHeader from './zh-TW/globalHeader';
import menu from './zh-TW/menu'; import menu from './zh-TW/menu';
import pwa from './zh-TW/pwa';
import settingDrawer from './zh-TW/settingDrawer'; import settingDrawer from './zh-TW/settingDrawer';
import settings from './zh-TW/settings'; import settings from './zh-TW/settings';
import pwa from './zh-TW/pwa';
import component from './zh-TW/component';
export default { export default {
'navBar.lang': '語言', 'navBar.lang': '語言',
......
import { EffectsCommandMap } from 'dva';
import { AnyAction } from 'redux'; import { AnyAction } from 'redux';
import { EffectsCommandMap } from 'dva';
import { MenuDataItem } from '@ant-design/pro-layout';
import { RouterTypes } from 'umi'; import { RouterTypes } from 'umi';
import { GlobalModelState } from './global'; import { GlobalModelState } from './global';
import { UserModelState } from './user';
import { DefaultSettings as SettingModelState } from '../../config/defaultSettings'; import { DefaultSettings as SettingModelState } from '../../config/defaultSettings';
import { MenuDataItem } from '@ant-design/pro-layout'; import { UserModelState } from './user';
export { GlobalModelState, SettingModelState, UserModelState };
export type Effect = (
action: AnyAction,
effects: EffectsCommandMap & { select: <T>(func: (state: ConnectState) => T) => T },
) => void;
/** export { GlobalModelState, SettingModelState, UserModelState };
* @type P: Type of payload
* @type C: Type of callback
*/
export type Dispatch = <P = any, C = (payload: P) => void>(action: {
type: string;
payload?: P;
callback?: C;
[key: string]: any;
}) => any;
export interface Loading { export interface Loading {
global: boolean; global: boolean;
...@@ -41,6 +26,22 @@ export interface ConnectState { ...@@ -41,6 +26,22 @@ export interface ConnectState {
user: UserModelState; user: UserModelState;
} }
export type Effect = (
action: AnyAction,
effects: EffectsCommandMap & { select: <T>(func: (state: ConnectState) => T) => T },
) => void;
/**
* @type P: Type of payload
* @type C: Type of callback
*/
export type Dispatch = <P = any, C = (payload: P) => void>(action: {
type: string;
payload?: P;
callback?: C;
[key: string]: any;
}) => any;
export interface Route extends MenuDataItem { export interface Route extends MenuDataItem {
routes?: Route[]; routes?: Route[];
} }
...@@ -52,5 +53,3 @@ export interface ConnectProps<T extends { [key: string]: any } = {}> ...@@ -52,5 +53,3 @@ export interface ConnectProps<T extends { [key: string]: any } = {}>
extends Partial<RouterTypes<Route, T>> { extends Partial<RouterTypes<Route, T>> {
dispatch?: Dispatch; dispatch?: Dispatch;
} }
export default ConnectState;
import { queryNotices } from '@/services/user'; import { Effect } from './connect.d';
import { Subscription } from 'dva';
import { Reducer } from 'redux';
import { Effect } from './connect';
import { NoticeIconData } from '@/components/NoticeIcon'; import { NoticeIconData } from '@/components/NoticeIcon';
import { Reducer } from 'redux';
import { Subscription } from 'dva';
import { queryNotices } from '@/services/user';
export interface NoticeItem extends NoticeIconData { export interface NoticeItem extends NoticeIconData {
id: string; id: string;
type: string; type: string;
[key: string]: any;
} }
export interface GlobalModelState { export interface GlobalModelState {
...@@ -84,10 +83,12 @@ const GlobalModel: GlobalModelType = { ...@@ -84,10 +83,12 @@ const GlobalModel: GlobalModelType = {
return notice; return notice;
}), }),
); );
yield put({ yield put({
type: 'saveNotices', type: 'saveNotices',
payload: notices, payload: notices,
}); });
yield put({ yield put({
type: 'user/changeNotifyCount', type: 'user/changeNotifyCount',
payload: { payload: {
...@@ -99,32 +100,32 @@ const GlobalModel: GlobalModelType = { ...@@ -99,32 +100,32 @@ const GlobalModel: GlobalModelType = {
}, },
reducers: { reducers: {
changeLayoutCollapsed(state = { notices: [], collapsed: true }, { payload }) { changeLayoutCollapsed(state = { notices: [], collapsed: true }, { payload }): GlobalModelState {
return { return {
...state, ...state,
collapsed: payload, collapsed: payload,
}; };
}, },
saveNotices(state, { payload }) { saveNotices(state, { payload }): GlobalModelState {
return { return {
collapsed: false, collapsed: false,
...state, ...state,
notices: payload, notices: payload,
}; };
}, },
saveClearedNotices(state = { notices: [], collapsed: true }, { payload }) { saveClearedNotices(state = { notices: [], collapsed: true }, { payload }): GlobalModelState {
return { return {
collapsed: false, collapsed: false,
...state, ...state,
notices: state.notices.filter(item => item.type !== payload), notices: state.notices.filter((item): boolean => item.type !== payload),
}; };
}, },
}, },
subscriptions: { subscriptions: {
setup({ history }) { setup({ history }): void {
// Subscribe history(url) change, trigger `load` action if pathname is `/` // Subscribe history(url) change, trigger `load` action if pathname is `/`
return history.listen(({ pathname, search }) => { history.listen(({ pathname, search }): void => {
if (typeof (window as any).ga !== 'undefined') { if (typeof (window as any).ga !== 'undefined') {
(window as any).ga('send', 'pageview', pathname + search); (window as any).ga('send', 'pageview', pathname + search);
} }
......
import { routerRedux } from 'dva/router'; import { AnyAction, Reducer } from 'redux';
import { Reducer, AnyAction } from 'redux'; import { parse, stringify } from 'qs';
import { EffectsCommandMap } from 'dva'; import { EffectsCommandMap } from 'dva';
import { stringify, parse } from 'qs'; import { routerRedux } from 'dva/router';
export function getPageQuery() { export function getPageQuery(): string {
return parse(window.location.href.split('?')[1]); return parse(window.location.href.split('?')[1]);
} }
......
import { message } from 'antd';
import { Reducer } from 'redux'; import { Reducer } from 'redux';
// eslint-disable-next-line eslint-comments/disable-enable-pair
/* eslint-disable promise/catch-or-return */
import { message } from 'antd';
import defaultSettings, { DefaultSettings } from '../../config/defaultSettings'; import defaultSettings, { DefaultSettings } from '../../config/defaultSettings';
import themeColorClient from '../components/SettingDrawer/themeColorClient'; import themeColorClient from '../components/SettingDrawer/themeColorClient';
...@@ -35,8 +37,8 @@ const updateTheme: (primaryColor?: string) => void = primaryColor => { ...@@ -35,8 +37,8 @@ const updateTheme: (primaryColor?: string) => void = primaryColor => {
const hideMessage = message.loading('正在编译主题!', 0); const hideMessage = message.loading('正在编译主题!', 0);
function buildIt() { function buildIt() {
if (!(window as any).less) { if (!(window as any).less) {
// tslint:disable-next-line no-console console.log('no less');
return console.log('no less'); return;
} }
setTimeout(() => { setTimeout(() => {
(window as any).less (window as any).less
...@@ -45,6 +47,7 @@ const updateTheme: (primaryColor?: string) => void = primaryColor => { ...@@ -45,6 +47,7 @@ const updateTheme: (primaryColor?: string) => void = primaryColor => {
}) })
.then(() => { .then(() => {
hideMessage(); hideMessage();
return true;
}) })
.catch(() => { .catch(() => {
message.error('Failed to update theme'); message.error('Failed to update theme');
......
import { query as queryUsers, queryCurrent } from '@/services/user'; import { queryCurrent, query as queryUsers } from '@/services/user';
import { Effect } from 'dva'; import { Effect } from 'dva';
import { Reducer } from 'redux'; import { Reducer } from 'redux';
...@@ -8,7 +9,6 @@ export interface CurrentUser { ...@@ -8,7 +9,6 @@ export interface CurrentUser {
title?: string; title?: string;
group?: string; group?: string;
signature?: string; signature?: string;
geographic?: any;
tags?: { tags?: {
key: string; key: string;
label: string; label: string;
......
import { ConnectProps, ConnectState, Route, UserModelState } from '@/models/connect';
import Authorized from '@/utils/Authorized'; import Authorized from '@/utils/Authorized';
import { ConnectProps, ConnectState, UserModelState, Route } from '@/models/connect';
import { connect } from 'dva';
import pathToRegexp from 'path-to-regexp';
import React from 'react'; import React from 'react';
import Redirect from 'umi/redirect'; import Redirect from 'umi/redirect';
import { connect } from 'dva';
import pathToRegexp from 'path-to-regexp';
interface AuthComponentProps extends ConnectProps { interface AuthComponentProps extends ConnectProps {
user: UserModelState; user: UserModelState;
} }
const getRouteAuthority = (path: string, routeData: Route[]) => { const getRouteAuthority = (path: string, routeData: Route[]) => {
let authorities: string[] | string | undefined = undefined; let authorities: string[] | string | undefined;
routeData.forEach(route => { routeData.forEach(route => {
// match prefix // match prefix
if (pathToRegexp(`${route.path}(.*)`).test(path)) { if (pathToRegexp(`${route.path}(.*)`).test(path)) {
...@@ -29,7 +29,9 @@ const AuthComponent: React.FC<AuthComponentProps> = ({ ...@@ -29,7 +29,9 @@ const AuthComponent: React.FC<AuthComponentProps> = ({
route = { route = {
routes: [], routes: [],
}, },
location, location = {
pathname: '',
},
user, user,
}) => { }) => {
const { currentUser } = user; const { currentUser } = user;
...@@ -37,7 +39,7 @@ const AuthComponent: React.FC<AuthComponentProps> = ({ ...@@ -37,7 +39,7 @@ const AuthComponent: React.FC<AuthComponentProps> = ({
const isLogin = currentUser && currentUser.name; const isLogin = currentUser && currentUser.name;
return ( return (
<Authorized <Authorized
authority={getRouteAuthority(location!.pathname, routes)!} authority={getRouteAuthority(location.pathname, routes) || ''}
noMatch={isLogin ? <Redirect to="/exception/403" /> : <Redirect to="/user/login" />} noMatch={isLogin ? <Redirect to="/exception/403" /> : <Redirect to="/user/login" />}
> >
{children} {children}
......
import React from 'react'; import React from 'react';
export default () => ( export default (): React.ReactNode => (
<p style={{ textAlign: 'center' }}> <p style={{ textAlign: 'center' }}>
Want to add more pages? Please refer to{' '} Want to add more pages? Please refer to{' '}
<a href="https://pro.ant.design/docs/block-cn" target="_blank" rel="noopener noreferrer"> <a href="https://pro.ant.design/docs/block-cn" target="_blank" rel="noopener noreferrer">
......
/* globals workbox */ /* eslint-disable eslint-comments/disable-enable-pair */
/* eslint-disable no-restricted-globals */ /* eslint-disable no-restricted-globals */
/* eslint-disable no-underscore-dangle */
/* globals workbox */
workbox.core.setCacheNameDetails({ workbox.core.setCacheNameDetails({
prefix: 'antd-pro', prefix: 'antd-pro',
suffix: 'v1', suffix: 'v1',
...@@ -11,7 +13,6 @@ workbox.clientsClaim(); ...@@ -11,7 +13,6 @@ workbox.clientsClaim();
* Use precaching list generated by workbox in build process. * Use precaching list generated by workbox in build process.
* https://developers.google.com/web/tools/workbox/reference-docs/latest/workbox.precaching * https://developers.google.com/web/tools/workbox/reference-docs/latest/workbox.precaching
*/ */
/* eslint-disable no-underscore-dangle */
workbox.precaching.precacheAndRoute(self.__precacheManifest || []); workbox.precaching.precacheAndRoute(self.__precacheManifest || []);
/** /**
......
declare module 'slash2'; declare module 'slash2';
declare module 'antd-pro-merge-less';
declare module 'antd-theme-webpack-plugin'; declare module 'antd-theme-webpack-plugin';
declare module '*.css'; declare module '*.css';
...@@ -19,8 +18,11 @@ declare module 'react-copy-to-clipboard'; ...@@ -19,8 +18,11 @@ declare module 'react-copy-to-clipboard';
declare module 'react-fittext'; declare module 'react-fittext';
declare module '@antv/data-set'; declare module '@antv/data-set';
declare module 'nzh/cn'; declare module 'nzh/cn';
declare module 'webpack-theme-color-replacer';
declare module 'webpack-theme-color-replacer/client';
declare let ga: Function; declare let ga: Function;
// preview.pro.ant.design only do not use in your production ; // preview.pro.ant.design only do not use in your production ;
// preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。 // preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。
declare let ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: 'site' | undefined; declare let ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: 'site' | undefined;
import { default as RenderAuthorize } from '@/components/Authorized'; import RenderAuthorize from '@/components/Authorized';
import { getAuthority } from './authority'; import { getAuthority } from './authority';
/* eslint-disable eslint-comments/disable-enable-pair */
let Authorized = RenderAuthorize(getAuthority()); // eslint-disable-line /* eslint-disable import/no-mutable-exports */
let Authorized = RenderAuthorize(getAuthority());
// Reload the rights component // Reload the rights component
const reloadAuthorized = () => { const reloadAuthorized = (): void => {
Authorized = RenderAuthorize(getAuthority()); Authorized = RenderAuthorize(getAuthority());
}; };
......
import 'jest';
import { getAuthority } from './authority'; import { getAuthority } from './authority';
describe('getAuthority should be strong', () => { describe('getAuthority should be strong', () => {
it('empty', () => {
expect(getAuthority(null)).toEqual(null); // default value
});
it('string', () => { it('string', () => {
expect(getAuthority('admin')).toEqual(['admin']); expect(getAuthority('admin')).toEqual(['admin']);
}); });
......
// use localStorage to store the authority info, which might be sent from server in actual project. // use localStorage to store the authority info, which might be sent from server in actual project.
export function getAuthority(str?: string): any { export function getAuthority(str?: string): string | string[] {
// return localStorage.getItem('antd-pro-authority') || ['admin', 'user']; // return localStorage.getItem('antd-pro-authority') || ['admin', 'user'];
const authorityString = const authorityString =
typeof str === 'undefined' ? localStorage.getItem('antd-pro-authority') : str; typeof str === 'undefined' ? localStorage.getItem('antd-pro-authority') : str;
// authorityString could be admin, "admin", ["admin"] // authorityString could be admin, "admin", ["admin"]
let authority; let authority;
try { try {
authority = JSON.parse(authorityString!); if (authorityString) {
authority = JSON.parse(authorityString);
}
} catch (e) { } catch (e) {
authority = authorityString; authority = authorityString;
} }
if (typeof authority === 'string') { if (typeof authority === 'string') {
return [authority]; return [authority];
} }
// preview.pro.ant.design only do not use in your production ; preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。 // preview.pro.ant.design only do not use in your production.
// preview.pro.ant.design 专用环境变量,请不要在你的项目中使用它。
if (!authority && ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site') { if (!authority && ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site') {
return ['admin']; return ['admin'];
} }
......
...@@ -5,12 +5,6 @@ ...@@ -5,12 +5,6 @@
import { extend } from 'umi-request'; import { extend } from 'umi-request';
import { notification } from 'antd'; import { notification } from 'antd';
interface ResponseError<D = any> extends Error {
name: string;
data: D;
response: Response;
}
const codeMessage = { const codeMessage = {
200: '服务器成功返回请求的数据。', 200: '服务器成功返回请求的数据。',
201: '新建或修改数据成功。', 201: '新建或修改数据成功。',
...@@ -32,15 +26,17 @@ const codeMessage = { ...@@ -32,15 +26,17 @@ const codeMessage = {
/** /**
* 异常处理程序 * 异常处理程序
*/ */
const errorHandler = (error: ResponseError) => { const errorHandler = (error: { response: Response }): void => {
const { response = {} as Response } = error; const { response } = error;
const errortext = codeMessage[response.status] || response.statusText; if (response && response.status) {
const { status, url } = response; const errorText = codeMessage[response.status] || response.statusText;
const { status, url } = response;
notification.error({ notification.error({
message: `请求错误 ${status}: ${url}`, message: `请求错误 ${status}: ${url}`,
description: errortext, description: errorText,
}); });
}
}; };
/** /**
......
import 'jest';
import { isUrl } from './utils'; import { isUrl } from './utils';
describe('isUrl tests', () => { describe('isUrl tests', (): void => {
it('should return false for invalid and corner case inputs', () => { it('should return false for invalid and corner case inputs', (): void => {
expect(isUrl([] as any)).toBeFalsy(); expect(isUrl([] as any)).toBeFalsy();
expect(isUrl({} as any)).toBeFalsy(); expect(isUrl({} as any)).toBeFalsy();
expect(isUrl(false as any)).toBeFalsy(); expect(isUrl(false as any)).toBeFalsy();
...@@ -13,7 +12,7 @@ describe('isUrl tests', () => { ...@@ -13,7 +12,7 @@ describe('isUrl tests', () => {
expect(isUrl('')).toBeFalsy(); expect(isUrl('')).toBeFalsy();
}); });
it('should return false for invalid URLs', () => { it('should return false for invalid URLs', (): void => {
expect(isUrl('foo')).toBeFalsy(); expect(isUrl('foo')).toBeFalsy();
expect(isUrl('bar')).toBeFalsy(); expect(isUrl('bar')).toBeFalsy();
expect(isUrl('bar/test')).toBeFalsy(); expect(isUrl('bar/test')).toBeFalsy();
...@@ -21,7 +20,7 @@ describe('isUrl tests', () => { ...@@ -21,7 +20,7 @@ describe('isUrl tests', () => {
expect(isUrl('ttp://example.com/')).toBeFalsy(); expect(isUrl('ttp://example.com/')).toBeFalsy();
}); });
it('should return true for valid URLs', () => { it('should return true for valid URLs', (): void => {
expect(isUrl('http://example.com/')).toBeTruthy(); expect(isUrl('http://example.com/')).toBeTruthy();
expect(isUrl('https://example.com/')).toBeTruthy(); expect(isUrl('https://example.com/')).toBeTruthy();
expect(isUrl('http://example.com/test/123')).toBeTruthy(); expect(isUrl('http://example.com/test/123')).toBeTruthy();
......
/* 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]*))?)$/;
const isUrl = (path: string): boolean => { const isUrl = (path: string): boolean => reg.test(path);
return reg.test(path);
};
const isAntDesignPro = (): boolean => { const isAntDesignPro = (): boolean => {
if (ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site') { if (ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site') {
......
/* eslint-disable no-console */ /* eslint-disable eslint-comments/disable-enable-pair */
/* eslint-disable @typescript-eslint/no-var-requires */
/* eslint-disable eslint-comments/no-unlimited-disable */
const { spawn } = require('child_process'); const { spawn } = require('child_process');
const { kill } = require('cross-port-killer'); const { kill } = require('cross-port-killer');
......
defaultSeverity: error
globals:
- ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true
extends:
- tslint-react
- tslint-eslint-rules
- tslint-config-prettier
jsRules:
rules:
class-name: true
eofline: true
forin: true
jsdoc-format: false
label-position: true
member-ordering:
- true
- order: statics-first
new-parens: true
no-arg: true
no-bitwise: true
no-conditional-assignment: true
no-consecutive-blank-lines: true
no-construct: true
no-debugger: true
no-duplicate-variable: true
no-eval: true
no-internal-module: true
no-multi-spaces: true
no-namespace: true
no-reference: true
no-shadowed-variable: true
no-string-literal: true
no-trailing-whitespace: true
no-unused-expression: true
no-var-keyword: true
one-variable-per-declaration:
- true
- ignore-for-loop
prefer-const:
- true
- destructuring: all
radix: true
space-in-parens: true
switch-default: true
trailing-comma:
- true
- singleline: never
multiline: always
esSpecCompliant: true
triple-equals:
- true
- allow-null-check
typedef-whitespace:
- true
- call-signature: nospace
index-signature: nospace
parameter: nospace
property-declaration: nospace
variable-declaration: nospace
- call-signature: onespace
index-signature: onespace
parameter: onespace
property-declaration: onespace
variable-declaration: onespace
use-isnan: true
variable-name:
- true
- allow-leading-underscore
- ban-keywords
- check-format
- allow-pascal-case
jsx-no-lambda: false
jsx-no-string-ref: false
jsx-boolean-value:
- true
- never
jsx-no-multiline-js: false
whitespace:
- true
- check-branch
- check-decl
- check-operator
- check-module
- check-separator
- check-rest-spread
- check-type
- check-type-operator
- check-preblock
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment