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 = {
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,
},
};
......@@ -35,3 +35,4 @@ functions/*
# screenshot
screenshot
.firebase
.eslintcache
......@@ -14,3 +14,6 @@ Dockerfile*
.gitignore
.prettierignore
LICENSE
.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/
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 ;
......
// 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);
......
......@@ -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": {
......
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';
import AuthorizedRoute from './AuthorizedRoute';
import Secured from './Secured';
interface IAuthorizedProps {
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}</>;
};
......
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,
......
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);
/**
......
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);
};
......
/* 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();
......
import { Icon, Popover, Typography } from 'antd';
import { FormattedMessage } from 'umi-plugin-react/locale';
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 styles from './index.less';
const firstUpperCase = (pathString: string) => {
return pathString
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,
......
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 (
......
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 { 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 moment from 'moment';
import groupBy from 'lodash/groupBy';
import NoticeIcon from '../NoticeIcon';
import moment from 'moment';
import styles from './index.less';
import { connect } from 'dva';
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();
......
import { ConnectProps, ConnectState } from '@/models/connect';
import React, { Component } from 'react';
import { Icon, Tooltip } from 'antd';
import { formatMessage } from 'umi-plugin-react/locale';
import Avatar from './AvatarDropdown';
import HeaderSearch from '../HeaderSearch';
import React from 'react';
import SelectLang from '../SelectLang';
import styles from './index.less';
import Avatar from './AvatarDropdown';
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,9 +15,8 @@ export interface GlobalHeaderRightProps extends ConnectProps {
layout: 'sidemenu' | 'topmenu';
}
class GlobalHeaderRight extends Component<GlobalHeaderRightProps> {
render() {
const { theme, layout } = this.props;
const GlobalHeaderRight: React.SFC<GlobalHeaderRightProps> = props => {
const { theme, layout } = props;
let className = styles.right;
if (theme === 'dark' && layout === 'topmenu') {
......@@ -42,10 +42,10 @@ class GlobalHeaderRight extends Component<GlobalHeaderRightProps> {
}),
]}
onSearch={value => {
console.log('input', value); // tslint:disable-line no-console
console.log('input', value);
}}
onPressEnter={value => {
console.log('enter', value); // tslint:disable-line no-console
console.log('enter', value);
}}
/>
<Tooltip
......@@ -66,8 +66,7 @@ class GlobalHeaderRight extends Component<GlobalHeaderRightProps> {
<SelectLang className={styles.action} />
</div>
);
}
}
};
export default connect(({ settings }: ConnectState) => ({
theme: settings.navTheme,
......
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';
......
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,13 +70,14 @@ 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) => {
onChange: AutoCompleteProps['onChange'] = value => {
if (typeof value === 'string') {
const { onSearch, onChange } = this.props;
this.setState({ value });
if (onSearch) {
......@@ -83,6 +86,7 @@ export default class HeaderSearch extends Component<HeaderSearchProps, HeaderSea
if (onChange) {
onChange(value);
}
}
};
enterSearchMode = () => {
......@@ -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 {
......
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;
......
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,40 +55,42 @@ 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>) => {
const panes = React.Children.map(
children,
(child: React.ReactElement<NoticeIconTabProps>): React.ReactNode => {
if (!child) {
return null;
}
......@@ -101,9 +104,9 @@ export default class NoticeIcon extends Component<NoticeIconProps> {
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)}
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}
......@@ -111,7 +114,8 @@ export default class NoticeIcon extends Component<NoticeIconProps> {
/>
</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);
......
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': '简体中文',
......
// 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;
......
jest.mock('antd-pro-merge-less');
const RouterConfig = require('../../config/config').default.routes;
const BASE_URL = `http://localhost:${process.env.PORT || 8000}`;
......
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 => {
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,11 +101,10 @@ const BasicLayout: React.FC<BasicLayoutProps> = props => {
<ProLayoutComponents
logo={logo}
onCollapse={handleMenuCollapse}
menuItemRender={(menuItemProps, defaultDom) => {
return <Link to={menuItemProps.path}>{defaultDom}</Link>;
}}
breadcrumbRender={(routers = []) => {
return [
menuItemRender={(menuItemProps, defaultDom) => (
<Link to={menuItemProps.path}>{defaultDom}</Link>
)}
breadcrumbRender={(routers = []) => [
{
path: '/',
breadcrumbName: formatMessage({
......@@ -110,8 +113,7 @@ const BasicLayout: React.FC<BasicLayoutProps> = props => {
}),
},
...routers,
];
}}
]}
footerRender={footerRender}
menuDataRender={menuDataRender}
formatMessage={formatMessage}
......
......@@ -32,7 +32,7 @@
}
.content {
padding: 32px 0 24px 0;
padding: 32px 0 24px;
}
}
......
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 };
......
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',
......
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',
......
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': '语言',
......
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': '語言',
......
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';
export { GlobalModelState, SettingModelState, UserModelState };
export type Effect = (
action: AnyAction,
effects: EffectsCommandMap & { select: <T>(func: (state: ConnectState) => T) => T },
) => void;
import { UserModelState } from './user';
/**
* @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 { GlobalModelState, SettingModelState, UserModelState };
export interface Loading {
global: boolean;
......@@ -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;
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);
}
......
import { routerRedux } from 'dva/router';
import { Reducer, AnyAction } from 'redux';
import { AnyAction, Reducer } from 'redux';
import { parse, stringify } from 'qs';
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]);
}
......
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');
......
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;
......
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}
......
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">
......
/* 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 || []);
/**
......
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;
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());
};
......
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']);
});
......
// 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 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,
description: errorText,
});
}
};
/**
......
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();
......
/* 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') {
......
/* 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');
......
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