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