Merge branch 'master' of github.com:didi/nightingale
This commit is contained in:
commit
59f2bb003b
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"index-520b59d8379e5c351e38.js","sources":["webpack:///index-520b59d8379e5c351e38.js"],"mappings":"AAAA;;;;;;;AAuhZA","sourceRoot":""}
|
File diff suppressed because one or more lines are too long
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"index-5c8cbf958683e20086f5.js","sources":["webpack:///index-5c8cbf958683e20086f5.js"],"mappings":"AAAA;;;;;;;AAmsYA","sourceRoot":""}
|
|
@ -1 +1 @@
|
|||
<!doctype html><html><head><meta charset="UTF-8"><title>Nightingale</title><link rel="shortcut icon" href="/favicon.ico"><link href="/index-5c8cbf958683e20086f5.css" rel="stylesheet"></head><body><div id="react-content"></div><script src="/lib-033bee8514de110e36ef.dll.js"></script><script src="/index-5c8cbf958683e20086f5.js"></script></body></html>
|
||||
<!doctype html><html><head><meta charset="UTF-8"><title>Nightingale</title><link rel="shortcut icon" href="/favicon.ico"><link href="/index-520b59d8379e5c351e38.css" rel="stylesheet"></head><body><div id="react-content"></div><script src="/lib-033bee8514de110e36ef.dll.js"></script><script src="/index-520b59d8379e5c351e38.js"></script></body></html>
|
|
@ -32,11 +32,13 @@ func consume(event *model.Event) {
|
|||
return
|
||||
}
|
||||
|
||||
// 配置了升级策略,但不代表每个事件都要升级,比如判断时间是否到了升级条件
|
||||
if event.NeedUpgrade == 1 {
|
||||
event.RealUpgrade = needUpgrade(event)
|
||||
}
|
||||
|
||||
if event.RealUpgrade {
|
||||
// 确实需要升级的话,事件级别要改成升级之后的级别
|
||||
if err := updatePriority(event); err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -57,6 +59,7 @@ func consume(event *model.Event) {
|
|||
SetEventStatus(event, model.STATUS_CALLBACK)
|
||||
}
|
||||
|
||||
// 如果需要升级,需要在这个方法里把升级策略里配置的升级人员也解析出来
|
||||
if err := fillRecvs(event); err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -210,7 +213,7 @@ func isInConverge(event *model.Event) bool {
|
|||
}
|
||||
|
||||
if cnt >= convergeMaxCounts {
|
||||
logger.Infof("converge max counts: %c reached, current: %v, event hashid: %v", convergeMaxCounts, cnt, event.HashId)
|
||||
logger.Infof("converge max counts: %d reached, current: %v, event hashid: %v", convergeMaxCounts, cnt, event.HashId)
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -220,7 +223,7 @@ func isInConverge(event *model.Event) bool {
|
|||
// 三种情况,不需要升级报警
|
||||
// 1,认领的报警不需要升级
|
||||
// 2,忽略的报警不需要升级
|
||||
// 3,屏蔽的报警不需要升级
|
||||
// 3,屏蔽的报警不需要升级,屏蔽判断在前面已经有了处理,这个方法不用关注
|
||||
func needUpgrade(event *model.Event) bool {
|
||||
alertUpgradeKey := PrefixAlertUpgrade + fmt.Sprint(event.HashId)
|
||||
eventAlertKey := PrefixAlertTime + fmt.Sprint(event.HashId)
|
||||
|
|
|
@ -79,7 +79,7 @@ func popEvent(queues []interface{}) (*model.Event, bool) {
|
|||
// 可能endpoint挪了节点
|
||||
endpoint, err := model.EndpointGet("ident", event.Endpoint)
|
||||
if err != nil {
|
||||
logger.Errorf("get host_id failed, event: %+v, err: %v", event, err)
|
||||
logger.Errorf("model.EndpointGet fail, event: %+v, err: %v", event, err)
|
||||
return nil, true
|
||||
}
|
||||
|
||||
|
|
|
@ -2313,6 +2313,43 @@
|
|||
"resize-detector": "^0.2.0"
|
||||
}
|
||||
},
|
||||
"@formatjs/intl-displaynames": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "http://registry.npm.xiaojukeji.com/@formatjs/intl-displaynames/download/@formatjs/intl-displaynames-1.2.2.tgz",
|
||||
"integrity": "sha1-0PDt662WZgGW0oL2CaEWmoiifUo=",
|
||||
"requires": {
|
||||
"@formatjs/intl-utils": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"@formatjs/intl-listformat": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "http://registry.npm.xiaojukeji.com/@formatjs/intl-listformat/download/@formatjs/intl-listformat-1.4.2.tgz",
|
||||
"integrity": "sha1-7YJQEH6E+qn+n6/YYCAi6NnWoXk=",
|
||||
"requires": {
|
||||
"@formatjs/intl-utils": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"@formatjs/intl-relativetimeformat": {
|
||||
"version": "4.5.10",
|
||||
"resolved": "http://registry.npm.xiaojukeji.com/@formatjs/intl-relativetimeformat/download/@formatjs/intl-relativetimeformat-4.5.10.tgz",
|
||||
"integrity": "sha1-XCN3XaQ2bo43Y8kAJwcR1CoPT7c=",
|
||||
"requires": {
|
||||
"@formatjs/intl-utils": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"@formatjs/intl-unified-numberformat": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "http://registry.npm.xiaojukeji.com/@formatjs/intl-unified-numberformat/download/@formatjs/intl-unified-numberformat-3.3.0.tgz",
|
||||
"integrity": "sha1-BpI0apzUMquyzZtoed3WWSWFZBo=",
|
||||
"requires": {
|
||||
"@formatjs/intl-utils": "^2.2.0"
|
||||
}
|
||||
},
|
||||
"@formatjs/intl-utils": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "http://registry.npm.xiaojukeji.com/@formatjs/intl-utils/download/@formatjs/intl-utils-2.2.0.tgz",
|
||||
"integrity": "sha1-um4S/mT/f9FgvjkgB8R9JLeuXHU="
|
||||
},
|
||||
"@hot-loader/react-dom": {
|
||||
"version": "16.8.6",
|
||||
"resolved": "https://registry.npmjs.org/@hot-loader/react-dom/-/react-dom-16.8.6.tgz",
|
||||
|
@ -2402,6 +2439,11 @@
|
|||
"hoist-non-react-statics": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"@types/invariant": {
|
||||
"version": "2.2.31",
|
||||
"resolved": "http://registry.npm.xiaojukeji.com/@types/invariant/download/@types/invariant-2.2.31.tgz",
|
||||
"integrity": "sha1-RETAMATyFSidvKOFZThDQxfdKLI="
|
||||
},
|
||||
"@types/lodash": {
|
||||
"version": "4.14.149",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.149.tgz",
|
||||
|
@ -7952,6 +7994,28 @@
|
|||
"ipaddr.js": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"intl-format-cache": {
|
||||
"version": "4.2.22",
|
||||
"resolved": "http://registry.npm.xiaojukeji.com/intl-format-cache/download/intl-format-cache-4.2.22.tgz",
|
||||
"integrity": "sha1-tafory9Dnq/r0MQOP+bNilTnnR0="
|
||||
},
|
||||
"intl-messageformat": {
|
||||
"version": "8.2.3",
|
||||
"resolved": "http://registry.npm.xiaojukeji.com/intl-messageformat/download/intl-messageformat-8.2.3.tgz",
|
||||
"integrity": "sha1-CQ6T8uX347l8fOmpTfqZLz0OjE8=",
|
||||
"requires": {
|
||||
"intl-format-cache": "^4.2.22",
|
||||
"intl-messageformat-parser": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"intl-messageformat-parser": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "http://registry.npm.xiaojukeji.com/intl-messageformat-parser/download/intl-messageformat-parser-4.1.1.tgz",
|
||||
"integrity": "sha1-M6OsGFSoua3Bjfxz2wGKv5G+TDI=",
|
||||
"requires": {
|
||||
"@formatjs/intl-unified-numberformat": "^3.3.0"
|
||||
}
|
||||
},
|
||||
"invariant": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
||||
|
@ -11421,6 +11485,40 @@
|
|||
"source-map": "^0.7.3"
|
||||
}
|
||||
},
|
||||
"react-intl": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "http://registry.npm.xiaojukeji.com/react-intl/download/react-intl-4.2.2.tgz",
|
||||
"integrity": "sha1-VLQGXHTXd8RtnURZASSqkm39nCE=",
|
||||
"requires": {
|
||||
"@formatjs/intl-displaynames": "^1.2.2",
|
||||
"@formatjs/intl-listformat": "^1.4.2",
|
||||
"@formatjs/intl-relativetimeformat": "^4.5.10",
|
||||
"@formatjs/intl-unified-numberformat": "^3.3.0",
|
||||
"@formatjs/intl-utils": "^2.2.0",
|
||||
"@types/hoist-non-react-statics": "^3.3.1",
|
||||
"@types/invariant": "^2.2.31",
|
||||
"hoist-non-react-statics": "^3.3.2",
|
||||
"intl-format-cache": "^4.2.22",
|
||||
"intl-messageformat": "^8.2.3",
|
||||
"intl-messageformat-parser": "^4.1.1",
|
||||
"shallow-equal": "^1.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "http://registry.npm.xiaojukeji.com/hoist-non-react-statics/download/hoist-non-react-statics-3.3.2.tgz",
|
||||
"integrity": "sha1-7OCsr3HWLClpwuxZ/v9CpLGoW0U=",
|
||||
"requires": {
|
||||
"react-is": "^16.7.0"
|
||||
}
|
||||
},
|
||||
"shallow-equal": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "http://registry.npm.xiaojukeji.com/shallow-equal/download/shallow-equal-1.2.1.tgz",
|
||||
"integrity": "sha1-TBar+lYEOqINBQMk76aJQLDaedo="
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.8.6",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz",
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
"react-dom": "^16.8.6",
|
||||
"react-highlight": "^0.12.0",
|
||||
"react-hot-loader": "^4.8.7",
|
||||
"react-intl": "^4.2.2",
|
||||
"react-router-dom": "4.x",
|
||||
"react-sortable-hoc": "^1.8.3",
|
||||
"react-syntax-highlighter": "^7.0.4",
|
||||
|
|
|
@ -4,3 +4,5 @@ declare module 'd3';
|
|||
declare module 'd3-scale-chromatic';
|
||||
declare module '@d3-charts/ts-graph';
|
||||
declare module 'react-sortable-hoc';
|
||||
declare module 'rc-calendar';
|
||||
declare module 'rc-calendar/lib/locale/en_US';
|
||||
|
|
112
web/src/app.tsx
112
web/src/app.tsx
|
@ -1,9 +1,16 @@
|
|||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { HashRouter, Switch, Route, Redirect } from 'react-router-dom';
|
||||
import { hot } from 'react-hot-loader/root';
|
||||
import { ConfigProvider } from 'antd';
|
||||
import antdZhCN from 'antd/lib/locale/zh_CN';
|
||||
import antdEnUS from 'antd/lib/locale/en_US';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import _ from 'lodash';
|
||||
import { Page403, Page404 } from '@cpts/Exception';
|
||||
import { Login, Register, PrivateRoute } from '@cpts/Auth';
|
||||
import Layout from './components/Layout';
|
||||
import Layout from '@cpts/Layout';
|
||||
import intlZhCN from './locales/zh';
|
||||
import intlEnUS from './locales/en';
|
||||
import Monitor from './pages/Monitor';
|
||||
import ServiceTree from './pages/ServiceTree';
|
||||
import User from './pages/User';
|
||||
|
@ -13,87 +20,120 @@ interface Props {
|
|||
habitsId: string;
|
||||
}
|
||||
|
||||
interface LocaleMap {
|
||||
[index: string]: any,
|
||||
}
|
||||
|
||||
const localeMap: LocaleMap = {
|
||||
zh: {
|
||||
antd: antdZhCN,
|
||||
intl: 'zh',
|
||||
intlMessages: intlZhCN,
|
||||
},
|
||||
en: {
|
||||
antd: antdEnUS,
|
||||
intl: 'en',
|
||||
intlMessages: intlEnUS,
|
||||
},
|
||||
};
|
||||
const defaultLanguage = window.localStorage.getItem('language') || navigator.language.substr(0, 2);
|
||||
|
||||
function App({ habitsId }: Props) {
|
||||
const [language, setLanguage] = useState(defaultLanguage);
|
||||
const intlMessages = _.get(localeMap[language], 'intlMessages', intlZhCN);
|
||||
const menuConf = [
|
||||
{
|
||||
name: '监控对象',
|
||||
name: intlMessages['menu.endpoints'],
|
||||
path: 'sTree',
|
||||
icon: 'cluster',
|
||||
children: [
|
||||
{
|
||||
name: '全部对象',
|
||||
name: intlMessages['menu.endpoints.all'],
|
||||
path: 'endpointMgmt',
|
||||
}, {
|
||||
name: '节点下对象',
|
||||
name: intlMessages['menu.endpoints.node'],
|
||||
path: 'endpoints',
|
||||
}, {
|
||||
name: '树节点管理',
|
||||
name: intlMessages['menu.endpoints.node.manage'],
|
||||
path: 'node',
|
||||
},
|
||||
],
|
||||
}, {
|
||||
name: '监控报警',
|
||||
name: intlMessages['menu.monitor'],
|
||||
path: 'monitor',
|
||||
icon: 'icon-speed-fast',
|
||||
children: [
|
||||
{
|
||||
name: '监控看图',
|
||||
name: intlMessages['menu.monitor.dashboard'],
|
||||
path: 'dashboard',
|
||||
}, {
|
||||
name: '监控大盘',
|
||||
name: intlMessages['menu.monitor.screen'],
|
||||
path: 'screen',
|
||||
}, {
|
||||
name: '报警策略',
|
||||
name: intlMessages['menu.monitor.strategy'],
|
||||
path: 'strategy',
|
||||
}, {
|
||||
name: '报警历史',
|
||||
name: intlMessages['menu.monitor.history'],
|
||||
path: 'history',
|
||||
}, {
|
||||
name: '报警屏蔽',
|
||||
name: intlMessages['menu.monitor.silence'],
|
||||
path: 'silence',
|
||||
}, {
|
||||
name: '采集配置',
|
||||
name: intlMessages['menu.monitor.collect'],
|
||||
path: 'collect',
|
||||
},
|
||||
],
|
||||
}, {
|
||||
name: '用户管理',
|
||||
name: intlMessages['menu.users'],
|
||||
path: 'user',
|
||||
icon: 'icon-users2',
|
||||
children: [
|
||||
{
|
||||
name: '用户管理',
|
||||
name: intlMessages['menu.users.users'],
|
||||
path: 'list',
|
||||
}, {
|
||||
name: '团队管理',
|
||||
name: intlMessages['menu.users.teams'],
|
||||
path: 'team',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<HashRouter>
|
||||
<Switch>
|
||||
<Route path="/login" component={Login} />
|
||||
<Route path="/register" component={Register} />
|
||||
<Route path="/403" component={Page403} />
|
||||
<Route path="/404" component={Page404} />
|
||||
<Layout
|
||||
appName=""
|
||||
menuConf={menuConf}
|
||||
habitsId={habitsId}
|
||||
>
|
||||
<IntlProvider
|
||||
locale={_.get(localeMap[language], 'intl', 'zh')}
|
||||
messages={intlMessages}
|
||||
>
|
||||
<ConfigProvider locale={_.get(localeMap[language], 'antd', antdZhCN)}>
|
||||
<HashRouter>
|
||||
<Switch>
|
||||
<Route exact path="/" render={() => <Redirect to="/sTree" />} />
|
||||
<PrivateRoute path="/monitor" component={Monitor} />
|
||||
<PrivateRoute path="/sTree" component={ServiceTree} />
|
||||
<PrivateRoute path="/user" component={User} />
|
||||
<PrivateRoute path="/profile" component={Profile} />
|
||||
<Route render={() => <Redirect to="/404" />} />
|
||||
<Route path="/login" component={Login} />
|
||||
<Route path="/register" component={Register} />
|
||||
<Route path="/403" component={Page403} />
|
||||
<Route path="/404" component={Page404} />
|
||||
<Layout
|
||||
appName=""
|
||||
menuConf={menuConf}
|
||||
habitsId={habitsId}
|
||||
language={language}
|
||||
onLanguageChange={(newLanguage) => {
|
||||
setLanguage(newLanguage);
|
||||
window.localStorage.setItem('language', newLanguage);
|
||||
}}
|
||||
>
|
||||
<Switch>
|
||||
<Route exact path="/" render={() => <Redirect to="/sTree" />} />
|
||||
<PrivateRoute path="/monitor" component={Monitor} />
|
||||
<PrivateRoute path="/sTree" component={ServiceTree} />
|
||||
<PrivateRoute path="/user" component={User} />
|
||||
<PrivateRoute path="/profile" component={Profile} />
|
||||
<Route render={() => <Redirect to="/404" />} />
|
||||
</Switch>
|
||||
</Layout>
|
||||
</Switch>
|
||||
</Layout>
|
||||
</Switch>
|
||||
</HashRouter>
|
||||
</HashRouter>
|
||||
</ConfigProvider>
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,13 +4,14 @@ import { Card, Form, Input, Icon, Button, Checkbox } from 'antd';
|
|||
import { FormProps } from 'antd/lib/form';
|
||||
import queryString from 'query-string';
|
||||
import _ from 'lodash';
|
||||
import { injectIntl, WrappedComponentProps } from 'react-intl';
|
||||
import { appname } from '@common/config';
|
||||
import auth from './auth';
|
||||
import './style.less';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
class Login extends Component<RouteComponentProps & FormProps> {
|
||||
class Login extends Component<RouteComponentProps & FormProps & WrappedComponentProps> {
|
||||
handleSubmit = (e: FormEvent) => {
|
||||
e.preventDefault();
|
||||
const { history, location } = this.props;
|
||||
|
@ -47,6 +48,7 @@ class Login extends Component<RouteComponentProps & FormProps> {
|
|||
const { history } = this.props;
|
||||
const { getFieldDecorator } = this.props.form!;
|
||||
const isAuthenticated = auth.getIsAuthenticated();
|
||||
const { formatMessage } = this.props.intl;
|
||||
|
||||
if (isAuthenticated) {
|
||||
history.push({
|
||||
|
@ -58,20 +60,20 @@ class Login extends Component<RouteComponentProps & FormProps> {
|
|||
<div className={prefixCls}>
|
||||
<div className={`${prefixCls}-main`}>
|
||||
<Card>
|
||||
<div className={`${prefixCls}-title`}>账户登录</div>
|
||||
<div className={`${prefixCls}-title`}>{formatMessage({ id: 'login.title' })}</div>
|
||||
<Form onSubmit={this.handleSubmit}>
|
||||
<FormItem>
|
||||
{getFieldDecorator('username', {
|
||||
rules: [{ required: true, message: '请输入你的用户名!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<Input prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="用户名" />,
|
||||
<Input prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder={formatMessage({ id: 'user.username' })} />,
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
{getFieldDecorator('password', {
|
||||
rules: [{ required: true, message: '请输入你的密码!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<Input prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} type="password" placeholder="密码" />,
|
||||
<Input prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} type="password" placeholder={formatMessage({ id: 'user.password' })} />,
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
|
@ -79,10 +81,10 @@ class Login extends Component<RouteComponentProps & FormProps> {
|
|||
valuePropName: 'checked',
|
||||
initialValue: false,
|
||||
})(
|
||||
<Checkbox>使用LDAP账号登录</Checkbox>,
|
||||
<Checkbox>{formatMessage({ id: 'login.ldap' })}</Checkbox>,
|
||||
)}
|
||||
<Button type="primary" htmlType="submit" className={`${prefixCls}-submitBtn`}>
|
||||
登 录
|
||||
{formatMessage({ id: 'form.login' })}
|
||||
</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
|
@ -93,4 +95,4 @@ class Login extends Component<RouteComponentProps & FormProps> {
|
|||
}
|
||||
}
|
||||
|
||||
export default Form.create()(Login);
|
||||
export default injectIntl(Form.create()(Login));
|
||||
|
|
|
@ -2,17 +2,19 @@ import React, { Component, FormEvent } from 'react';
|
|||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import { Card, Button, message } from 'antd';
|
||||
import queryString from 'query-string';
|
||||
import { injectIntl, WrappedComponentProps } from 'react-intl';
|
||||
import ProfileForm from '@cpts/ProfileForm';
|
||||
import request from '@common/request';
|
||||
import api from '@common/api';
|
||||
import { appname } from '@common/config';
|
||||
import './style.less';
|
||||
|
||||
class Register extends Component<RouteComponentProps> {
|
||||
class Register extends Component<RouteComponentProps & WrappedComponentProps> {
|
||||
profileForm: any; // TODO useRef
|
||||
handleSubmit = (e: FormEvent) => {
|
||||
e.preventDefault();
|
||||
const { location, history } = this.props;
|
||||
const { formatMessage } = this.props.intl;
|
||||
const query = queryString.parse(location.search);
|
||||
this.profileForm.validateFields((err: any, values: any) => {
|
||||
if (!err) {
|
||||
|
@ -23,7 +25,7 @@ class Register extends Component<RouteComponentProps> {
|
|||
token: query.token,
|
||||
}),
|
||||
}).then(() => {
|
||||
message.success('注册成功!');
|
||||
message.success(formatMessage({ id: 'msg.submit.success' }));
|
||||
history.push({
|
||||
pathname: '/',
|
||||
});
|
||||
|
@ -34,19 +36,20 @@ class Register extends Component<RouteComponentProps> {
|
|||
|
||||
render() {
|
||||
const prefixCls = `${appname}-register`;
|
||||
const { formatMessage } = this.props.intl;
|
||||
|
||||
return (
|
||||
<div className={prefixCls}>
|
||||
<div className={`${prefixCls}-main`}>
|
||||
<Card>
|
||||
<div className={`${prefixCls}-title`}>账户注册</div>
|
||||
<div className={`${prefixCls}-title`}>{formatMessage({ id: 'register' })}</div>
|
||||
<ProfileForm type="register" ref={(ref: any) => { this.profileForm = ref; }} />
|
||||
<Button
|
||||
type="primary"
|
||||
className={`${prefixCls}-submitBtn`}
|
||||
onClick={this.handleSubmit}
|
||||
>
|
||||
注 册
|
||||
{formatMessage({ id: 'register' })}
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
|
@ -55,4 +58,4 @@ class Register extends Component<RouteComponentProps> {
|
|||
}
|
||||
}
|
||||
|
||||
export default Register;
|
||||
export default injectIntl(Register);
|
||||
|
|
|
@ -1,123 +0,0 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Table } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import queryString from 'query-string';
|
||||
import api from '@common/api';
|
||||
import * as config from '@common/config';
|
||||
import request from '@common/request';
|
||||
import './style.less';
|
||||
|
||||
export default class BaseComponent extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.api = api;
|
||||
this.config = config;
|
||||
this.prefixCls = config.appname;
|
||||
this.request = request;
|
||||
this.otherParamsKey = [];
|
||||
this.state = {
|
||||
loading: false,
|
||||
pagination: {
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
showSizeChanger: true,
|
||||
},
|
||||
data: [],
|
||||
searchValue: '',
|
||||
};
|
||||
}
|
||||
|
||||
handleSearchChange = (value) => {
|
||||
this.setState({ searchValue: value }, () => {
|
||||
this.reload({
|
||||
query: value,
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
||||
handleTableChange = (pagination) => {
|
||||
const { pagination: paginationState } = this.state;
|
||||
const pager = {
|
||||
...paginationState,
|
||||
current: pagination.current,
|
||||
pageSize: pagination.pageSize,
|
||||
};
|
||||
this.setState({ pagination: pager }, () => {
|
||||
this.reload({
|
||||
limit: pagination.pageSize,
|
||||
page: pagination.current,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
reload(params) {
|
||||
this.fetchData(params);
|
||||
}
|
||||
|
||||
fetchData(newParams = {}, backFirstPage = false) {
|
||||
const url = this.getFetchDataUrl();
|
||||
|
||||
if (!url) return;
|
||||
const othenParams = _.pick(this.state, this.otherParamsKey);
|
||||
const { pagination, searchValue } = this.state;
|
||||
const params = {
|
||||
limit: pagination.pageSize,
|
||||
p: backFirstPage ? 1 : pagination.current,
|
||||
query: searchValue,
|
||||
...othenParams,
|
||||
...newParams,
|
||||
};
|
||||
|
||||
this.setState({ loading: true });
|
||||
// TODO: Method 'fetchData' expected no return value.
|
||||
// eslint-disable-next-line consistent-return
|
||||
return this.request(`${url}?${queryString(params)}`).then((res) => {
|
||||
const newPagination = {
|
||||
...pagination,
|
||||
current: backFirstPage ? 1 : pagination.current,
|
||||
total: res.total,
|
||||
};
|
||||
let data = [];
|
||||
if (_.isArray(res.list)) {
|
||||
data = res.list;
|
||||
} else if (_.isArray(res)) {
|
||||
data = res;
|
||||
}
|
||||
this.setState({
|
||||
data,
|
||||
pagination: newPagination,
|
||||
});
|
||||
return data;
|
||||
}).finally(() => {
|
||||
this.setState({ loading: false });
|
||||
});
|
||||
}
|
||||
|
||||
renderTable(params) {
|
||||
const { loading, pagination, data } = this.state;
|
||||
return (
|
||||
<Table
|
||||
rowKey="id"
|
||||
size="small"
|
||||
loading={loading}
|
||||
pagination={{
|
||||
...pagination,
|
||||
showTotal: total => `共 ${total} 条数据`,
|
||||
pageSizeOptions: config.defaultPageSizeOptions,
|
||||
onChange: () => {
|
||||
if (this.handlePaginationChange) this.handlePaginationChange();
|
||||
},
|
||||
}}
|
||||
rowClassName={(record, index) => {
|
||||
if (index % 2 === 1) {
|
||||
return 'table-row-bg';
|
||||
}
|
||||
return '';
|
||||
}}
|
||||
dataSource={data}
|
||||
onChange={this.handleTableChange}
|
||||
{...params}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
.table-row-bg {
|
||||
background: #f9f9f9;
|
||||
}
|
|
@ -134,17 +134,14 @@ export default class DateInput extends Component<any, any> {
|
|||
...locale,
|
||||
}}
|
||||
selectedValue={selectedValue}
|
||||
onOk={(mDate) => {
|
||||
onOk={(mDate: any) => {
|
||||
onChange(mDate.toDate());
|
||||
this.closePopover();
|
||||
}}
|
||||
onClear={() => {
|
||||
this.closePopover();
|
||||
}}
|
||||
// onChange={(mDate) => {
|
||||
// this.setState({ tempSelectedValue: mDate.format(momentFormat) });
|
||||
// }}
|
||||
onSelect={(mDate) => {
|
||||
onSelect={(mDate: any) => {
|
||||
if (mDate && mDate.format() !== 'Invalid date') {
|
||||
this.setState({ tempSelectedValue: mDate.format(momentFormat) });
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Modal, Form, Input, Radio } from 'antd';
|
|||
import { FormProps } from 'antd/lib/form';
|
||||
import _ from 'lodash';
|
||||
import ModalControl from '@cpts/ModalControl';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
interface Props {
|
||||
field: string,
|
||||
|
@ -18,7 +19,7 @@ const FormItem = Form.Item;
|
|||
const RadioGroup = Radio.Group;
|
||||
|
||||
class BatchSearch extends Component<Props & FormProps> {
|
||||
static defaultProps = {
|
||||
static defaultProps: any = {
|
||||
field: 'ident',
|
||||
batch: '',
|
||||
title: '',
|
||||
|
@ -54,17 +55,17 @@ class BatchSearch extends Component<Props & FormProps> {
|
|||
onCancel={this.handleCancel}
|
||||
>
|
||||
<Form layout="vertical">
|
||||
<FormItem label="过滤字段">
|
||||
<FormItem label={<FormattedMessage id="endpoints.batch.filter.key" />}>
|
||||
{getFieldDecorator('field', {
|
||||
initialValue: field,
|
||||
})(
|
||||
<RadioGroup>
|
||||
<Radio value="ident">标识</Radio>
|
||||
<Radio value="alias">别名</Radio>
|
||||
<Radio value="ident"><FormattedMessage id="endpoints.ident" /></Radio>
|
||||
<Radio value="alias"><FormattedMessage id="endpoints.alias" /></Radio>
|
||||
</RadioGroup>,
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem label="过滤值">
|
||||
<FormItem label={<FormattedMessage id="endpoints.batch.filter.value" />}>
|
||||
{getFieldDecorator('batch', {
|
||||
initialValue: _.replace(batch, /,/g, '\n'),
|
||||
})(
|
||||
|
|
|
@ -2,6 +2,7 @@ import React, { Component } from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import { Dropdown, Menu, Modal, Input, Icon, message } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import clipboard from '@common/clipboard';
|
||||
import request from '@common/request';
|
||||
import api from '@common/api';
|
||||
|
@ -14,16 +15,10 @@ interface Props {
|
|||
hasSelected: boolean;
|
||||
}
|
||||
|
||||
export default class CopyTitle extends Component<Props> {
|
||||
class CopyTitle extends Component<Props> {
|
||||
static contextTypes = {
|
||||
getSelectedNode: PropTypes.func,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
data: PropTypes.array,
|
||||
selected: PropTypes.array,
|
||||
dataIndex: PropTypes.string.isRequired,
|
||||
hasSelected: PropTypes.bool,
|
||||
intl: PropTypes.any,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -33,7 +28,7 @@ export default class CopyTitle extends Component<Props> {
|
|||
};
|
||||
|
||||
handleCopyBtnClick = async (dataIndex: string, copyType: string) => {
|
||||
const { getSelectedNode } = this.context;
|
||||
const { getSelectedNode, intl } = this.context;
|
||||
const { data, selected } = this.props;
|
||||
let tobeCopy = [];
|
||||
|
||||
|
@ -47,13 +42,14 @@ export default class CopyTitle extends Component<Props> {
|
|||
}
|
||||
tobeCopy = _.map(allData, item => item[dataIndex]);
|
||||
} else if (copyType === 'currentPage') {
|
||||
console.log('dataIndex', dataIndex);
|
||||
tobeCopy = _.map(data, item => item[dataIndex]);
|
||||
} else if (copyType === 'selected') {
|
||||
tobeCopy = _.map(selected, item => item[dataIndex]);
|
||||
}
|
||||
|
||||
if (_.isEmpty(tobeCopy)) {
|
||||
message.warning('复制的对象为空');
|
||||
message.warning(intl.formatMessage({ id: 'endpoints.copy.empty' }));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -61,10 +57,14 @@ export default class CopyTitle extends Component<Props> {
|
|||
const copySucceeded = clipboard(tobeCopyStr);
|
||||
|
||||
if (copySucceeded) {
|
||||
message.success(`复制成功${tobeCopy.length}条记录!`);
|
||||
if (intl.locale === 'zh') {
|
||||
message.success(`复制成功${tobeCopy.length}条记录`);
|
||||
} else if (intl.locale === 'en') {
|
||||
message.success(`Successful copy ${tobeCopy.length} items`);
|
||||
}
|
||||
} else {
|
||||
Modal.warning({
|
||||
title: '复制失败,请手动复制',
|
||||
title: intl.formatMessage({ id: 'endpoints.copy.error' }),
|
||||
content: <Input.TextArea defaultValue={tobeCopyStr} />,
|
||||
});
|
||||
}
|
||||
|
@ -81,13 +81,19 @@ export default class CopyTitle extends Component<Props> {
|
|||
overlay={
|
||||
<Menu>
|
||||
<Menu.Item>
|
||||
<a onClick={() => this.handleCopyBtnClick(dataIndex, 'selected')}>复制已选</a>
|
||||
<a onClick={() => this.handleCopyBtnClick(dataIndex, 'selected')}>
|
||||
<FormattedMessage id="endpoints.copy.selected" />
|
||||
</a>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<a onClick={() => this.handleCopyBtnClick(dataIndex, 'currentPage')}>复制当前页</a>
|
||||
<a onClick={() => this.handleCopyBtnClick(dataIndex, 'currentPage')}>
|
||||
<FormattedMessage id="endpoints.copy.currentPage" />
|
||||
</a>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<a onClick={() => this.handleCopyBtnClick(dataIndex, 'all')}>复制所有</a>
|
||||
<a onClick={() => this.handleCopyBtnClick(dataIndex, 'all')}>
|
||||
<FormattedMessage id="endpoints.copy.all" />
|
||||
</a>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
}
|
||||
|
@ -112,3 +118,5 @@ export default class CopyTitle extends Component<Props> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default CopyTitle;
|
||||
|
|
|
@ -2,6 +2,7 @@ import React, { Component } from 'react';
|
|||
import { Modal, Form, Input, message } from 'antd';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
import _ from 'lodash';
|
||||
import { injectIntl, FormattedMessage, WrappedComponentProps } from 'react-intl';
|
||||
import ModalControl from '@cpts/ModalControl';
|
||||
import { Endpoint } from '@interface';
|
||||
import request from '@common/request';
|
||||
|
@ -19,7 +20,7 @@ interface Props {
|
|||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
class SingleEdit extends Component<FormProps & Props> {
|
||||
class SingleEdit extends Component<FormProps & Props & WrappedComponentProps> {
|
||||
static defaultProps = {
|
||||
title: '',
|
||||
visible: true,
|
||||
|
@ -29,7 +30,6 @@ class SingleEdit extends Component<FormProps & Props> {
|
|||
};
|
||||
|
||||
handleOk = () => {
|
||||
const { title } = this.props;
|
||||
this.props.form!.validateFields((err, values) => {
|
||||
if (!err) {
|
||||
request(`${api.endpoint}/${values.id}`, {
|
||||
|
@ -38,7 +38,7 @@ class SingleEdit extends Component<FormProps & Props> {
|
|||
alias: values.alias,
|
||||
}),
|
||||
}).then(() => {
|
||||
message.success(`${title}成功`);
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.modify.success' }));
|
||||
this.props.onOk();
|
||||
this.props.destroy();
|
||||
});
|
||||
|
@ -68,10 +68,10 @@ class SingleEdit extends Component<FormProps & Props> {
|
|||
e.preventDefault();
|
||||
this.handleOk();
|
||||
}}>
|
||||
<FormItem label="标识">
|
||||
<FormItem label={<FormattedMessage id="endpoints.ident" />}>
|
||||
<span className="ant-form-text">{data.ident}</span>
|
||||
</FormItem>
|
||||
<FormItem label="别名">
|
||||
<FormItem label={<FormattedMessage id="endpoints.alias" />}>
|
||||
{getFieldDecorator('alias', {
|
||||
initialValue: data.alias,
|
||||
})(
|
||||
|
@ -84,4 +84,4 @@ class SingleEdit extends Component<FormProps & Props> {
|
|||
}
|
||||
}
|
||||
|
||||
export default ModalControl(Form.create()(SingleEdit));
|
||||
export default ModalControl(Form.create()(injectIntl(SingleEdit)));
|
||||
|
|
|
@ -4,6 +4,7 @@ import { Link } from 'react-router-dom';
|
|||
import { Row, Col, Input, Button, Dropdown, Menu, Checkbox, Icon } from 'antd';
|
||||
import { ColumnProps } from 'antd/lib/table';
|
||||
import _ from 'lodash';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import FetchTable from '@cpts/FetchTable';
|
||||
import request from '@common/request';
|
||||
import api from '@common/api';
|
||||
|
@ -35,6 +36,7 @@ interface State {
|
|||
class index extends Component<Props, State> {
|
||||
static contextTypes = {
|
||||
habitsId: PropTypes.string,
|
||||
intl: PropTypes.any,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -55,7 +57,8 @@ class index extends Component<Props, State> {
|
|||
|
||||
handelBatchSearchBtnClick = () => {
|
||||
BatchSearch({
|
||||
title: '批量过滤',
|
||||
title: this.context.intl.formatMessage({ id: 'endpoints.batch.filter' }),
|
||||
language: this.context.intl.locale,
|
||||
field: this.state.field,
|
||||
batch: this.state.batch,
|
||||
onOk: (field: string, batch: string) => {
|
||||
|
@ -127,7 +130,7 @@ class index extends Component<Props, State> {
|
|||
data={_.get(this.fetchtable, 'state.data')}
|
||||
selected={this.state.selectedRows}
|
||||
>
|
||||
标识
|
||||
<FormattedMessage id="endpoints.ident" />
|
||||
</CopyTitle>
|
||||
),
|
||||
dataIndex: 'ident',
|
||||
|
@ -149,11 +152,11 @@ class index extends Component<Props, State> {
|
|||
);
|
||||
},
|
||||
}, {
|
||||
title: '别名',
|
||||
title: <FormattedMessage id="endpoints.alias" />,
|
||||
dataIndex: 'alias',
|
||||
}, {
|
||||
title: '操作',
|
||||
width: 100,
|
||||
title: <FormattedMessage id="table.operations" />,
|
||||
width: 150,
|
||||
render: (_text, record) => {
|
||||
return this.props.renderOper(record);
|
||||
},
|
||||
|
@ -161,7 +164,7 @@ class index extends Component<Props, State> {
|
|||
];
|
||||
if (displayBindNode) {
|
||||
fullColumns.splice(2, 0, {
|
||||
title: '挂载节点',
|
||||
title: <FormattedMessage id="endpoints.nodes" />,
|
||||
dataIndex: 'nodes',
|
||||
render(text) {
|
||||
return (
|
||||
|
@ -195,7 +198,7 @@ class index extends Component<Props, State> {
|
|||
searchValue: value,
|
||||
});
|
||||
}}
|
||||
placeholder="快速过滤"
|
||||
placeholder="Search"
|
||||
/>
|
||||
<Button
|
||||
className="ml10"
|
||||
|
@ -203,7 +206,7 @@ class index extends Component<Props, State> {
|
|||
icon={batch ? 'check-circle' : ''}
|
||||
onClick={this.handelBatchSearchBtnClick}
|
||||
>
|
||||
批量过滤
|
||||
<FormattedMessage id="endpoints.batch.filter" />
|
||||
</Button>
|
||||
<Checkbox
|
||||
className="ml10"
|
||||
|
@ -215,7 +218,7 @@ class index extends Component<Props, State> {
|
|||
});
|
||||
}}
|
||||
>
|
||||
显示挂载节点
|
||||
<FormattedMessage id="node.display.path" />
|
||||
</Checkbox>
|
||||
</Col>
|
||||
<Col span={8} className="textAlignRight">
|
||||
|
@ -223,13 +226,15 @@ class index extends Component<Props, State> {
|
|||
overlay={
|
||||
<Menu>
|
||||
<Menu.Item>
|
||||
<a onClick={() => { this.props.exportEndpoints(_.get(this.fetchtable, 'state.data')); }}>导出 Excel</a>
|
||||
<a onClick={() => { this.props.exportEndpoints(_.get(this.fetchtable, 'state.data')); }}>
|
||||
<FormattedMessage id="endpoints.export.excel" />
|
||||
</a>
|
||||
</Menu.Item>
|
||||
{this.props.renderBatchOper(this.state.selectedIdents)}
|
||||
</Menu>
|
||||
}
|
||||
>
|
||||
<Button icon="down">批量操作</Button>
|
||||
<Button icon="down"><FormattedMessage id="table.batch.operations" /></Button>
|
||||
</Dropdown>
|
||||
</Col>
|
||||
</Row>
|
||||
|
|
|
@ -166,7 +166,7 @@ export default class FetchTable extends Component<Props, State> {
|
|||
pagination={{
|
||||
...this.state.pagination,
|
||||
showTotal: (total) => {
|
||||
return `共 ${total} 条数据`;
|
||||
return `Total ${total} items`;
|
||||
},
|
||||
pageSizeOptions: config.defaultPageSizeOptions,
|
||||
}}
|
||||
|
|
|
@ -28,15 +28,15 @@ export default class Info extends Component<Props> {
|
|||
return (
|
||||
<ul className="graph-info" key={groupName}>
|
||||
<li>
|
||||
<span className="graph-info-key">指标:</span>
|
||||
<span className="graph-info-key">Metric:</span>
|
||||
<span className="graph-info-value">{groupName}</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className="graph-info-key">采集周期:</span>
|
||||
<span className="graph-info-key">Step:</span>
|
||||
<span className="graph-info-value">{firstItem.step ? `${firstItem.step} s` : '无'}</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className="graph-info-key">时间范围:</span>
|
||||
<span className="graph-info-key">Time:</span>
|
||||
<span className="graph-info-value">
|
||||
{moment(Number(start)).format(config.timeFormatMap.moment)}
|
||||
<span> - </span>
|
||||
|
@ -46,7 +46,7 @@ export default class Info extends Component<Props> {
|
|||
{
|
||||
unit ?
|
||||
<li>
|
||||
<span className="graph-info-key">单位:</span>
|
||||
<span className="graph-info-key">Unit:</span>
|
||||
<span className="graph-info-value">{unit}</span>
|
||||
</li> : null
|
||||
}
|
||||
|
@ -61,7 +61,6 @@ export default class Info extends Component<Props> {
|
|||
<Popover
|
||||
trigger="click"
|
||||
content={this.getContent()}
|
||||
title="详情"
|
||||
placement="topLeft"
|
||||
>
|
||||
{this.props.children}
|
||||
|
|
|
@ -91,7 +91,7 @@ export default class Legend extends Component<Props, State> {
|
|||
const copySucceeded = clipboard(currentCounter);
|
||||
if (!copySucceeded) {
|
||||
Modal.info({
|
||||
title: '复制失败,请手动选择复制',
|
||||
title: 'Copy failed, please manually select copy',
|
||||
content: (
|
||||
<p>{currentCounter}</p>
|
||||
),
|
||||
|
@ -132,17 +132,17 @@ export default class Legend extends Component<Props, State> {
|
|||
const firstData = data[0];
|
||||
const columns: ColumnProps<LegendDataItem>[] = [
|
||||
{
|
||||
title: <span> 曲线({data.length}) </span>,
|
||||
title: <span> Series({data.length}) </span>,
|
||||
dataIndex: 'tags',
|
||||
filterDropdown: (
|
||||
<div className="custom-filter-dropdown">
|
||||
<Input
|
||||
placeholder="请输入曲线名称"
|
||||
placeholder="Input serie name"
|
||||
value={searchText}
|
||||
onChange={this.handleInputChange}
|
||||
onPressEnter={this.handleSearch}
|
||||
/>
|
||||
<Button type="primary" onClick={this.handleSearch}>搜索</Button>
|
||||
<Button type="primary" onClick={this.handleSearch}>Search</Button>
|
||||
</div>
|
||||
),
|
||||
filterDropdownVisible: this.state.filterDropdownVisible,
|
||||
|
@ -224,7 +224,7 @@ export default class Legend extends Component<Props, State> {
|
|||
|
||||
if (_.get(firstData, 'isSameMetric') === false) {
|
||||
columns.unshift({
|
||||
title: '指标',
|
||||
title: 'Metric',
|
||||
dataIndex: 'metric',
|
||||
width: 60,
|
||||
});
|
||||
|
@ -247,7 +247,7 @@ export default class Legend extends Component<Props, State> {
|
|||
<ContextMenu visible={this.state.contextMenuVisiable} left={this.state.contextMenuLeft} top={this.state.contextMenuTop}>
|
||||
<ul className="ant-dropdown-menu ant-dropdown-menu-vertical ant-dropdown-menu-light ant-dropdown-menu-root">
|
||||
<li className="ant-dropdown-menu-item">
|
||||
<a onClick={this.handleCopyCounter}>复制 counter</a>
|
||||
<a onClick={this.handleCopyCounter}>copy counter</a>
|
||||
</li>
|
||||
</ul>
|
||||
</ContextMenu>
|
||||
|
|
|
@ -191,19 +191,19 @@ export default class Graph extends Component<Props, State> {
|
|||
let errorText = e.err;
|
||||
|
||||
if (e.statusText === 'error') {
|
||||
errorText = '网络已断开,请检查网络';
|
||||
errorText = 'The network has been disconnected, please check the network';
|
||||
} else if (e.statusText === 'Not Found') {
|
||||
errorText = '404 Not Found,请联系管理员';
|
||||
errorText = '404 Not Found';
|
||||
} else if (e.responseJSON) {
|
||||
errorText = _.get(e.responseJSON, 'msg', e.responseText);
|
||||
|
||||
if (!errorText || e.status === 500) {
|
||||
errorText = '数据加载异常,请刷新重新加载';
|
||||
errorText = 'Data loading exception, please refresh and reload';
|
||||
}
|
||||
|
||||
// request entity too large
|
||||
if (e.status === 413) {
|
||||
errorText = '请求条件过大,请减少条件';
|
||||
errorText = 'Request condition is too large, please reduce the condition';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,17 +215,17 @@ export default class Graph extends Component<Props, State> {
|
|||
checkEndpointCounters(endpointCounters: CounterInterface[], countersMaxLength: number) {
|
||||
let errorText: any = '';
|
||||
if (!_.get(endpointCounters, 'length', 0)) {
|
||||
errorText = '暂无数据';
|
||||
errorText = 'No data';
|
||||
}
|
||||
|
||||
if (endpointCounters.length > countersMaxLength) {
|
||||
errorText = (
|
||||
<span className="counters-maxLength">
|
||||
曲线过多,当前
|
||||
Too many series,Current
|
||||
{endpointCounters.length}
|
||||
上限
|
||||
cap
|
||||
{countersMaxLength}
|
||||
,请减少曲线
|
||||
,Please reduce the number of series
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import _ from 'lodash';
|
||||
import moment from 'moment';
|
||||
import { Button, Select, DatePicker } from 'antd';
|
||||
|
@ -102,19 +103,22 @@ export default class GlobalOperationbar extends Component<Props> {
|
|||
<div className="global-operationbar-warp">
|
||||
{
|
||||
this.props.refreshVisible ?
|
||||
<Button onClick={this.handleRefresh} style={{ marginRight: 8 }}>刷新</Button> : null
|
||||
<Button onClick={this.handleRefresh} style={{ marginRight: 8 }}>
|
||||
<FormattedMessage id="graph.refresh" />
|
||||
</Button> : null
|
||||
}
|
||||
<span>
|
||||
<Select
|
||||
style={{ width: 80 }}
|
||||
value={timeVal}
|
||||
onChange={this.handleTimeOptionChange}
|
||||
placeholder="无"
|
||||
>
|
||||
{
|
||||
_.map(config.time, (o) => {
|
||||
return (
|
||||
<Select.Option key={o.value} value={o.value}>{o.label}</Select.Option>
|
||||
<Select.Option key={o.value} value={o.value}>
|
||||
<FormattedMessage id={o.label} />
|
||||
</Select.Option>
|
||||
);
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import update from 'react-addons-update';
|
||||
import { Row, Col, Spin, Table, Form, Select, Input, InputNumber, Icon, TreeSelect, DatePicker } from 'antd';
|
||||
|
@ -75,7 +76,7 @@ export default class GraphConfigForm extends Component<Props, State> {
|
|||
metrics,
|
||||
},
|
||||
loading: false,
|
||||
tableEmptyText: '暂无数据',
|
||||
tableEmptyText: 'No data',
|
||||
nsSearchVal: '', // 节点搜索值
|
||||
counterListVisible: false,
|
||||
advancedVisible: false,
|
||||
|
@ -525,7 +526,7 @@ export default class GraphConfigForm extends Component<Props, State> {
|
|||
<FormItem
|
||||
labelCol={{ span: 3 }}
|
||||
wrapperCol={{ span: 21 }}
|
||||
label="节点"
|
||||
label={<FormattedMessage id="graph.config.node" />}
|
||||
style={{ marginBottom: 5 }}
|
||||
required
|
||||
>
|
||||
|
@ -559,7 +560,7 @@ export default class GraphConfigForm extends Component<Props, State> {
|
|||
readOnly
|
||||
value={_.join(_.slice(selectedTagv, 0, 40), ', ')}
|
||||
size="default"
|
||||
placeholder="若无此tag,请留空"
|
||||
// placeholder="若无此tag,请留空"
|
||||
onClick={() => {
|
||||
show(tagk);
|
||||
}}
|
||||
|
@ -585,7 +586,7 @@ export default class GraphConfigForm extends Component<Props, State> {
|
|||
<FormItem
|
||||
labelCol={{ span: 3 }}
|
||||
wrapperCol={{ span: 21 }}
|
||||
label="指标"
|
||||
label={<FormattedMessage id="graph.config.metric" />}
|
||||
style={{ marginBottom: 5 }}
|
||||
required
|
||||
>
|
||||
|
@ -593,8 +594,8 @@ export default class GraphConfigForm extends Component<Props, State> {
|
|||
showSearch
|
||||
size="default"
|
||||
style={{ width: '100%' }}
|
||||
placeholder="监控项指标名, 如cpu.idle"
|
||||
notFoundContent="请输入关键词过滤"
|
||||
// placeholder="监控项指标名, 如cpu.idle"
|
||||
// notFoundContent="请输入关键词过滤"
|
||||
className="select-metric"
|
||||
value={metricObj.selectedMetric}
|
||||
onChange={(value: string) => this.handleMetricChange(value, currentMetric)}
|
||||
|
@ -609,21 +610,21 @@ export default class GraphConfigForm extends Component<Props, State> {
|
|||
<FormItem
|
||||
labelCol={{ span: 6 }}
|
||||
wrapperCol={{ span: 18 }}
|
||||
label="聚合"
|
||||
label={<FormattedMessage id="graph.config.aggr" />}
|
||||
style={{ marginBottom: 0 }}
|
||||
>
|
||||
<Select
|
||||
allowClear
|
||||
size="default"
|
||||
style={{ width: '100%' }}
|
||||
placeholder="无"
|
||||
// placeholder="无"
|
||||
value={metricObj.aggrFunc}
|
||||
onChange={(val: string) => this.handleAggregateChange(currentMetric, val)}
|
||||
>
|
||||
<Option value="sum">求和</Option>
|
||||
<Option value="avg">均值</Option>
|
||||
<Option value="max">最大值</Option>
|
||||
<Option value="min">最小值</Option>
|
||||
<Option value="sum"><FormattedMessage id="graph.config.aggr.sum" /></Option>
|
||||
<Option value="avg"><FormattedMessage id="graph.config.aggr.avg" /></Option>
|
||||
<Option value="max"><FormattedMessage id="graph.config.aggr.max" /></Option>
|
||||
<Option value="min"><FormattedMessage id="graph.config.aggr.min" /></Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Col>
|
||||
|
@ -631,7 +632,7 @@ export default class GraphConfigForm extends Component<Props, State> {
|
|||
<FormItem
|
||||
labelCol={{ span: 5 }}
|
||||
wrapperCol={{ span: 19 }}
|
||||
label="聚合维度"
|
||||
label={<FormattedMessage id="graph.config.aggr.group" />}
|
||||
style={{ marginBottom: 0 }}
|
||||
>
|
||||
<Select
|
||||
|
@ -639,7 +640,7 @@ export default class GraphConfigForm extends Component<Props, State> {
|
|||
size="default"
|
||||
style={{ width: '100%' }}
|
||||
disabled={!metricObj.aggrFunc}
|
||||
placeholder="无"
|
||||
// placeholder="无"
|
||||
value={metricObj.aggrGroup || []}
|
||||
onChange={(val: string[]) => this.handleAggregateDimensionChange(currentMetric, val)}
|
||||
>
|
||||
|
@ -650,7 +651,7 @@ export default class GraphConfigForm extends Component<Props, State> {
|
|||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
<FormItem
|
||||
{/* <FormItem
|
||||
labelCol={{ span: 3 }}
|
||||
wrapperCol={{ span: 21 }}
|
||||
label="采样函数"
|
||||
|
@ -668,7 +669,7 @@ export default class GraphConfigForm extends Component<Props, State> {
|
|||
<Option value="MAX">最大值</Option>
|
||||
<Option value="MIN">最小值</Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</FormItem> */}
|
||||
<Tagkv
|
||||
type="modal"
|
||||
data={withoutEndpointTagkv}
|
||||
|
@ -680,7 +681,7 @@ export default class GraphConfigForm extends Component<Props, State> {
|
|||
readOnly
|
||||
value={_.join(_.slice(selectedTagv, 0, 40), ', ')}
|
||||
size="default"
|
||||
placeholder="若无此tag,请留空"
|
||||
// placeholder="若无此tag,请留空"
|
||||
onClick={() => {
|
||||
show(tagk);
|
||||
}}
|
||||
|
@ -706,12 +707,12 @@ export default class GraphConfigForm extends Component<Props, State> {
|
|||
<FormItem
|
||||
labelCol={{ span: 3 }}
|
||||
wrapperCol={{ span: 21 }}
|
||||
label="曲线"
|
||||
label={<FormattedMessage id="graph.config.series" />}
|
||||
style={{ marginBottom: 5 }}
|
||||
>
|
||||
<span style={{ color: '#ff7f00', paddingRight: 5 }}>
|
||||
{_.get(metricObj.counterList, 'length')}
|
||||
条
|
||||
<FormattedMessage id="graph.config.series.unit" />
|
||||
</span>
|
||||
<a onClick={() => {
|
||||
this.setState({ counterListVisible: !this.state.counterListVisible });
|
||||
|
@ -752,7 +753,7 @@ export default class GraphConfigForm extends Component<Props, State> {
|
|||
<FormItem
|
||||
labelCol={{ span: 3 }}
|
||||
wrapperCol={{ span: 21 }}
|
||||
label="分类"
|
||||
label={<FormattedMessage id="graph.config.cate" />}
|
||||
style={{ marginBottom: 5 }}
|
||||
required
|
||||
>
|
||||
|
@ -772,24 +773,24 @@ export default class GraphConfigForm extends Component<Props, State> {
|
|||
<FormItem
|
||||
labelCol={{ span: 3 }}
|
||||
wrapperCol={{ span: 21 }}
|
||||
label="标题"
|
||||
label={<FormattedMessage id="graph.config.graph.title" />}
|
||||
style={{ marginBottom: 5 }}
|
||||
>
|
||||
<Input
|
||||
style={{ width: '100%' }}
|
||||
value={graphConfig.title}
|
||||
onChange={this.handleTitleChange}
|
||||
placeholder="如果留空将会用指标名称做为标题"
|
||||
placeholder="The metric name as the default title"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
labelCol={{ span: 3 }}
|
||||
wrapperCol={{ span: 21 }}
|
||||
label="时间"
|
||||
label={<FormattedMessage id="graph.config.time" />}
|
||||
style={{ marginTop: 5, marginBottom: 0 }}
|
||||
required
|
||||
>
|
||||
<Select placeholder="时间选择" size="default" style={
|
||||
<Select size="default" style={
|
||||
timeVal === 'custom' ?
|
||||
{
|
||||
width: 198,
|
||||
|
@ -802,7 +803,7 @@ export default class GraphConfigForm extends Component<Props, State> {
|
|||
onChange={this.handleTimeOptionChange}
|
||||
>
|
||||
{
|
||||
_.map(config.time, o => <Option key={o.value} value={o.value}>{o.label}</Option>)
|
||||
_.map(config.time, o => <Option key={o.value} value={o.value}><FormattedMessage id={o.label} /></Option>)
|
||||
}
|
||||
</Select>
|
||||
{
|
||||
|
@ -838,7 +839,7 @@ export default class GraphConfigForm extends Component<Props, State> {
|
|||
<FormItem
|
||||
labelCol={{ span: 3 }}
|
||||
wrapperCol={{ span: 21 }}
|
||||
label="阈值"
|
||||
label={<FormattedMessage id="graph.config.threshold" />}
|
||||
style={{ marginBottom: 5 }}
|
||||
>
|
||||
<InputNumber
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import update from 'react-addons-update';
|
||||
import _ from 'lodash';
|
||||
import moment from 'moment';
|
||||
|
@ -188,19 +189,19 @@ export default class GraphConfigInner extends Component<Props> {
|
|||
<div className="graph-config-inner">
|
||||
<div className="graph-config-inner-item">
|
||||
<Button size="small" type="ghost" onClick={this.refresh}>
|
||||
刷新
|
||||
<FormattedMessage id="graph.refresh" />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="graph-config-inner-item">
|
||||
<Select
|
||||
size="small"
|
||||
style={{ width: 70 }}
|
||||
value={timeLabel}
|
||||
value={<FormattedMessage id={timeLabel} />}
|
||||
onChange={this.timeOptionChange}
|
||||
>
|
||||
{
|
||||
_.map(config.time, (o) => {
|
||||
return <Option key={o.value} value={o.value}>{o.label}</Option>;
|
||||
return <Option key={o.value} value={o.value}><FormattedMessage id={o.label} /></Option>;
|
||||
})
|
||||
}
|
||||
</Select>
|
||||
|
@ -241,7 +242,7 @@ export default class GraphConfigInner extends Component<Props> {
|
|||
}
|
||||
</div>
|
||||
<div className="graph-config-inner-item">
|
||||
聚合:
|
||||
<FormattedMessage id="graph.config.aggr" />:
|
||||
<Select
|
||||
allowClear
|
||||
size="small"
|
||||
|
@ -250,17 +251,17 @@ export default class GraphConfigInner extends Component<Props> {
|
|||
value={_.get(data.metrics, '[0].aggrFunc')}
|
||||
onChange={this.handleAggrFuncChange}
|
||||
>
|
||||
<Option value="sum">求和</Option>
|
||||
<Option value="avg">均值</Option>
|
||||
<Option value="max">最大值</Option>
|
||||
<Option value="min">最小值</Option>
|
||||
<Option value="sum"><FormattedMessage id="graph.config.aggr.sum" /></Option>
|
||||
<Option value="avg"><FormattedMessage id="graph.config.aggr.avg" /></Option>
|
||||
<Option value="max"><FormattedMessage id="graph.config.aggr.max" /></Option>
|
||||
<Option value="min"><FormattedMessage id="graph.config.aggr.min" /></Option>
|
||||
</Select>
|
||||
</div>
|
||||
{
|
||||
_.get(data.metrics, '[0].aggrFunc') ?
|
||||
<div className="graph-config-inner-item">
|
||||
<Tooltip title="按照某个 tag 聚合出多条曲线">
|
||||
<span>聚合维度:</span>
|
||||
<span><FormattedMessage id="graph.config.aggr.group" />:</span>
|
||||
</Tooltip>
|
||||
<Select
|
||||
mode="multiple"
|
||||
|
@ -276,7 +277,6 @@ export default class GraphConfigInner extends Component<Props> {
|
|||
}],
|
||||
});
|
||||
}}
|
||||
placeholder="无"
|
||||
>
|
||||
{
|
||||
_.map(aggrGroupOptions, o => <Option key={o.value} value={o.value}>{o.label}</Option>)
|
||||
|
@ -284,7 +284,7 @@ export default class GraphConfigInner extends Component<Props> {
|
|||
</Select>
|
||||
</div> : null
|
||||
}
|
||||
<div className="graph-config-inner-item">
|
||||
{/* <div className="graph-config-inner-item">
|
||||
采样函数:
|
||||
<Select
|
||||
allowClear
|
||||
|
@ -298,7 +298,7 @@ export default class GraphConfigInner extends Component<Props> {
|
|||
<Option value="MAX">最大值</Option>
|
||||
<Option value="MIN">最小值</Option>
|
||||
</Select>
|
||||
</div>
|
||||
</div> */}
|
||||
<div className="graph-config-inner-item">
|
||||
<Checkbox checked={!!data.legend} onChange={this.legendChange}>
|
||||
Legend
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import update from 'react-addons-update';
|
||||
import _ from 'lodash';
|
||||
import { Input, Button, Modal, Popover, Switch } from 'antd';
|
||||
|
@ -185,12 +186,12 @@ export default class Tagkv extends Component<Props, State> {
|
|||
/>
|
||||
<div style={{ marginTop: 10, textAlign: 'center' }}>
|
||||
<Button.Group>
|
||||
<Button onClick={() => this.hide(tagk)}>取消</Button>
|
||||
<Button onClick={() => this.hide(tagk)}>Cancel</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => this.submit(tagk)}
|
||||
>
|
||||
确认
|
||||
Ok
|
||||
</Button>
|
||||
</Button.Group>
|
||||
</div>
|
||||
|
@ -198,14 +199,14 @@ export default class Tagkv extends Component<Props, State> {
|
|||
{
|
||||
dynamicSwitch ?
|
||||
<span>
|
||||
<span>动态值: </span>
|
||||
<a onClick={() => this.dynamicSelect(tagk, '=all')}>全选</a>
|
||||
<span><FormattedMessage id="select.dynamic" />: </span>
|
||||
<a onClick={() => this.dynamicSelect(tagk, '=all')}><FormattedMessage id="select.all" /></a>
|
||||
<span className="ant-divider" />
|
||||
<Popover
|
||||
trigger="click"
|
||||
content={
|
||||
<div style={{ width: 200 }}>
|
||||
<Input placeholder="请输入关键词,Enter键提交" onKeyDown={
|
||||
<Input placeholder="Press enter to submit" onKeyDown={
|
||||
(e: any) => {
|
||||
if (e.keyCode === 13) {
|
||||
this.dynamicSelect(tagk, '=+', e.target.value);
|
||||
|
@ -213,10 +214,9 @@ export default class Tagkv extends Component<Props, State> {
|
|||
}} />
|
||||
</div>
|
||||
}
|
||||
title="包含"
|
||||
getTooltipContainer={() => this.refs[`${tagk}dynamic`]}
|
||||
>
|
||||
<a>包含</a>
|
||||
<a><FormattedMessage id="select.include" /></a>
|
||||
</Popover>
|
||||
<span className="ant-divider" />
|
||||
<Popover
|
||||
|
@ -232,14 +232,13 @@ export default class Tagkv extends Component<Props, State> {
|
|||
|
||||
</div>
|
||||
}
|
||||
title="排除"
|
||||
getTooltipContainer={() => this.refs[`${tagk}dynamic`]}
|
||||
>
|
||||
<a>排除</a>
|
||||
<a><FormattedMessage id="select.exclude" /></a>
|
||||
</Popover>
|
||||
</span> :
|
||||
<div>
|
||||
动态值 <Switch onChange={this.dynamicSwitchChange} size="small" />
|
||||
<FormattedMessage id="select.dynamic" /> <Switch onChange={this.dynamicSwitchChange} size="small" />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Modal, Button, message } from 'antd';
|
||||
import _ from 'lodash';
|
||||
|
@ -113,7 +114,7 @@ export default class GraphConfig extends Component {
|
|||
<Modal
|
||||
key={key}
|
||||
width={750}
|
||||
title={title}
|
||||
title={<FormattedMessage id="graph.config.title" />}
|
||||
destroyOnClose
|
||||
visible={visible}
|
||||
maskClosable={false}
|
||||
|
|
|
@ -207,7 +207,7 @@ export const time: { [index: string]: string }[] = [
|
|||
label: '30天',
|
||||
value: '2592000000',
|
||||
}, {
|
||||
label: '其它 ',
|
||||
label: '其它',
|
||||
value: 'custom',
|
||||
},
|
||||
];
|
||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import _ from 'lodash';
|
||||
|
||||
export default function CreateIncludeNsTree(WrappedComponent: React.ComponentType, opts?: any) {
|
||||
export default function CreateIncludeNsTree(WrappedComponent: any, opts?: any) {
|
||||
return class HOC extends React.Component {
|
||||
static contextTypes = {
|
||||
nsTreeVisibleChange: PropTypes.func,
|
||||
|
|
|
@ -2,11 +2,12 @@ import React, { Component } from 'react';
|
|||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link, withRouter } from 'react-router-dom';
|
||||
import { Layout, Dropdown, Menu, Icon } from 'antd';
|
||||
import { Layout, Dropdown, Menu, Icon, Button } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import PubSub from 'pubsub-js';
|
||||
import _ from 'lodash';
|
||||
import queryString from 'query-string';
|
||||
import { WrappedComponentProps, injectIntl } from 'react-intl';
|
||||
import { auth } from '@cpts/Auth';
|
||||
import { MenuConfItem, TreeNode } from '@interface';
|
||||
import request from '@common/request';
|
||||
|
@ -22,6 +23,8 @@ interface Props {
|
|||
appName: string,
|
||||
menuConf: MenuConfItem[],
|
||||
children: React.ReactNode,
|
||||
language: string,
|
||||
onLanguageChange: (language: string) => void,
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
@ -38,7 +41,7 @@ interface State {
|
|||
|
||||
const { Header, Content, Sider } = Layout;
|
||||
|
||||
class NILayout extends Component<Props & RouteComponentProps, State> {
|
||||
class NILayout extends Component<Props & RouteComponentProps & WrappedComponentProps, State> {
|
||||
static childContextTypes = {
|
||||
nsTreeVisibleChange: PropTypes.func.isRequired,
|
||||
getNodes: PropTypes.func.isRequired,
|
||||
|
@ -48,9 +51,10 @@ class NILayout extends Component<Props & RouteComponentProps, State> {
|
|||
deleteSelectedNode: PropTypes.func.isRequired,
|
||||
reloadNsTree: PropTypes.func.isRequired,
|
||||
habitsId: PropTypes.string.isRequired,
|
||||
intl: PropTypes.any.isRequired,
|
||||
};
|
||||
|
||||
constructor(props: Props & RouteComponentProps) {
|
||||
constructor(props: Props & RouteComponentProps & WrappedComponentProps) {
|
||||
super(props);
|
||||
let selectedNode;
|
||||
try {
|
||||
|
@ -177,6 +181,7 @@ class NILayout extends Component<Props & RouteComponentProps, State> {
|
|||
this.fetchTreeData();
|
||||
},
|
||||
habitsId: this.props.habitsId,
|
||||
intl: this.props.intl,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -201,7 +206,7 @@ class NILayout extends Component<Props & RouteComponentProps, State> {
|
|||
});
|
||||
|
||||
return (
|
||||
<Layout className={layoutCls} style={{ height: '100%' }}>
|
||||
<Layout className={layoutCls}>
|
||||
<Sider
|
||||
className={`${prefixCls}-sider-nstree`}
|
||||
width={nsTreeVisible ? 200 : 0}
|
||||
|
@ -233,7 +238,7 @@ class NILayout extends Component<Props & RouteComponentProps, State> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { menuConf } = this.props;
|
||||
const { menuConf, language, onLanguageChange } = this.props;
|
||||
const { checkAuthenticateLoading, collapsed, selectedNode, nsTreeVisible } = this.state;
|
||||
const prefixCls = `${appname}-layout`;
|
||||
const { dispname, isroot } = auth.getSelftProfile();
|
||||
|
@ -296,6 +301,17 @@ class NILayout extends Component<Props & RouteComponentProps, State> {
|
|||
{nsTreeVisible ? _.get(selectedNode, 'path') : null}
|
||||
</div>
|
||||
<div className={`${prefixCls}-headRight`}>
|
||||
<Button
|
||||
style={{ margin: '0 20px' }}
|
||||
size="small"
|
||||
onClick={() => {
|
||||
const newLanguage = language === 'zh' ? 'en' : 'zh';
|
||||
onLanguageChange(newLanguage);
|
||||
}}
|
||||
>
|
||||
{language === 'zh' ? 'English' : ''}
|
||||
{language === 'en' ? '中文' : ''}
|
||||
</Button>
|
||||
<Dropdown placement="bottomRight" overlay={
|
||||
<Menu style={{ width: 110 }}>
|
||||
<Menu.Item>
|
||||
|
@ -326,4 +342,4 @@ class NILayout extends Component<Props & RouteComponentProps, State> {
|
|||
}
|
||||
}
|
||||
|
||||
export default withRouter(NILayout);
|
||||
export default injectIntl(withRouter(NILayout));
|
||||
|
|
|
@ -1,7 +1,31 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { ConfigProvider } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import antdZhCN from 'antd/lib/locale/zh_CN';
|
||||
import antdEnUS from 'antd/lib/locale/en_US';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import intlZhCN from '../../locales/zh';
|
||||
import intlEnUS from '../../locales/en';
|
||||
|
||||
export default function ModalControlWrap(Component: typeof React.Component) {
|
||||
interface LocaleMap {
|
||||
[index: string]: any,
|
||||
}
|
||||
|
||||
const localeMap: LocaleMap = {
|
||||
zh: {
|
||||
antd: antdZhCN,
|
||||
intl: 'zh',
|
||||
intlMessages: intlZhCN,
|
||||
},
|
||||
en: {
|
||||
antd: antdEnUS,
|
||||
intl: 'en',
|
||||
intlMessages: intlEnUS,
|
||||
},
|
||||
};
|
||||
|
||||
export default function ModalControlWrap(Component: any) {
|
||||
return function ModalControl(config: any) {
|
||||
const div = document.createElement('div');
|
||||
document.body.appendChild(div);
|
||||
|
@ -14,7 +38,17 @@ export default function ModalControlWrap(Component: typeof React.Component) {
|
|||
}
|
||||
|
||||
function render(props: any) {
|
||||
ReactDOM.render(<Component {...props} />, div);
|
||||
ReactDOM.render(
|
||||
<IntlProvider
|
||||
locale={_.get(localeMap[config.language], 'intl', 'zh')}
|
||||
messages={_.get(localeMap[config.language], 'intlMessages', intlZhCN)}
|
||||
>
|
||||
<ConfigProvider locale={_.get(localeMap[config.language], 'antd', antdZhCN)}>
|
||||
<Component {...props} />
|
||||
</ConfigProvider>
|
||||
</IntlProvider>,
|
||||
div
|
||||
);
|
||||
}
|
||||
|
||||
render({ ...config, visible: true, destroy });
|
||||
|
|
|
@ -21,6 +21,7 @@ import React, { Component } from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import { Row, Col, Input, Button, Pagination, Checkbox, Popover, Tag, message } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import './style.less';
|
||||
|
||||
const TextArea = Input.TextArea ? Input.TextArea : Input;
|
||||
|
@ -134,7 +135,7 @@ class Multipicker extends Component {
|
|||
|
||||
if (data.length > 500) {
|
||||
selectedList = selectedList.splice(0, 500);
|
||||
message.warning('最多只能全选500个');
|
||||
message.warning('Can only select a maximum of 500');
|
||||
}
|
||||
if (searchVal) {
|
||||
selectedList = _.uniq(selected.concat(this.filterData()));
|
||||
|
@ -249,12 +250,12 @@ class Multipicker extends Component {
|
|||
<div className="multipicker-selected-list-box">
|
||||
<Row>
|
||||
<Col span={14}>
|
||||
<strong>已选({selected.length}):</strong>
|
||||
<strong><FormattedMessage id="select.selected" />({selected.length}):</strong>
|
||||
<a
|
||||
className="remove-all"
|
||||
onClick={this.removeAll}
|
||||
>
|
||||
清除已选项
|
||||
<FormattedMessage id="select.selected.clear" />
|
||||
</a>
|
||||
{
|
||||
manualEntry &&
|
||||
|
@ -278,7 +279,7 @@ class Multipicker extends Component {
|
|||
}}
|
||||
/>
|
||||
<div style={{ marginTop: 5 }}>
|
||||
<Button size="small" onClick={this.handleManualEntry}>确定</Button>
|
||||
<Button size="small" onClick={this.handleManualEntry}>Ok</Button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
@ -290,7 +291,7 @@ class Multipicker extends Component {
|
|||
this.setState({ manualVisible: !this.state.manualVisible });
|
||||
}}
|
||||
>
|
||||
手动输入
|
||||
<FormattedMessage id="select.manual.input" />
|
||||
</a>
|
||||
</Popover>
|
||||
}
|
||||
|
@ -301,15 +302,15 @@ class Multipicker extends Component {
|
|||
<div className="multipicker-option-list-box">
|
||||
<Row>
|
||||
<Col span={16}>
|
||||
<strong>选项({data.length}):</strong>
|
||||
<strong><FormattedMessage id="select.total" />({data.length}):</strong>
|
||||
<a
|
||||
className="select-all-currentPage"
|
||||
onClick={this.currentPageSelectAll}
|
||||
style={{ paddingRight: 10 }}
|
||||
>
|
||||
全选当前页
|
||||
<FormattedMessage id="select.current.page" />
|
||||
</a>
|
||||
<a className="select-all" onClick={this.selectAll}>全选</a>
|
||||
<a className="select-all" onClick={this.selectAll}><FormattedMessage id="select.all" /></a>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<div className="multipicker-search">
|
||||
|
@ -317,7 +318,7 @@ class Multipicker extends Component {
|
|||
size="small"
|
||||
type="text"
|
||||
className="keyword"
|
||||
placeholder="搜索,支持正则"
|
||||
placeholder="support regular"
|
||||
onChange={this.search} />
|
||||
</div>
|
||||
</Col>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React, { Component, Fragment } from 'react';
|
||||
import { Form, Input, Switch, Icon } from 'antd';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
import { injectIntl, WrappedComponentProps } from 'react-intl';
|
||||
import { UserProfile } from '@interface';
|
||||
|
||||
interface Props {
|
||||
|
@ -11,8 +12,8 @@ interface Props {
|
|||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
class ProfileForm extends Component<Props & FormProps> {
|
||||
static defaultProps = {
|
||||
class ProfileForm extends Component<Props & FormProps & WrappedComponentProps> {
|
||||
static defaultProps: any = {
|
||||
type: 'post',
|
||||
isrootVsible: false,
|
||||
initialValue: {},
|
||||
|
@ -33,47 +34,48 @@ class ProfileForm extends Component<Props & FormProps> {
|
|||
render() {
|
||||
const { type, isrootVsible, initialValue } = this.props;
|
||||
const { getFieldDecorator } = this.props.form!;
|
||||
const { formatMessage } = this.props.intl;
|
||||
return (
|
||||
<Form layout="vertical">
|
||||
{
|
||||
type === 'post' || type === 'register' ?
|
||||
<Fragment>
|
||||
<FormItem label={this.renderLabel('用户名')} required>
|
||||
<FormItem label={this.renderLabel(formatMessage({ id: 'user.username' }))} required>
|
||||
{getFieldDecorator('username', {
|
||||
rules: [{ required: true, message: '请输入用户名!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<Input placeholder="用户名" />,
|
||||
<Input placeholder={formatMessage({ id: 'user.username' })} />,
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem label={this.renderLabel('密码')} required>
|
||||
<FormItem label={this.renderLabel(formatMessage({ id: 'user.password' }))} required>
|
||||
{getFieldDecorator('password', {
|
||||
rules: [{ required: true, message: '请输入密码!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<Input type="password" placeholder="密码" />,
|
||||
<Input type="password" placeholder={formatMessage({ id: 'user.password' })} />,
|
||||
)}
|
||||
</FormItem>
|
||||
</Fragment> : null
|
||||
}
|
||||
<FormItem label={this.renderLabel('显示名')} required>
|
||||
<FormItem label={this.renderLabel(formatMessage({ id: 'user.dispname' }))} required>
|
||||
{getFieldDecorator('dispname', {
|
||||
initialValue: initialValue.dispname,
|
||||
rules: [{ required: true, message: '请输入显示名!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<Input placeholder="显示名" />,
|
||||
<Input placeholder={formatMessage({ id: 'user.dispname' })} />,
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem label={this.renderLabel('手机')}>
|
||||
<FormItem label={this.renderLabel(formatMessage({ id: 'user.phone' }))}>
|
||||
{getFieldDecorator('phone', {
|
||||
initialValue: initialValue.phone,
|
||||
})(
|
||||
<Input placeholder="手机" style={{ width: '100%' }} />,
|
||||
<Input placeholder={formatMessage({ id: 'user.phone' })} style={{ width: '100%' }} />,
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem label={this.renderLabel('邮箱')}>
|
||||
<FormItem label={this.renderLabel(formatMessage({ id: 'user.email' }))}>
|
||||
{getFieldDecorator('email', {
|
||||
initialValue: initialValue.email,
|
||||
})(
|
||||
<Input placeholder="邮箱" />,
|
||||
<Input placeholder={formatMessage({ id: 'user.email' })} />,
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem label={this.renderLabel('im')}>
|
||||
|
@ -85,7 +87,7 @@ class ProfileForm extends Component<Props & FormProps> {
|
|||
</FormItem>
|
||||
{
|
||||
isrootVsible ?
|
||||
<FormItem label={this.renderLabel('是否超管')}>
|
||||
<FormItem label={this.renderLabel(formatMessage({ id: 'user.isroot' }))}>
|
||||
{getFieldDecorator('is_root', {
|
||||
valuePropName: 'checked',
|
||||
initialValue: initialValue.is_root === 1,
|
||||
|
@ -102,4 +104,4 @@ class ProfileForm extends Component<Props & FormProps> {
|
|||
}
|
||||
}
|
||||
|
||||
export default Form.create()(ProfileForm as any);
|
||||
export default Form.create()(injectIntl(ProfileForm));
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
import * as React from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { injectIntl } from 'react-intl';
|
||||
|
||||
export const IntlContext = React.createContext({} as any);
|
||||
|
||||
// turn the old context into the new context
|
||||
export const InjectIntlContext = injectIntl(({ intl, children }) => (
|
||||
<IntlContext.Provider value={intl}>
|
||||
{ children }
|
||||
</IntlContext.Provider>
|
||||
));
|
||||
|
||||
export const getIntl = () => useContext(IntlContext);
|
||||
|
||||
// the format message hook
|
||||
const useFormatMessage = () => {
|
||||
const intl = useContext(IntlContext);
|
||||
return intl.formatMessage;
|
||||
};
|
||||
|
||||
export default useFormatMessage;
|
|
@ -0,0 +1,433 @@
|
|||
export default {
|
||||
'login': 'Login',
|
||||
'logout': 'Logout',
|
||||
'register': 'Register',
|
||||
'login.title': 'Login',
|
||||
'login.ldap': 'Use LDAP',
|
||||
|
||||
'form.save': 'Save',
|
||||
'form.create': 'Create',
|
||||
'form.submit': 'Submit',
|
||||
'form.delete': 'Delete',
|
||||
'form.login': 'Login',
|
||||
'form.goback': 'Go back',
|
||||
|
||||
'msg.submit.success': 'Submit successfully',
|
||||
'msg.modify.success': 'Modify Successfully',
|
||||
'msg.create.success': 'Create successfully',
|
||||
'msg.add.success': 'Add successfully',
|
||||
'msg.delete.success': 'Delete successfully',
|
||||
'msg.clone.success': 'Clone successfully',
|
||||
'msg.sort.success': 'Sort successfully',
|
||||
|
||||
'please.select.node': 'Please select the node first',
|
||||
|
||||
'table.nodata': 'No data',
|
||||
'table.create': 'Create',
|
||||
'table.operations': 'Operations',
|
||||
'table.batch.operations': 'Batch Operations',
|
||||
'table.detail': 'Detail',
|
||||
'table.modify': 'Modify',
|
||||
'table.delete': 'Delete',
|
||||
'table.delete.batch': 'Batch delete',
|
||||
'table.clone': 'Clone',
|
||||
'table.delete.sure': 'Are you sure to delete it?',
|
||||
'table.delete.there.sure': 'Are you sure to delete these?',
|
||||
'table.ident': 'Ident',
|
||||
'table.name': 'Name',
|
||||
'table.cate': 'Cate',
|
||||
'table.creator': 'Creator',
|
||||
'table.lastupdated': 'Last updated',
|
||||
'table.note': 'Note',
|
||||
|
||||
'user.create': 'Create',
|
||||
'user.modify': 'Modify',
|
||||
'user.username': 'Username',
|
||||
'user.dispname': 'Dispname',
|
||||
'user.password': 'Password',
|
||||
'user.email': 'Email',
|
||||
'user.phone': 'Phone',
|
||||
'user.reset.password': 'Reset password',
|
||||
'user.reset.password.success': 'Reset password successfully',
|
||||
'user.invite': 'Invite',
|
||||
'user.invite.tips': 'Click to generate a link to invite users',
|
||||
'user.isroot': 'is root',
|
||||
'password.old': 'Old Password',
|
||||
'password.new': 'New Password',
|
||||
'token.reset': 'Reset',
|
||||
'token.reset.success': 'Reset successfully',
|
||||
'invite.user.copy.success': 'Copy succeeded',
|
||||
'invite.user.copy.faile': 'Failed, please copy manually',
|
||||
|
||||
'tree.select.node': 'Please choose the tree node',
|
||||
'tree.search': 'Search (space division)',
|
||||
'tree.node': 'Node',
|
||||
'node.copy.path': 'Copy node path',
|
||||
'node.copy.path.success': 'Copy succeeded',
|
||||
'node.copy.path.error': 'Copy failed',
|
||||
'node.create.tenant': 'Add tenant node',
|
||||
'node.create': 'Add node',
|
||||
'node.modify': 'Modify node',
|
||||
'node.delete': 'Delete node',
|
||||
'node.name': 'Name',
|
||||
'node.isLeaf': 'Is leaf',
|
||||
'node.cate': 'Category',
|
||||
'node.color': 'Color',
|
||||
'node.note': 'Note',
|
||||
'node.cate.create': 'Create node category',
|
||||
'node.cate.modify': 'Modify node category',
|
||||
'node.display.path': 'Display node',
|
||||
'node.rename': 'Rename node',
|
||||
'node.rename.newname': 'node name',
|
||||
'node.rename.success': 'Rename successfully',
|
||||
'node.child.create': 'Create a new node',
|
||||
'node.child.create.success': 'Create successfully',
|
||||
'node.child.newname': 'node name',
|
||||
'node.delete.success': 'Delete successfully',
|
||||
'node.leaf.cannot.create': 'Leaf node cannot continue to create child node',
|
||||
'根节点不能删除': 'Root node cannot delete',
|
||||
|
||||
'select.all': 'all',
|
||||
'select.include': 'include',
|
||||
'select.exclude': 'exclude',
|
||||
'select.dynamic': 'dynamic value',
|
||||
'select.selected': 'selected',
|
||||
'select.selected.clear': 'clear',
|
||||
'select.manual.input': 'manual',
|
||||
'select.total': 'total',
|
||||
'select.current.page': 'currentPage',
|
||||
|
||||
'1小时': '1hour',
|
||||
'2小时': '2hours',
|
||||
'6小时': '6hours',
|
||||
'12小时': '12hours',
|
||||
'1天': '1day',
|
||||
'2天': '2days',
|
||||
'7天': '7days',
|
||||
'30天': '30days',
|
||||
'其它': 'other',
|
||||
|
||||
'menu.endpoints': 'Endpoints',
|
||||
'menu.endpoints.all': 'All endpoints',
|
||||
'menu.endpoints.node': 'Endpoints of node',
|
||||
'menu.endpoints.node.manage': 'Node manage',
|
||||
'menu.monitor': 'Monitor',
|
||||
'menu.monitor.dashboard': 'Dashboard',
|
||||
'menu.monitor.screen': 'Screens',
|
||||
'menu.monitor.strategy': 'Alarm strategies',
|
||||
'menu.monitor.history': 'Alarm events',
|
||||
'menu.monitor.silence': 'Alarm silences',
|
||||
'menu.monitor.collect': 'Collections',
|
||||
'menu.users': 'Users',
|
||||
'menu.users.users': 'Users',
|
||||
'menu.users.teams': 'Teams',
|
||||
|
||||
'endpoints.ident': 'Ident',
|
||||
'endpoints.alias': 'Alias',
|
||||
'endpoints.nodes': 'Nodes',
|
||||
'endpoints.batch.filter': 'Batch filter',
|
||||
'endpoints.batch.filter.key': 'Key',
|
||||
'endpoints.batch.filter.value': 'Value',
|
||||
'endpoints.export.excel': 'Export excel',
|
||||
'endpoints.import': 'Import endpoints',
|
||||
'endpoints.export': 'Export endpoints',
|
||||
'endpoints.delete': 'Delete Endpoints',
|
||||
'endpoints.bind': 'Bind Endpoints',
|
||||
'endpoints.unbind': 'Unbind Endpoints',
|
||||
'endpoints.copy.selected': 'Copy the selected',
|
||||
'endpoints.copy.currentPage': 'Copy the current page',
|
||||
'endpoints.copy.all': 'Copy all',
|
||||
'endpoints.copy.empty': 'Copy the object is empty',
|
||||
'endpoints.copy.error': 'Failed to copy, please manually copy',
|
||||
'endpoints.import.batch.help': 'Each one is an ident::alias',
|
||||
'endpoints.modify.alias': 'Modify alias',
|
||||
'endpoints.bind.node': 'Node',
|
||||
'endpoints.unbind.node': 'Node',
|
||||
'endpoints.delete.old.bind': 'Delete old Bind',
|
||||
|
||||
'team.ident': 'Ident',
|
||||
'team.name': 'Name',
|
||||
'team.admins': 'Admins',
|
||||
'team.members': 'Members',
|
||||
'team.mgmt': 'Management mode',
|
||||
'team.mgmt.admin': 'Admin',
|
||||
'team.mgmt.member': 'Member',
|
||||
|
||||
'周一': 'Mon.',
|
||||
'周二': 'Tue.',
|
||||
'周三': 'Wed.',
|
||||
'周四': 'Thu.',
|
||||
'周五': 'Fri.',
|
||||
'周六': 'Sat.',
|
||||
'周日': 'Sun.',
|
||||
|
||||
'clone.to.other.node': 'Clone to other node',
|
||||
'clone.to.other.node.success': 'Clone to node successfully!',
|
||||
'collect.log': 'Log',
|
||||
'collect.port': 'Port',
|
||||
'collect.proc': 'Proc',
|
||||
'collect.common.search': 'Search',
|
||||
'collect.common.name': 'Name',
|
||||
'collect.common.type': 'Type',
|
||||
'collect.common.creator': 'Creator',
|
||||
'collect.common.last_updated': 'Last updated',
|
||||
'collect.common.node': 'Node',
|
||||
'collect.common.step': 'Step',
|
||||
'collect.common.step.unit': 'seconds',
|
||||
'collect.common.note': 'Note',
|
||||
|
||||
'collect.log.msg.pattern.empty': 'Pattern is required',
|
||||
'collect.log.msg.log.empty': 'Log is required',
|
||||
'collect.log.msg.tag.maximum': 'Maximum of three',
|
||||
'collect.log.ns': 'NS',
|
||||
'collect.log.name': 'Name',
|
||||
'collect.log.func': 'Calc func',
|
||||
'collect.log.func.cnt': 'Count',
|
||||
'collect.log.func.avg': 'Average',
|
||||
'collect.log.func.sum': 'Sum',
|
||||
'collect.log.func.max': 'Max',
|
||||
'collect.log.func.min': 'Min',
|
||||
'collect.log.path': 'Path',
|
||||
'collect.log.path.dynamic': 'dynamic log',
|
||||
'collect.log.path.dynamic.tip.1': 'The time format at the end of the log, eg.',
|
||||
'collect.log.path.dynamic.tip.2': "/ cannot be included in $'{}'",
|
||||
'collect.log.timeFmt': 'Time format',
|
||||
'collect.log.timeFmt.help.1': 'The time format must be the same as the format in the log.',
|
||||
'collect.log.timeFmt.help.2': 'Only the first match result is used.',
|
||||
'collect.log.step': 'Step',
|
||||
'collect.log.step.unit': 'seconds',
|
||||
'collect.log.pattern': 'Pattern',
|
||||
'collect.log.pattern.tip.1': 'Please Enter regular expression',
|
||||
'collect.log.pattern.tip.3': 'eg. cost=(\\d+) , Take \\d+ (the default is the first bracket)',
|
||||
'collect.log.tagval.placeholder': 'Not a curve value! Must be enumerable!',
|
||||
'collect.log.tags.add': 'Add tag',
|
||||
'collect.log.tagName.help.title': 'tagName description',
|
||||
'collect.log.tagName.help.1': 'Not allowed to use host, trigger, include',
|
||||
'collect.log.tagName.help.2': 'Not allowed to include = , : @',
|
||||
'collect.log.tagValue.help.title': 'tagValue description',
|
||||
'collect.log.tagValue.help.1': 'Must include parentheses. and the content is used as the value of tagValue, and must be enumerable.',
|
||||
'collect.log.tagValue.help.2': 'Not allowed to include = , : @',
|
||||
'collect.log.check': 'Check',
|
||||
'collect.log.check.btn': 'Check',
|
||||
'collect.log.check.btn2': 'Is there a problem with my configuration?',
|
||||
'collect.log.check.help': 'Enter a complete log to be monitored, including time.',
|
||||
'collect.log.check.help.tip.1': 'The correct: ',
|
||||
'collect.log.check.help.tip.2': 'Output regular, tag match result complete and sub-items, and time matching results',
|
||||
'collect.log.check.help.tip.3': 'The wrong: ',
|
||||
'collect.log.check.help.tip.4': 'Output error message',
|
||||
'collect.log.check.add.tip': 'Please check, When adding',
|
||||
'collect.log.note': 'Note',
|
||||
'collect.batch.import': 'Import',
|
||||
'collect.batch.export': 'Export',
|
||||
|
||||
'collect.port.title': 'Metric',
|
||||
'collect.port.name.placeholder': 'Description of the collection, such as web port',
|
||||
'collect.port.pattern.msg': 'Only english, numbers, -_.',
|
||||
'collect.port.port': 'Port',
|
||||
'collect.port.timeout': 'Timeout',
|
||||
'collect.port.timeout.unit': 'seconds',
|
||||
|
||||
'collect.proc.title': 'Metric',
|
||||
'collect.proc.name.placeholder': 'Description of the collection, such as nginx',
|
||||
'collect.proc.service.pattern.msg': 'Only english, numbers, -_.',
|
||||
'collect.proc.type': 'Type',
|
||||
'collect.proc.type.cmd': 'Command',
|
||||
'collect.proc.type.name': 'Process Name',
|
||||
'collect.proc.type.input.pattern.msg': 'Cannot contain Chinese',
|
||||
|
||||
'graph.subscribe': 'Subscribe',
|
||||
'graph.subscribe.node': 'Node',
|
||||
'graph.subscribe.screen': 'Screen',
|
||||
'graph.subscribe.tag': 'Tag',
|
||||
'graph.subscribe.success': 'Subscription successfully',
|
||||
'graph.share': 'Share',
|
||||
'graph.clear': 'Clear',
|
||||
'graph.view': 'View',
|
||||
'graph.save': 'Save',
|
||||
'graph.machine.list.title': 'Endpoints',
|
||||
'graph.machine.list.update': 'Update graphs',
|
||||
'graph.metric.list.title': 'Metrics',
|
||||
'graph.metric.list.search': 'Search',
|
||||
'graph.metric.list.all': 'All',
|
||||
'graph.refresh': 'Refresh',
|
||||
'graph.config.title': 'Setting',
|
||||
'graph.config.graph.title': 'title',
|
||||
'graph.config.node': 'node',
|
||||
'graph.config.metric': 'metric',
|
||||
'graph.config.aggr': 'aggr',
|
||||
'graph.config.aggr.sum': 'sum',
|
||||
'graph.config.aggr.avg': 'avg',
|
||||
'graph.config.aggr.max': 'max',
|
||||
'graph.config.aggr.min': 'min',
|
||||
'graph.config.aggr.group': 'groupBy',
|
||||
'graph.config.series': 'series',
|
||||
'graph.config.series.unit': 'pcs',
|
||||
'graph.config.cate': 'cate',
|
||||
'graph.config.time': 'time',
|
||||
'graph.config.threshold': 'threshold',
|
||||
'graph.config.link': 'link',
|
||||
'graph.config.link.help': 'custom link',
|
||||
'graph.config.chartType.targetValue': 'value',
|
||||
'graph.config.chartType.current': 'current',
|
||||
'graph.config.chartType.unit': 'unit',
|
||||
'graph.config.chartType.subType': 'type',
|
||||
'graph.config.subType.normal': 'value',
|
||||
'graph.config.subType.normal.tip': '(aggr required)',
|
||||
'graph.config.subType.solidGauge': 'solidGauge',
|
||||
'graph.config.subType.liquidFillGauge': 'liquidFillGauge',
|
||||
'graph.config.chartType.valueMap': 'mapType',
|
||||
'graph.config.chartType.mapConf': 'map',
|
||||
'graph.config.chartType.tableType': 'table',
|
||||
'graph.config.chartType.tableType.current': 'current',
|
||||
'graph.config.chartType.tableType.stats': 'stats',
|
||||
'graph.config.chartType.pieType': 'type',
|
||||
'graph.config.chartType.pieType.pie': 'Pie',
|
||||
'graph.config.chartType.pieType.donut': 'Donut',
|
||||
'graph.config.chartType.tableType.columnsKey': 'columns',
|
||||
|
||||
'event.tab.alert': 'Alarming',
|
||||
'event.tab.all': 'History',
|
||||
'event.msg.ignore.success': 'Successfully ignore',
|
||||
'event.msg.claim.success': 'Successfully claim',
|
||||
'event.msg.claim.all.success': 'Successfully claim all',
|
||||
'event.table.time': 'Time',
|
||||
'event.table.stra': 'Stra',
|
||||
'event.table.node': 'Node',
|
||||
'event.table.priority': 'Priority',
|
||||
'event.table.notify': 'Notify result',
|
||||
'event.table.ignore': 'Ignore',
|
||||
'event.table.ignore.sure': 'Are you sure to ignore this alarm?',
|
||||
'event.table.claim': 'Claim',
|
||||
'event.table.claim.sure': 'Are you sure to claim this alarm?',
|
||||
'event.table.shield': 'Shield',
|
||||
'event.table.assignees': 'Assignees',
|
||||
'event.table.status': 'Status',
|
||||
'event.table.status.alert': 'alert',
|
||||
'event.table.status.recovery': 'recovery',
|
||||
'event.table.claim.all': 'Claim all',
|
||||
'event.table.claim.all.sure': 'Are you sure to claim all unrecovered alarms?',
|
||||
'event.table.detail.title': 'Detail',
|
||||
'event.table.metric': 'Metric',
|
||||
'event.table.expression': 'Expression',
|
||||
'event.table.scene': 'Scene',
|
||||
'event.table.scene.time': 'Time',
|
||||
'event.table.scene.value': 'Value',
|
||||
|
||||
'screen.create': 'Add',
|
||||
'screen.tag.add': 'Add tag',
|
||||
'screen.tag.batch.modify': 'Batch modify',
|
||||
'screen.auto.refresh': 'Auto refresh',
|
||||
'screen.col': 'col',
|
||||
'screen.tag.graph.add': 'Add graph',
|
||||
'screen.tag.graph.add.graph': 'Graph',
|
||||
'screen.tag.graph.add.number': 'Number (aggr required)',
|
||||
'screen.tag.graph.add.table': 'Table',
|
||||
'screen.tag.graph.add.pie': 'Pie',
|
||||
'screen.tag.up': 'Up',
|
||||
'screen.tag.down': 'Down',
|
||||
'screen.tag.batch.modify.tag': 'Active tag',
|
||||
'screen.tag.batch.modify.target.node': 'Target node',
|
||||
'screen.tag.batch.modify.target.screen': 'Target screen',
|
||||
'screen.graph.extraMoreList.share': 'share',
|
||||
'screen.graph.extraMoreList.clone': 'clone',
|
||||
'screen.graph.extraMoreList.delete': 'delete',
|
||||
'screen.graph.extraMoreList.delete.sure': 'Are you sure to delete this chart?',
|
||||
|
||||
'silence.add': 'Add',
|
||||
'silence.metric': 'Metric',
|
||||
'silence.bindNode': 'Node',
|
||||
'silence.time': 'Time',
|
||||
'silence.cause': 'Cause',
|
||||
'silence.user': 'User',
|
||||
'silence.delete': 'Delete',
|
||||
'silence.form.metric': 'Metric',
|
||||
'silence.form.endpoints': 'Endpoints',
|
||||
'silence.form.tags': 'Tags',
|
||||
'silence.form.stime': 'Start time',
|
||||
'silence.form.etime': 'End time',
|
||||
'silence.cause.default': 'Quick shielding',
|
||||
|
||||
'stra.add': 'Add',
|
||||
'stra.batch.import.success': 'Batch import successfully',
|
||||
'stra.advanced': 'Advanced',
|
||||
'stra.seconds': 's',
|
||||
'stra.minutes': 'min',
|
||||
'stra.name': 'Name',
|
||||
'stra.priority': 'Priority',
|
||||
'stra.metric': 'Metric',
|
||||
'stra.notify': 'Notify',
|
||||
'stra.batch.modify.excludeNs': 'Modify excluded nodes',
|
||||
'stra.batch.modify.notify': 'Modify notify',
|
||||
'stra.batch.cloneTo.otherNode': 'Clone to other node',
|
||||
'stra.batch.delete': 'Delete',
|
||||
'stra.batch.import': 'Import',
|
||||
'stra.batch.export': 'Export',
|
||||
'stra.node': 'Node',
|
||||
'stra.node.exclude': 'Excluded nodes',
|
||||
'stra.priority.1': 'P1',
|
||||
'stra.priority.2': 'P2',
|
||||
'stra.priority.3': 'P3',
|
||||
'stra.priority.1.tip': 'P1: Phone, SMS, IM, Email',
|
||||
'stra.priority.2.tip': 'P2: SMS, IM, Email',
|
||||
'stra.priority.3.tip': 'P3: IM, Email',
|
||||
'stra.alertDur': 'Alert duration',
|
||||
'stra.trigger': 'Trigger condition',
|
||||
'stra.trigger.normal': 'Normal',
|
||||
'stra.trigger.and': 'And',
|
||||
'stra.preview': 'Preview',
|
||||
'stra.preview.duration': 'duration',
|
||||
'stra.preview.all': 'each value',
|
||||
'stra.preview.happen': 'value',
|
||||
'stra.preview.nodata': 'no data',
|
||||
'stra.preview.max': 'max',
|
||||
'stra.preview.min': 'min',
|
||||
'stra.preview.avg': 'avg',
|
||||
'stra.preview.sum': 'sum',
|
||||
'stra.preview.all.help': 'The disconnection situation is discontinuous. To increase fault tolerance, you can choose happen',
|
||||
'stra.tag': 'Tag filter',
|
||||
'stra.tag.add': 'Add tag filter',
|
||||
'stra.tag.modify': 'Modify tag filter',
|
||||
'stra.tag.include': 'include',
|
||||
'stra.tag.exclude': 'exclude',
|
||||
'stra.action': 'Action',
|
||||
'stra.action.d1': 'in',
|
||||
'stra.action.d2': 'min',
|
||||
'stra.action.d3': 'maximum alarm',
|
||||
'stra.action.d4': 'times',
|
||||
'stra.notify.team': 'Notify teams',
|
||||
'stra.notify.user': 'Notify users',
|
||||
'stra.notify.msg.error': 'Must be an alarm receiver or receiving group',
|
||||
'stra.notify.callback': 'Notify me of the system I developed (alarm callback, please confirm that it is an address accessible in IDC)',
|
||||
'stra.recovery.dur': 'Recovery duration',
|
||||
'stra.recovery.dur.help.1': 'Recovered, it will continue to observe for',
|
||||
'stra.recovery.dur.help.2': 'seconds, and the recovery notification is sent only when the alarm is not triggered again.',
|
||||
'stra.recovery.notify': 'Recovery notify',
|
||||
'stra.recovery.notify.checkbox': 'Do not send recovery notifications',
|
||||
'stra.period.time': 'Period time',
|
||||
'stra.alert.upgrade': 'Alert upgrade',
|
||||
'stra.alert.upgrade.checkbox': 'ON',
|
||||
'stra.alert.upgrade.d1': 'duration',
|
||||
'stra.alert.upgrade.d2': 'unprocessed and unrecovered continuous alarm',
|
||||
'stra.alert.upgrade.d3': 'will be use',
|
||||
'stra.alert.upgrade.d4': 'send to',
|
||||
|
||||
'api.name': 'Name',
|
||||
'api.url': 'URL',
|
||||
'api.viewGraph': 'Open graph',
|
||||
'api.alarm': 'Setup alarm',
|
||||
'api.batch.viewGraph': 'Batch open graphs',
|
||||
'api.batch.alarm': 'Batch setup alarms',
|
||||
'api.title': 'Metric',
|
||||
'api.protocol': 'Protocol',
|
||||
'api.domain': 'Domain',
|
||||
'api.port': 'Port',
|
||||
'api.path': 'Path',
|
||||
'api.header.add': 'Add header',
|
||||
'api.expected_code': 'HTTP status code',
|
||||
'api.expected_string': 'Expected string',
|
||||
'api.unexpected_string': 'Unexpected string',
|
||||
'api.timeout': 'Timeout',
|
||||
'api.interval': 'Interval',
|
||||
'api.region': 'Region',
|
||||
'api.comment': 'Comment',
|
||||
}
|
|
@ -0,0 +1,435 @@
|
|||
export default {
|
||||
'login': '登录',
|
||||
'logout': '退出登录',
|
||||
'register': '注册',
|
||||
'login.title': '账户登录',
|
||||
'login.ldap': '使用LDAP账号登录',
|
||||
|
||||
'form.save': '保 存',
|
||||
'form.create': '创 建',
|
||||
'form.submit': '提 交',
|
||||
'form.delete': '删 除',
|
||||
'form.login': '登 录',
|
||||
'form.goback': '返 回',
|
||||
|
||||
'msg.submit.success': '提交成功',
|
||||
'msg.modify.success': '修改成功',
|
||||
'msg.create.success': '创建成功',
|
||||
'msg.add.success': '添加成功',
|
||||
'msg.delete.success': '删除成功',
|
||||
'msg.clone.success': '克隆成功',
|
||||
'msg.sort.success': '排序成功',
|
||||
|
||||
'please.select.node': '请先选择左侧服务节点',
|
||||
|
||||
'table.nodata': '暂无数据',
|
||||
'table.create': '创建',
|
||||
'table.operations': '操作',
|
||||
'table.batch.operations': '批量操作',
|
||||
'table.detail': '详情',
|
||||
'table.modify': '修改',
|
||||
'table.delete': '删除',
|
||||
'table.delete.batch': '批量删除',
|
||||
'table.clone': '克隆',
|
||||
'table.delete.sure': '确定要删除吗?',
|
||||
'table.delete.there.sure': '确定要删除这些吗?',
|
||||
'table.ident': '英文标识',
|
||||
'table.name': '显示名',
|
||||
'table.cate': '类别',
|
||||
'table.creator': '创建者',
|
||||
'table.lastupdated': '修改时间',
|
||||
'table.note': '备注',
|
||||
|
||||
'user.create': '新建用户',
|
||||
'user.modify': '修改用户',
|
||||
'user.username': '用户名',
|
||||
'user.dispname': '显示名',
|
||||
'user.password': '密码',
|
||||
'user.email': '邮箱',
|
||||
'user.phone': '手机',
|
||||
'user.reset.password': '重置密码',
|
||||
'user.reset.password.success': '重置密码成功',
|
||||
'user.invite': '邀请用户',
|
||||
'user.invite.tips': '点击生成一个邀请用户的链接',
|
||||
'user.isroot': '是否超管',
|
||||
'password.old': '旧密码',
|
||||
'password.new': '新密码',
|
||||
'token.reset': '重置',
|
||||
'token.reset.success': '重置成功',
|
||||
'invite.user.copy.success': '邀请用户的链接复制成功',
|
||||
'invite.user.copy.faile': '复制失败,请手动复制',
|
||||
|
||||
'tree.select.node': '请先选择左侧节点',
|
||||
'tree.search': '搜节点(空格分割)',
|
||||
'tree.node': '节点',
|
||||
'node.copy.path': '拷贝路径',
|
||||
'node.copy.path.success': '拷贝路径成功',
|
||||
'node.copy.path.error': '拷贝路径失败',
|
||||
'node.create.tenant': '添加租户节点',
|
||||
'node.create': '添加节点',
|
||||
'node.modify': '修改节点',
|
||||
'node.delete': '删除节点',
|
||||
'node.name': '节点名称',
|
||||
'node.isLeaf': '是否叶子节点',
|
||||
'node.cate': '类别',
|
||||
'node.color': '颜色',
|
||||
'node.note': '备注',
|
||||
'node.cate.create': '创建节点类别',
|
||||
'node.cate.modify': '修改节点类别',
|
||||
'node.display.path': '显示挂载节点',
|
||||
'node.rename': '节点重命名',
|
||||
'node.rename.newname': '新节点名称',
|
||||
'node.rename.success': '节点重命名成功!',
|
||||
'node.child.create': '创建子节点',
|
||||
'node.child.create.success': '创建子节点成功!',
|
||||
'node.child.newname': '子节点名称',
|
||||
'node.delete.success': '删除节点成功!',
|
||||
'node.leaf.cannot.create': '叶子节点无法继续创建子节点',
|
||||
'根节点不能删除': '根节点不能删除',
|
||||
|
||||
'select.all': '全选',
|
||||
'select.include': '包含',
|
||||
'select.exclude': '排除',
|
||||
'select.dynamic': '动态值',
|
||||
'select.selected': '已选',
|
||||
'select.selected.clear': '清除已选项',
|
||||
'select.manual.input': '手动输入',
|
||||
'select.total': '选项',
|
||||
'select.current.page': '全选当前页',
|
||||
|
||||
'1小时': '1小时',
|
||||
'2小时': '2小时',
|
||||
'6小时': '6小时',
|
||||
'12小时': '12小时',
|
||||
'1天': '1天',
|
||||
'2天': '2天',
|
||||
'7天': '7天',
|
||||
'30天': '30天',
|
||||
'其它': '其它',
|
||||
|
||||
'menu.endpoints': '监控对象',
|
||||
'menu.endpoints.all': '全部对象',
|
||||
'menu.endpoints.node': '节点对象',
|
||||
'menu.endpoints.node.manage': '节点管理',
|
||||
'menu.monitor': '监控报警',
|
||||
'menu.monitor.dashboard': '监控看图',
|
||||
'menu.monitor.screen': '监控大盘',
|
||||
'menu.monitor.strategy': '报警策略',
|
||||
'menu.monitor.history': '报警历史',
|
||||
'menu.monitor.silence': '报警屏蔽',
|
||||
'menu.monitor.collect': '采集配置',
|
||||
'menu.users': '用户管理',
|
||||
'menu.users.users': '用户管理',
|
||||
'menu.users.teams': '团队管理',
|
||||
|
||||
'endpoints.ident': '标识',
|
||||
'endpoints.alias': '别名',
|
||||
'endpoints.nodes': '挂载节点',
|
||||
'endpoints.batch.filter': '批量过滤',
|
||||
'endpoints.batch.filter.key': '批量字段',
|
||||
'endpoints.batch.filter.value': '批量值',
|
||||
'endpoints.export.excel': '导出 Excel',
|
||||
'endpoints.import': '导入 Endpoints',
|
||||
'endpoints.export': '导出 Endpoints',
|
||||
'endpoints.delete': '删除 Endpoints',
|
||||
'endpoints.bind': '挂载 Endpoints',
|
||||
'endpoints.unbind': '解载 Endpoints',
|
||||
'endpoints.copy.selected': '复制已选',
|
||||
'endpoints.copy.currentPage': '复制当前页',
|
||||
'endpoints.copy.all': '复制所有',
|
||||
'endpoints.copy.empty': '复制的对象为空',
|
||||
'endpoints.copy.error': '复制失败,请手动复制',
|
||||
'endpoints.import.batch.help': '每一条是 ident::alias 拼接在一起',
|
||||
'endpoints.modify.alias': '改别名',
|
||||
'endpoints.bind.node': '挂载的节点',
|
||||
'endpoints.unbind.node': '解除挂载的节点',
|
||||
'endpoints.delete.old.bind': '是否删除旧的挂载关系',
|
||||
|
||||
'team.ident': '英文标识',
|
||||
'team.name': '中文名称',
|
||||
'team.admins': '管理员',
|
||||
'team.members': '普通成员',
|
||||
'team.mgmt': '管理方式',
|
||||
'team.mgmt.admin': '管理员管理制',
|
||||
'team.mgmt.member': '成员管理制',
|
||||
|
||||
'周一': '周一',
|
||||
'周二': '周二',
|
||||
'周三': '周三',
|
||||
'周四': '周四',
|
||||
'周五': '周五',
|
||||
'周六': '周六',
|
||||
'周日': '周日',
|
||||
|
||||
'clone.to.other.node': '克隆到其他节点',
|
||||
'clone.to.other.node.success': '克隆到节点成功成功!',
|
||||
'collect.log': '日志',
|
||||
'collect.port': '端口',
|
||||
'collect.proc': '进程',
|
||||
'collect.common.search': '搜索名称',
|
||||
'collect.common.name': '采集名称',
|
||||
'collect.common.type': '类型',
|
||||
'collect.common.creator': '创建者',
|
||||
'collect.common.last_updated': '修改时间',
|
||||
'collect.common.node': '归属节点',
|
||||
'collect.common.step': '采集周期',
|
||||
'collect.common.step.unit': '秒',
|
||||
'collect.common.note': '备注',
|
||||
|
||||
'collect.log.msg.pattern.empty': '匹配正则不能为空',
|
||||
'collect.log.msg.log.empty': '日志不能为空',
|
||||
'collect.log.msg.tag.maximum': 'tags 上限三个',
|
||||
'collect.log.ns': '归属节点',
|
||||
'collect.log.name': '监控指标名称',
|
||||
'collect.log.func': '计算方法',
|
||||
'collect.log.func.cnt': '计数:对符合规则的日志进行计数',
|
||||
'collect.log.func.avg': '平均:对符合规则的日志抓取出的数字进行平均',
|
||||
'collect.log.func.sum': '求和:对符合规则的日志抓取出的数字进行求和',
|
||||
'collect.log.func.max': '最大值:对符合规则的日志抓取出的数字取最大值',
|
||||
'collect.log.func.min': '最小值:对符合规则的日志抓取出的数字进最小值',
|
||||
'collect.log.path': '日志路径',
|
||||
'collect.log.path.dynamic': '动态日志',
|
||||
'collect.log.path.dynamic.tip.1': '日志末尾自带时间格式,例如',
|
||||
'collect.log.path.dynamic.tip.2': "$'{}' 中不能包含 /",
|
||||
'collect.log.timeFmt': '时间格式',
|
||||
'collect.log.timeFmt.help.1': '时间格式必须和日志中的格式一样, 否则无法采集到数据。',
|
||||
'collect.log.timeFmt.help.2': '如日志中出现多段符合时间正则的, 只使用第一个匹配结果。',
|
||||
'collect.log.step': '采集周期',
|
||||
'collect.log.step.unit': '秒',
|
||||
'collect.log.pattern': '匹配正则',
|
||||
'collect.log.pattern.tip.1': '请填写正则表达式',
|
||||
'collect.log.pattern.tip.2': '如计算方式选择了耗时: 必须包含括号( )',
|
||||
'collect.log.pattern.tip.3': '例如 cost=(\\d+) , 则取\\d+的部分(默认以第一个括号为准)',
|
||||
'collect.log.tagval.placeholder': '不是曲线值! 匹配结果必须可枚举!',
|
||||
'collect.log.tags.add': '新增 tag',
|
||||
'collect.log.tagName.help.title': 'tagName 填写说明',
|
||||
'collect.log.tagName.help.1': '不允许包含 host、trigger、include',
|
||||
'collect.log.tagName.help.2': '不允许包含如下4个特殊字符= , : @',
|
||||
'collect.log.tagValue.help.title': 'tagValue 填写说明',
|
||||
'collect.log.tagValue.help.1': '必须包含括号。括号中的正则内容被用作tagValue的取值,必须可枚举。',
|
||||
'collect.log.tagValue.help.2': '不允许包含如下4个特殊字符= , : @',
|
||||
'collect.log.check': '配置验证',
|
||||
'collect.log.check.btn': '验证',
|
||||
'collect.log.check.btn2': '我的配置是否有问题?',
|
||||
'collect.log.check.help': '请输入一行待监控的完整日志,包括时间。',
|
||||
'collect.log.check.help.tip.1': '正确匹配:',
|
||||
'collect.log.check.help.tip.2': '输出正则匹配结果完整式及子项,输出tag正则匹配结果完整式及子项,以及时间匹配结果',
|
||||
'collect.log.check.help.tip.3': '错误匹配:',
|
||||
'collect.log.check.help.tip.4': '输出错误信息',
|
||||
'collect.log.check.add.tip': '添加采集配置的时候,请验证配置',
|
||||
'collect.log.note': '备注',
|
||||
'collect.batch.import': '导入采集配置',
|
||||
'collect.batch.export': '导出采集配置',
|
||||
|
||||
'collect.port.title': '端口监控指标',
|
||||
'collect.port.name.placeholder': '对采集配置的说明,例如 web端口采集',
|
||||
'collect.port.pattern.msg': '只能允许填写英文、数字、中划线、下划线、点',
|
||||
'collect.port.port': '端口号',
|
||||
'collect.port.timeout': '连接超时',
|
||||
'collect.port.timeout.unit': '秒',
|
||||
|
||||
'collect.proc.title': '进程采集指标',
|
||||
'collect.proc.name.placeholder': '对采集配置的说明,例如 nginx进程采集',
|
||||
'collect.proc.service.pattern.msg': '只能允许填写英文、数字、中划线、下划线、点',
|
||||
'collect.proc.type': '采集方式',
|
||||
'collect.proc.type.cmd': '命令行',
|
||||
'collect.proc.type.name': '进程名',
|
||||
'collect.proc.type.input.pattern.msg': '不能包含中文',
|
||||
|
||||
'graph.subscribe': '订阅图表',
|
||||
'graph.subscribe.node': '所属节点',
|
||||
'graph.subscribe.screen': '选择大盘',
|
||||
'graph.subscribe.tag': '选择分类',
|
||||
'graph.subscribe.success': '图表订阅成功!',
|
||||
'graph.share': '分享图表',
|
||||
'graph.clear': '清空图表',
|
||||
'graph.view': '查看',
|
||||
'graph.save': '保存',
|
||||
'graph.machine.list.title': '机器列表',
|
||||
'graph.machine.list.update': '更新图表',
|
||||
'graph.metric.list.title': '指标列表',
|
||||
'graph.metric.list.search': '搜索指标',
|
||||
'graph.metric.list.all': '全部',
|
||||
'graph.refresh': '刷新',
|
||||
'graph.config.title': '图表配置',
|
||||
'graph.config.graph.title': '标题',
|
||||
'graph.config.node': '节点',
|
||||
'graph.config.metric': '指标',
|
||||
'graph.config.aggr': '聚合',
|
||||
'graph.config.aggr.sum': '求和',
|
||||
'graph.config.aggr.avg': '均值',
|
||||
'graph.config.aggr.max': '最大值',
|
||||
'graph.config.aggr.min': '最小值',
|
||||
'graph.config.aggr.group': '聚合维度',
|
||||
'graph.config.series': '曲线',
|
||||
'graph.config.series.unit': '条',
|
||||
'graph.config.cate': '分类',
|
||||
'graph.config.time': '时间',
|
||||
'graph.config.threshold': '阈值',
|
||||
'graph.config.link': '下钻',
|
||||
'graph.config.link.help': '自定义链接,方便跳转到更深层的大盘、临时图、报警策略等',
|
||||
'graph.config.chartType.targetValue': '取值',
|
||||
'graph.config.chartType.current': '当前值',
|
||||
'graph.config.chartType.unit': '单位',
|
||||
'graph.config.chartType.subType': '类型',
|
||||
'graph.config.subType.normal': '数值',
|
||||
'graph.config.subType.normal.tip': '(必须选择聚合)',
|
||||
'graph.config.subType.solidGauge': '仪表盘',
|
||||
'graph.config.subType.liquidFillGauge': '容量水位',
|
||||
'graph.config.chartType.valueMap': '数值映射',
|
||||
'graph.config.chartType.mapConf': '映射关系',
|
||||
'graph.config.chartType.tableType': '表格类型',
|
||||
'graph.config.chartType.tableType.current': '当前值',
|
||||
'graph.config.chartType.tableType.stats': '统计值',
|
||||
'graph.config.chartType.pieType': '样式',
|
||||
'graph.config.chartType.pieType.pie': 'Pie',
|
||||
'graph.config.chartType.pieType.donut': 'Donut',
|
||||
'graph.config.chartType.tableType.columnsKey': '显示列',
|
||||
|
||||
'event.tab.alert': '未恢复报警',
|
||||
'event.tab.all': '所有历史报警',
|
||||
'event.msg.ignore.success': '忽略报警成功',
|
||||
'event.msg.claim.success': '认领报警成功',
|
||||
'event.msg.claim.all.success': '一键认领报警成功',
|
||||
'event.table.time': '发生时间',
|
||||
'event.table.stra': '策略名称',
|
||||
'event.table.node': '节点',
|
||||
'event.table.priority': '级别',
|
||||
'event.table.notify': '通知结果',
|
||||
'event.table.ignore': '忽略',
|
||||
'event.table.ignore.sure': '确定要忽略这条报警吗?',
|
||||
'event.table.claim': '认领',
|
||||
'event.table.claim.sure': '确定要认领这条报警吗?',
|
||||
'event.table.shield': '屏蔽',
|
||||
'event.table.assignees': '认领人',
|
||||
'event.table.status': '状态',
|
||||
'event.table.status.alert': '报警',
|
||||
'event.table.status.recovery': '恢复',
|
||||
'event.table.claim.all': '一键认领',
|
||||
'event.table.claim.all.sure': '确定认领该节点下所有未恢复的报警吗?',
|
||||
'event.table.detail.title': '报警事件详情',
|
||||
'event.table.metric': '指标',
|
||||
'event.table.expression': '表达式',
|
||||
'event.table.scene': '现场值',
|
||||
'event.table.scene.time': '时间',
|
||||
'event.table.scene.value': '值',
|
||||
|
||||
'screen.create': '创建大盘',
|
||||
'screen.tag.add': '新增分类',
|
||||
'screen.tag.batch.modify': '批量修改分类',
|
||||
'screen.auto.refresh': '自动刷新',
|
||||
'screen.col': '列',
|
||||
'screen.tag.graph.add': '新增图表',
|
||||
'screen.tag.graph.add.graph': '折线图',
|
||||
'screen.tag.graph.add.number': '数值 (必须选择聚合方式)',
|
||||
'screen.tag.graph.add.table': '表格',
|
||||
'screen.tag.graph.add.pie': '扇形图',
|
||||
'screen.tag.up': '上移',
|
||||
'screen.tag.down': '下移',
|
||||
'screen.tag.batch.modify.tag': '需要移动的分类',
|
||||
'screen.tag.batch.modify.target.node': '将要移动到的节点',
|
||||
'screen.tag.batch.modify.target.screen': '将要移动到的大盘',
|
||||
'screen.graph.extraMoreList.share': '分享图表',
|
||||
'screen.graph.extraMoreList.clone': '克隆图表',
|
||||
'screen.graph.extraMoreList.delete': '删除图表',
|
||||
'screen.graph.extraMoreList.delete.sure': '确定要删除这个图表吗?',
|
||||
|
||||
'silence.add': '新增屏蔽',
|
||||
'silence.metric': '指标',
|
||||
'silence.bindNode': '关联节点',
|
||||
'silence.time': '屏蔽时间',
|
||||
'silence.cause': '屏蔽原因',
|
||||
'silence.user': '操作者',
|
||||
'silence.delete': '解除',
|
||||
'silence.detail.title': '屏蔽详情',
|
||||
'silence.form.metric': '屏蔽指标',
|
||||
'silence.form.endpoints': '屏蔽 endpoints',
|
||||
'silence.form.tags': '屏蔽 tags',
|
||||
'silence.form.stime': '开始时间',
|
||||
'silence.form.etime': '结束时间',
|
||||
'silence.cause.default': '快速屏蔽',
|
||||
|
||||
'stra.add': '新增报警策略',
|
||||
'stra.batch.import.success': '批量导入成功',
|
||||
'stra.advanced': '高级',
|
||||
'stra.seconds': '秒',
|
||||
'stra.minutes': '分钟',
|
||||
'stra.name': '名称',
|
||||
'stra.priority': '级别',
|
||||
'stra.metric': '指标',
|
||||
'stra.notify': '报警接收',
|
||||
'stra.batch.modify.excludeNs': '修改排除节点',
|
||||
'stra.batch.modify.notify': '修改报警接收组',
|
||||
'stra.batch.cloneTo.otherNode': '克隆到其他节点',
|
||||
'stra.batch.delete': '批量删除',
|
||||
'stra.batch.import': '导入策略',
|
||||
'stra.batch.export': '导出策略',
|
||||
'stra.node': '生效节点',
|
||||
'stra.node.exclude': '排除节点',
|
||||
'stra.priority.1': '一级报警',
|
||||
'stra.priority.2': '二级报警',
|
||||
'stra.priority.3': '三级报警',
|
||||
'stra.priority.1.tip': '一级报警:发送语音, 短信, IM, 邮件',
|
||||
'stra.priority.2.tip': '二级报警:发送短信, IM, 邮件',
|
||||
'stra.priority.3.tip': '三级报警:发送IM,邮件',
|
||||
'stra.alertDur': '统计周期',
|
||||
'stra.trigger': '触发条件',
|
||||
'stra.trigger.normal': '常用',
|
||||
'stra.trigger.and': '与条件',
|
||||
'stra.preview': '预览',
|
||||
'stra.preview.duration': '持续',
|
||||
'stra.preview.all': '每个值',
|
||||
'stra.preview.happen': '次值',
|
||||
'stra.preview.nodata': '无数据上报',
|
||||
'stra.preview.max': '最大值',
|
||||
'stra.preview.min': '最小值',
|
||||
'stra.preview.avg': '均值',
|
||||
'stra.preview.sum': '求和值',
|
||||
'stra.preview.all.help': '断线情况,即为不连续。若要增加容错,可选择happen',
|
||||
'stra.tag': 'Tag 过滤',
|
||||
'stra.tag.add': '添加筛选条件',
|
||||
'stra.tag.modify': '修改筛选条件',
|
||||
'stra.tag.include': '包含',
|
||||
'stra.tag.exclude': '排除',
|
||||
'stra.action': '执行动作',
|
||||
'stra.action.d1': '在',
|
||||
'stra.action.d2': '分钟内',
|
||||
'stra.action.d3': '最多报警',
|
||||
'stra.action.d4': '次',
|
||||
'stra.notify.team': '报警接收团队',
|
||||
'stra.notify.user': '报警接收人',
|
||||
'stra.notify.msg.error': '必须存在一个报警接收人或接收组',
|
||||
'stra.notify.callback': '通知我自己开发的系统(报警回调, 请确认是 IDC 内可访问的地址)',
|
||||
'stra.recovery.dur': '留观时长',
|
||||
'stra.recovery.dur.help.1': '告警恢复后持续观察',
|
||||
'stra.recovery.dur.help.2': '秒,未再触发阈值才发送恢复通知',
|
||||
'stra.recovery.notify': '静默恢复',
|
||||
'stra.recovery.notify.checkbox': '不发送恢复通知',
|
||||
'stra.period.time': '生效时间',
|
||||
'stra.alert.upgrade': '报警升级',
|
||||
'stra.alert.upgrade.checkbox': '是否启动报警升级',
|
||||
'stra.alert.upgrade.d1': '持续',
|
||||
'stra.alert.upgrade.d2': '未处理并且未恢复的持续报警',
|
||||
'stra.alert.upgrade.d3': '将以',
|
||||
'stra.alert.upgrade.d4': '发送给',
|
||||
|
||||
'api.name': '采集名称',
|
||||
'api.url': '探测目标',
|
||||
'api.viewGraph': '看图',
|
||||
'api.alarm': '报警',
|
||||
'api.batch.viewGraph': '批量看图',
|
||||
'api.batch.alarm': '批量报警',
|
||||
'api.title': '监控指标',
|
||||
'api.protocol': '协议',
|
||||
'api.domain': '域名',
|
||||
'api.port': '端口',
|
||||
'api.path': '路径',
|
||||
'api.header.add': '添加 header',
|
||||
'api.expected_code': '状态码',
|
||||
'api.expected_string': '包含字符串',
|
||||
'api.unexpected_string': '不包含字符串',
|
||||
'api.timeout': '超时',
|
||||
'api.interval': '采集周期',
|
||||
'api.region': '探测源Region',
|
||||
'api.comment': '备注',
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Modal, Form, TreeSelect } from 'antd';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
import _ from 'lodash';
|
||||
|
@ -63,7 +64,7 @@ class BatchCloneToNidModal extends Component<Props & FormProps> {
|
|||
>
|
||||
<Form layout="vertical">
|
||||
<FormItem
|
||||
label="生效节点"
|
||||
label={<FormattedMessage id="collect.common.node" />}
|
||||
>
|
||||
{
|
||||
getFieldDecorator('nid', {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl';
|
||||
import { Link } from 'react-router-dom';
|
||||
import _ from 'lodash';
|
||||
import { Button, Form, Select, Input, Modal, message, Icon, Tooltip, Row, Col, TreeSelect } from 'antd';
|
||||
|
@ -47,8 +48,8 @@ function getPureName(name: string) {
|
|||
return name;
|
||||
}
|
||||
|
||||
class CollectForm extends Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
class CollectForm extends Component<Props & WrappedComponentProps, State> {
|
||||
constructor(props: Props & WrappedComponentProps) {
|
||||
super(props);
|
||||
const { params } = this.props;
|
||||
this.state = {
|
||||
|
@ -98,7 +99,7 @@ class CollectForm extends Component<Props, State> {
|
|||
tags,
|
||||
});
|
||||
} else {
|
||||
message.error('tags 上限三个');
|
||||
message.error(this.props.intl.formatMessage({ id: 'collect.log.msg.tag.maximum' }));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,9 +137,9 @@ class CollectForm extends Component<Props, State> {
|
|||
});
|
||||
|
||||
if (pattern === '') {
|
||||
message.error('匹配正则不能为空');
|
||||
message.error(this.props.intl.formatMessage({ id: 'collect.log.msg.pattern.empty' }));
|
||||
} else if (log === '') {
|
||||
message.error('log不能为空');
|
||||
message.error(this.props.intl.formatMessage({ id: 'collect.log.msg.log.empty' }));
|
||||
} else {
|
||||
this.setState({ logChecked: true, logCheckLoading: true });
|
||||
request(`${api.collect}/check`, {
|
||||
|
@ -181,7 +182,7 @@ class CollectForm extends Component<Props, State> {
|
|||
const dynamicLogReg = /\$\{[^{]+\}/;
|
||||
const dynamicLogRegMatch = filePath.match(dynamicLogReg);
|
||||
if (dynamicLogRegMatch && dynamicLogRegMatch.length && _.some(dynamicLogRegMatch, n => _.includes(n, '/'))) {
|
||||
message.error('动态日志 ${}中不能包含/');
|
||||
message.error('/ cannot be included in ${}');
|
||||
return;
|
||||
}
|
||||
// tags 数据转换成接口需要的格式,以及验证是否包含括号
|
||||
|
@ -190,15 +191,15 @@ class CollectForm extends Component<Props, State> {
|
|||
if (tags.length) {
|
||||
const TagValidateStatus = _.every(tags, (o) => {
|
||||
if (o.name === '' || o.value === '') {
|
||||
message.error('tagName、tagValue 值不能为空');
|
||||
message.error('tagName or tagValue is required');
|
||||
return false;
|
||||
}
|
||||
if (_.includes(reservedKws, o.name)) {
|
||||
message.error('tagName 不能包含 host、trigger、include 这些是odin系统保留关键字');
|
||||
message.error('Can not include the host trigger include these are the reserved keywords for the Odin');
|
||||
return false;
|
||||
}
|
||||
if (!bracketsReg.test(o.value)) {
|
||||
message.error('tagValue 必须包含括号');
|
||||
message.error('tagValue must include parentheses');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -217,7 +218,7 @@ class CollectForm extends Component<Props, State> {
|
|||
const { params = {} } = this.props;
|
||||
if (params.action === 'add') {
|
||||
if (!this.state.logChecked) {
|
||||
message.error('添加采集配置的时候,请验证配置');
|
||||
message.error('Verify the configuration when adding the collection configuration');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -257,13 +258,13 @@ class CollectForm extends Component<Props, State> {
|
|||
<Form layout="horizontal" onSubmit={this.handleSubmit}>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="归属节点"
|
||||
label={<FormattedMessage id="collect.common.node" />}
|
||||
>
|
||||
{
|
||||
getFieldDecorator('nid', {
|
||||
initialValue: initialValues.nid,
|
||||
rules: [
|
||||
{ required: true, message: '不能为空' },
|
||||
{ required: true },
|
||||
],
|
||||
})(
|
||||
<TreeSelect
|
||||
|
@ -280,16 +281,13 @@ class CollectForm extends Component<Props, State> {
|
|||
)
|
||||
}
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="监控指标名称">
|
||||
<FormItem {...formItemLayout} label={<FormattedMessage id="collect.log.name" />}>
|
||||
<Input
|
||||
addonBefore={params.action === 'add' || initialValues.name.indexOf('log.') === 0 ? 'log.' : null}
|
||||
{...getFieldProps('name', {
|
||||
initialValue: getPureName(initialValues.name),
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '不能为空',
|
||||
},
|
||||
{ required: true },
|
||||
nameRule,
|
||||
],
|
||||
})}
|
||||
|
@ -297,7 +295,7 @@ class CollectForm extends Component<Props, State> {
|
|||
style={{ width: params.action === 'add' || initialValues.name.indexOf('log.') === 0 ? 500 : 500 }}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="计算方法">
|
||||
<FormItem {...formItemLayout} label={<FormattedMessage id="collect.log.func" />}>
|
||||
<Select
|
||||
{...getFieldProps('func', {
|
||||
initialValue: initialValues.func,
|
||||
|
@ -305,28 +303,26 @@ class CollectForm extends Component<Props, State> {
|
|||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '不能为空',
|
||||
},
|
||||
],
|
||||
})}
|
||||
size="default"
|
||||
style={{ width: 500 }}
|
||||
>
|
||||
<Option value="cnt">计数:对符合规则的日志进行计数</Option>
|
||||
<Option value="avg">平均:对符合规则的日志抓取出的数字进行平均</Option>
|
||||
<Option value="sum">求和:对符合规则的日志抓取出的数字进行求和</Option>
|
||||
<Option value="max">最大值:对符合规则的日志抓取出的数字取最大值</Option>
|
||||
<Option value="min">最小值:对符合规则的日志抓取出的数字进最小值</Option>
|
||||
<Option value="cnt"><FormattedMessage id="collect.log.func.cnt" /></Option>
|
||||
<Option value="avg"><FormattedMessage id="collect.log.func.avg" /></Option>
|
||||
<Option value="sum"><FormattedMessage id="collect.log.func.sum" /></Option>
|
||||
<Option value="max"><FormattedMessage id="collect.log.func.max" /></Option>
|
||||
<Option value="min"><FormattedMessage id="collect.log.func.min" /></Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="日志路径">
|
||||
<FormItem {...formItemLayout} label={<FormattedMessage id="collect.log.path" />}>
|
||||
<Input
|
||||
{...getFieldProps('file_path', {
|
||||
initialValue: initialValues.file_path,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '不能为空',
|
||||
},
|
||||
],
|
||||
})}
|
||||
|
@ -338,16 +334,16 @@ class CollectForm extends Component<Props, State> {
|
|||
overlayClassName="largeTooltip"
|
||||
title={
|
||||
<div style={{ wordBreak: 'break-all', wordWrap: 'break-word' }}>
|
||||
日志末尾自带时间格式,例如 {'/path/access.log.${%Y%m%d%H}'}<br />
|
||||
{'${}中不能包含/'}
|
||||
<FormattedMessage id="collect.log.path.dynamic.tip.1" /> {'/path/access.log.${%Y%m%d%H}'}<br />
|
||||
<FormattedMessage id="collect.log.path.dynamic.tip.2" />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<span>动态日志 <Icon type="info-circle-o" /></span>
|
||||
<span><FormattedMessage id="collect.log.path.dynamic" /> <Icon type="info-circle-o" /></span>
|
||||
</Tooltip>
|
||||
</span>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="时间格式">
|
||||
<FormItem {...formItemLayout} label={<FormattedMessage id="collect.log.timeFmt" />}>
|
||||
<div
|
||||
style={{
|
||||
width: 500, float: 'left', position: 'relative', zIndex: 1,
|
||||
|
@ -359,7 +355,6 @@ class CollectForm extends Component<Props, State> {
|
|||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '不能为空',
|
||||
},
|
||||
],
|
||||
})}
|
||||
|
@ -378,25 +373,25 @@ class CollectForm extends Component<Props, State> {
|
|||
</Select>
|
||||
</div>
|
||||
<div style={{ marginLeft: 510, lineHeight: '20px' }}>
|
||||
时间格式必须和日志中的格式一样, 否则无法采集到数据。<br />
|
||||
如日志中出现多段符合时间正则的, 只使用第一个匹配结果。
|
||||
<FormattedMessage id="collect.log.timeFmt.help.1" /><br />
|
||||
<FormattedMessage id="collect.log.timeFmt.help.2" />
|
||||
</div>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="采集周期">
|
||||
<FormItem {...formItemLayout} label={<FormattedMessage id="collect.log.step" />}>
|
||||
<Select
|
||||
size="default"
|
||||
style={{ width: 100 }}
|
||||
{...getFieldProps('step', {
|
||||
initialValue: initialValues.step,
|
||||
rules: [
|
||||
{ required: true, message: '不能为空' },
|
||||
{ required: true },
|
||||
],
|
||||
})}
|
||||
>
|
||||
{
|
||||
_.map(interval, item => <Option key={item} value={item}>{item}</Option>)
|
||||
}
|
||||
</Select> 秒
|
||||
</Select> <FormattedMessage id="collect.log.step.unit" />
|
||||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
|
@ -404,13 +399,13 @@ class CollectForm extends Component<Props, State> {
|
|||
<Tooltip
|
||||
title={
|
||||
<div>
|
||||
请填写正则表达式<br />
|
||||
如计算方式选择了耗时: 必须包含括号( )<br />
|
||||
例如 cost=(\d+) , 则取\d+的部分(默认以第一个括号为准)
|
||||
<FormattedMessage id="collect.log.pattern.tip.1" /><br />
|
||||
<FormattedMessage id="collect.log.pattern.tip.2" /><br />
|
||||
<FormattedMessage id="collect.log.pattern.tip.3" />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<span>匹配正则 <Icon type="info-circle-o" /></span>
|
||||
<span><FormattedMessage id="collect.log.pattern" /> <Icon type="info-circle-o" /></span>
|
||||
</Tooltip>
|
||||
}
|
||||
>
|
||||
|
@ -420,13 +415,11 @@ class CollectForm extends Component<Props, State> {
|
|||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '不能为空',
|
||||
},
|
||||
],
|
||||
})}
|
||||
size="default"
|
||||
style={{ width: 500 }}
|
||||
placeholder="耗时计算:正则( )中的数值会用于计算曲线值;流量计数:每匹配到该正则,曲线值+1"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="tags">
|
||||
|
@ -451,7 +444,7 @@ class CollectForm extends Component<Props, State> {
|
|||
<Col span={13}>
|
||||
<Input
|
||||
addonBefore="tagValue"
|
||||
placeholder="不是曲线值! 匹配结果必须可枚举!"
|
||||
placeholder={this.props.intl.formatMessage({ id: 'collect.log.tagval.placeholder' })}
|
||||
value={value}
|
||||
onChange={(e) => {
|
||||
this.changeTag(e, index, 'value');
|
||||
|
@ -474,25 +467,25 @@ class CollectForm extends Component<Props, State> {
|
|||
size="default"
|
||||
onClick={this.addTag}
|
||||
>
|
||||
<Icon type="plus" />新增tag
|
||||
<Icon type="plus" /><FormattedMessage id="collect.log.tags.add" />
|
||||
</Button>
|
||||
</div>
|
||||
<div style={{ marginLeft: 510, lineHeight: '20px' }}>
|
||||
<h4>tagName填写说明</h4>
|
||||
<div>1. 不允许使用host、trigger、include</div>
|
||||
<div>2. 不允许包含如下4个特殊字符= , : @</div>
|
||||
<h4>tagValue填写说明</h4>
|
||||
<div>1. 必须包含<span style={{ color: '#B03A5B' }}>括号</span>。括号中的正则内容被用作tagValue的取值,必须可枚举。</div>
|
||||
<div>2. 不允许包含如下4个特殊字符= , : @</div>
|
||||
<h4><FormattedMessage id="collect.log.tagName.help.title" /></h4>
|
||||
<div><FormattedMessage id="collect.log.tagName.help.1" /></div>
|
||||
<div><FormattedMessage id="collect.log.tagName.help.2" /></div>
|
||||
<h4><FormattedMessage id="collect.log.tagValue.help.title" /></h4>
|
||||
<div><FormattedMessage id="collect.log.tagValue.help.1" /></div>
|
||||
<div><FormattedMessage id="collect.log.tagValue.help.2" /></div>
|
||||
</div>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="配置验证" required={this.state.logCheckVisible}>
|
||||
<FormItem {...formItemLayout} label={<FormattedMessage id="collect.log.check" />} required={this.state.logCheckVisible}>
|
||||
{
|
||||
this.state.logCheckVisible ?
|
||||
<div>
|
||||
<Input
|
||||
type="textarea"
|
||||
placeholder="01/Jan/2006:15:04:05 输入一段日志内容验证配置..."
|
||||
placeholder="01/Jan/2006:15:04:05"
|
||||
style={{ width: 500 }}
|
||||
value={this.state.log}
|
||||
onChange={(e) => {
|
||||
|
@ -502,12 +495,12 @@ class CollectForm extends Component<Props, State> {
|
|||
}}
|
||||
/>
|
||||
<span style={{ paddingLeft: 10 }}>
|
||||
请输入一行待监控的完整日志,包括时间。
|
||||
<FormattedMessage id="collect.log.check.help" />
|
||||
<Tooltip title={
|
||||
<div style={{ wordBreak: 'break-all', wordWrap: 'break-word' }}>
|
||||
正确匹配:<br />输出正则匹配结果完整式及子项,输出tag正则匹配结果完整式及子项,以及时间匹配结果
|
||||
<br />错误匹配:
|
||||
<br />输出错误信息
|
||||
<FormattedMessage id="collect.log.check.help.tip.1" /><br /><FormattedMessage id="collect.log.check.help.tip.2" />
|
||||
<br /><FormattedMessage id="collect.log.check.help.tip.3" />
|
||||
<br /><FormattedMessage id="collect.log.check.help.tip.4" />
|
||||
</div>
|
||||
}
|
||||
>
|
||||
|
@ -520,7 +513,7 @@ class CollectForm extends Component<Props, State> {
|
|||
onClick={this.checkLog}
|
||||
loading={this.state.logCheckLoading}
|
||||
>
|
||||
验证
|
||||
<FormattedMessage id="collect.log.check.btn" />
|
||||
</Button>
|
||||
</div>
|
||||
</div> :
|
||||
|
@ -533,11 +526,11 @@ class CollectForm extends Component<Props, State> {
|
|||
});
|
||||
}}
|
||||
>
|
||||
我的配置是否有问题?
|
||||
<FormattedMessage id="collect.log.check.btn2" />
|
||||
</Button>
|
||||
}
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="备注">
|
||||
<FormItem {...formItemLayout} label={<FormattedMessage id="collect.log.note" />}>
|
||||
<Input
|
||||
type="textarea"
|
||||
placeholder=""
|
||||
|
@ -548,22 +541,22 @@ class CollectForm extends Component<Props, State> {
|
|||
/>
|
||||
</FormItem>
|
||||
<FormItem wrapperCol={{ offset: 6 }} style={{ marginTop: 24 }}>
|
||||
<Button type="primary" htmlType="submit" loading={this.state.submitLoading}>提交</Button>
|
||||
<Button type="primary" htmlType="submit" loading={this.state.submitLoading}><FormattedMessage id="form.submit" /></Button>
|
||||
<Button
|
||||
style={{ marginLeft: 8 }}
|
||||
>
|
||||
<Link to={{ pathname: '/monitor/collect' }}>返回</Link>
|
||||
<Link to={{ pathname: '/monitor/collect' }}><FormattedMessage id="form.goback" /></Link>
|
||||
</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<Modal
|
||||
title={
|
||||
<span>
|
||||
验证结果:
|
||||
Result:
|
||||
{
|
||||
this.state.logCheckedResultsSuccess ?
|
||||
<span style={{ color: '#87d068' }}>成功</span> :
|
||||
<span style={{ color: '#f50' }}>失败</span>
|
||||
<span style={{ color: '#87d068' }}>success</span> :
|
||||
<span style={{ color: '#f50' }}>error</span>
|
||||
}
|
||||
</span>
|
||||
}
|
||||
|
@ -577,7 +570,7 @@ class CollectForm extends Component<Props, State> {
|
|||
size="large"
|
||||
onClick={this.closeLogCheckedResults}
|
||||
>
|
||||
关闭
|
||||
close
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
|
@ -608,4 +601,4 @@ class CollectForm extends Component<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
export default Form.create()(CollectForm);
|
||||
export default Form.create()(injectIntl(CollectForm));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl';
|
||||
import { Link } from 'react-router-dom';
|
||||
import _ from 'lodash';
|
||||
import { Button, Form, Select, Input, InputNumber, TreeSelect } from 'antd';
|
||||
|
@ -25,7 +26,7 @@ const defaultFormData = {
|
|||
step: 10,
|
||||
};
|
||||
|
||||
class CollectForm extends Component<Props> {
|
||||
class CollectForm extends Component<Props & WrappedComponentProps> {
|
||||
state = {
|
||||
submitLoading: false,
|
||||
};
|
||||
|
@ -69,19 +70,19 @@ class CollectForm extends Component<Props> {
|
|||
<Form layout="horizontal" onSubmit={this.handleSubmit}>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="端口监控指标"
|
||||
label={<FormattedMessage id="collect.port.title" />}
|
||||
>
|
||||
<span className="ant-form-text">proc.port.listen</span>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="归属节点"
|
||||
label={<FormattedMessage id="collect.common.node" />}
|
||||
>
|
||||
{
|
||||
getFieldDecorator('nid', {
|
||||
initialValue: initialValues.nid,
|
||||
rules: [
|
||||
{ required: true, message: '不能为空' },
|
||||
{ required: true },
|
||||
],
|
||||
})(
|
||||
<TreeSelect
|
||||
|
@ -98,21 +99,20 @@ class CollectForm extends Component<Props> {
|
|||
)
|
||||
}
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="采集名称">
|
||||
<FormItem {...formItemLayout} label={<FormattedMessage id="collect.common.name" />}>
|
||||
<Input
|
||||
{...getFieldProps('name', {
|
||||
initialValue: initialValues.name,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '不能为空',
|
||||
},
|
||||
nameRule,
|
||||
],
|
||||
})}
|
||||
size="default"
|
||||
style={{ width: 500 }}
|
||||
placeholder="对采集配置的说明,例如 web端口采集"
|
||||
placeholder={this.props.intl.formatMessage({ id: 'collect.port.name.placeholder' })}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="service">
|
||||
|
@ -120,29 +120,29 @@ class CollectForm extends Component<Props> {
|
|||
{...getFieldProps('service', {
|
||||
initialValue: service,
|
||||
rules: [
|
||||
{ required: true, message: '不能为空!' },
|
||||
{ pattern: /^[a-zA-Z0-9-]+$/, message: '只能允许填写英文、数字、中划线!' },
|
||||
{ required: true },
|
||||
{ pattern: /^[a-zA-Z0-9-]+$/, message: this.props.intl.formatMessage({ id: 'collect.port.pattern.msg' }) },
|
||||
],
|
||||
})}
|
||||
size="default"
|
||||
style={{ width: 500 }}
|
||||
placeholder="全局唯一的进程英文名"
|
||||
// placeholder="全局唯一的进程英文名"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="端口号" required>
|
||||
<FormItem {...formItemLayout} label={<FormattedMessage id="collect.port.port" />} required>
|
||||
<InputNumber
|
||||
{...getFieldProps('port', {
|
||||
initialValue: initialValues.port,
|
||||
rules: [
|
||||
{ required: true, message: '不能为空' },
|
||||
{ required: true },
|
||||
],
|
||||
})}
|
||||
size="default"
|
||||
style={{ width: 500 }}
|
||||
placeholder="请输入端口号"
|
||||
// placeholder="请输入端口号"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="连接超时">
|
||||
<FormItem {...formItemLayout} label={<FormattedMessage id="collect.port.timeout" />}>
|
||||
<InputNumber
|
||||
min={1}
|
||||
style={{ width: 100 }}
|
||||
|
@ -150,28 +150,28 @@ class CollectForm extends Component<Props> {
|
|||
{...getFieldProps('timeout', {
|
||||
initialValue: initialValues.timeout,
|
||||
rules: [
|
||||
{ required: true, message: '不能为空' },
|
||||
{ required: true },
|
||||
],
|
||||
})}
|
||||
/> 秒
|
||||
/> <FormattedMessage id="collect.port.timeout.unit" />
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="采集周期">
|
||||
<FormItem {...formItemLayout} label={<FormattedMessage id="collect.common.step" />}>
|
||||
<Select
|
||||
size="default"
|
||||
style={{ width: 100 }}
|
||||
{...getFieldProps('step', {
|
||||
initialValue: initialValues.step,
|
||||
rules: [
|
||||
{ required: true, message: '不能为空' },
|
||||
{ required: true },
|
||||
],
|
||||
})}
|
||||
>
|
||||
{
|
||||
_.map(interval, item => <Option key={item} value={item}>{item}</Option>)
|
||||
}
|
||||
</Select> 秒
|
||||
</Select> <FormattedMessage id="collect.common.step.unit" />
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="备注">
|
||||
<FormItem {...formItemLayout} label={<FormattedMessage id="collect.common.note" />}>
|
||||
<Input
|
||||
type="textarea"
|
||||
placeholder=""
|
||||
|
@ -182,11 +182,11 @@ class CollectForm extends Component<Props> {
|
|||
/>
|
||||
</FormItem>
|
||||
<FormItem wrapperCol={{ offset: 6 }} style={{ marginTop: 24 }}>
|
||||
<Button type="primary" htmlType="submit" loading={this.state.submitLoading}>提交</Button>
|
||||
<Button type="primary" htmlType="submit" loading={this.state.submitLoading}><FormattedMessage id="form.submit" /></Button>
|
||||
<Button
|
||||
style={{ marginLeft: 8 }}
|
||||
>
|
||||
<Link to={{ pathname: '/monitor/collect' }}>返回</Link>
|
||||
<Link to={{ pathname: '/monitor/collect' }}><FormattedMessage id="form.goback" /></Link>
|
||||
</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
|
@ -194,4 +194,4 @@ class CollectForm extends Component<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
export default Form.create()(CollectForm);
|
||||
export default Form.create()(injectIntl(CollectForm));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl';
|
||||
import { Link } from 'react-router-dom';
|
||||
import _ from 'lodash';
|
||||
import { Button, Form, Select, Input, TreeSelect } from 'antd';
|
||||
|
@ -25,7 +26,7 @@ const defaultFormData = {
|
|||
step: 10,
|
||||
};
|
||||
|
||||
class CollectForm extends Component<Props> {
|
||||
class CollectForm extends Component<Props & WrappedComponentProps> {
|
||||
state = {
|
||||
submitLoading: false,
|
||||
};
|
||||
|
@ -70,20 +71,20 @@ class CollectForm extends Component<Props> {
|
|||
<Form layout="horizontal" onSubmit={this.handleSubmit}>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="进程采集指标"
|
||||
label={<FormattedMessage id="collect.proc.title" />}
|
||||
>
|
||||
<span className="ant-form-text">proc.num</span>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="归属节点"
|
||||
label={<FormattedMessage id="collect.common.node" />}
|
||||
required
|
||||
>
|
||||
{
|
||||
getFieldDecorator('nid', {
|
||||
initialValue: initialValues.nid,
|
||||
rules: [
|
||||
{ required: true, message: '不能为空' },
|
||||
{ required: true },
|
||||
],
|
||||
})(
|
||||
<TreeSelect
|
||||
|
@ -100,21 +101,20 @@ class CollectForm extends Component<Props> {
|
|||
)
|
||||
}
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="采集名称">
|
||||
<FormItem {...formItemLayout} label={<FormattedMessage id="collect.common.name" />}>
|
||||
<Input
|
||||
{...getFieldProps('name', {
|
||||
initialValue: initialValues.name,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '不能为空',
|
||||
},
|
||||
nameRule,
|
||||
],
|
||||
})}
|
||||
size="default"
|
||||
style={{ width: 500 }}
|
||||
placeholder="对采集配置的说明,例如 nginx进程采集"
|
||||
placeholder={this.props.intl.formatMessage({ id: 'collect.proc.name.placeholder' })}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="service">
|
||||
|
@ -122,34 +122,34 @@ class CollectForm extends Component<Props> {
|
|||
{...getFieldProps('service', {
|
||||
initialValue: service,
|
||||
rules: [
|
||||
{ required: true, message: '不能为空!' },
|
||||
{ pattern: /^[a-zA-Z0-9-]+$/, message: '只能允许填写英文、数字、中划线!' },
|
||||
{ required: true },
|
||||
{ pattern: /^[a-zA-Z0-9-]+$/, message: this.props.intl.formatMessage({ id: 'collect.proc.service.pattern.msg' }) },
|
||||
],
|
||||
})}
|
||||
size="default"
|
||||
style={{ width: 500 }}
|
||||
placeholder="全局唯一的进程英文名"
|
||||
// placeholder="全局唯一的进程英文名"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="采集方式" required>
|
||||
<FormItem {...formItemLayout} label={<FormattedMessage id="collect.proc.type" />} required>
|
||||
<Select
|
||||
{...getFieldProps('collect_method', {
|
||||
initialValue: initialValues.collect_method,
|
||||
rules: [
|
||||
{ required: true, message: '不能为空' },
|
||||
{ required: true },
|
||||
],
|
||||
})}
|
||||
size="default"
|
||||
style={{ width: 500 }}
|
||||
>
|
||||
<Select.Option value="cmd">命令行</Select.Option>
|
||||
<Select.Option value="name">进程名</Select.Option>
|
||||
<Select.Option value="cmd"><FormattedMessage id="collect.proc.type.cmd" /></Select.Option>
|
||||
<Select.Option value="name"><FormattedMessage id="collect.proc.type.name" /></Select.Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label={
|
||||
getFieldValue('collect_method') === 'cmd' ? '命令行' : '进程名'
|
||||
getFieldValue('collect_method') === 'cmd' ? <FormattedMessage id="collect.proc.type.cmd" /> : <FormattedMessage id="collect.proc.type.name" />
|
||||
}
|
||||
required
|
||||
>
|
||||
|
@ -157,31 +157,31 @@ class CollectForm extends Component<Props> {
|
|||
{...getFieldProps('target', {
|
||||
initialValue: initialValues.target,
|
||||
rules: [
|
||||
{ required: true, message: '不能为空' },
|
||||
{ pattern: /^[^\u4e00-\u9fa5]+$/, message: '不能包含中文!' },
|
||||
{ required: true },
|
||||
{ pattern: /^[^\u4e00-\u9fa5]+$/, message: this.props.intl.formatMessage({ id: 'collect.proc.type.input.pattern.msg' }) },
|
||||
],
|
||||
})}
|
||||
size="default"
|
||||
style={{ width: 500 }}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="采集周期">
|
||||
<FormItem {...formItemLayout} label={<FormattedMessage id="collect.common.step" />}>
|
||||
<Select
|
||||
size="default"
|
||||
style={{ width: 100 }}
|
||||
{...getFieldProps('step', {
|
||||
initialValue: initialValues.step,
|
||||
rules: [
|
||||
{ required: true, message: '不能为空' },
|
||||
{ required: true },
|
||||
],
|
||||
})}
|
||||
>
|
||||
{
|
||||
_.map(interval, item => <Option key={item} value={item}>{item}</Option>)
|
||||
}
|
||||
</Select> 秒
|
||||
</Select> <FormattedMessage id="collect.common.step.unit" />
|
||||
</FormItem>
|
||||
<FormItem {...formItemLayout} label="备注">
|
||||
<FormItem {...formItemLayout} label={<FormattedMessage id="collect.common.note" />}>
|
||||
<Input
|
||||
type="textarea"
|
||||
placeholder=""
|
||||
|
@ -192,11 +192,11 @@ class CollectForm extends Component<Props> {
|
|||
/>
|
||||
</FormItem>
|
||||
<FormItem wrapperCol={{ offset: 6 }} style={{ marginTop: 24 }}>
|
||||
<Button type="primary" htmlType="submit" loading={this.state.submitLoading}>提交</Button>
|
||||
<Button type="primary" htmlType="submit" loading={this.state.submitLoading}><FormattedMessage id="form.submit" /></Button>
|
||||
<Button
|
||||
style={{ marginLeft: 8 }}
|
||||
>
|
||||
<Link to={{ pathname: '/monitor/collect' }}>返回</Link>
|
||||
<Link to={{ pathname: '/monitor/collect' }}><FormattedMessage id="form.goback" /></Link>
|
||||
</Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
|
@ -205,4 +205,4 @@ class CollectForm extends Component<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
export default Form.create()(CollectForm);
|
||||
export default Form.create()(injectIntl(CollectForm));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps } from 'react-intl';
|
||||
import { withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
import { Spin, message } from 'antd';
|
||||
import PropTypes from 'prop-types';
|
||||
|
@ -9,14 +10,14 @@ import request from '@common/request';
|
|||
import api from '@common/api';
|
||||
import CollectForm from './CollectForm';
|
||||
|
||||
class CollectFormMain extends Component<RouteComponentProps> {
|
||||
class CollectFormMain extends Component<RouteComponentProps & WrappedComponentProps> {
|
||||
static contextTypes = {
|
||||
getSelectedNode: PropTypes.func,
|
||||
};
|
||||
selectedNodeId: number | undefined = undefined;
|
||||
state = {
|
||||
loading: false,
|
||||
data: {},
|
||||
data: {} as any,
|
||||
selectedTreeNode: {},
|
||||
treeData: [],
|
||||
};
|
||||
|
@ -53,7 +54,7 @@ class CollectFormMain extends Component<RouteComponentProps> {
|
|||
}
|
||||
|
||||
handleSubmit = (values: any) => {
|
||||
const { action, type } = this.props.match.params;
|
||||
const { action, type } = this.props.match.params as any;
|
||||
let reqBody;
|
||||
|
||||
if (action === 'add' || action === 'clone') {
|
||||
|
@ -75,7 +76,7 @@ class CollectFormMain extends Component<RouteComponentProps> {
|
|||
method: action === 'modify' ? 'PUT' : 'POST',
|
||||
body: JSON.stringify(reqBody),
|
||||
}).then(() => {
|
||||
message.success('提交成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.submit.success' }));
|
||||
this.props.history.push({
|
||||
pathname: '/monitor/collect',
|
||||
});
|
||||
|
@ -83,7 +84,7 @@ class CollectFormMain extends Component<RouteComponentProps> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { action, type } = this.props.match.params;
|
||||
const { action, type } = this.props.match.params as any;
|
||||
const { treeData, data, loading } = this.state;
|
||||
const ActiveForm = CollectForm[type];
|
||||
if (action === 'add') {
|
||||
|
@ -103,4 +104,4 @@ class CollectFormMain extends Component<RouteComponentProps> {
|
|||
}
|
||||
}
|
||||
|
||||
export default CreateIncludeNsTree(withRouter(CollectFormMain));
|
||||
export default CreateIncludeNsTree(withRouter(injectIntl(CollectFormMain)));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export const typeMap = {
|
||||
export const typeMap: any = {
|
||||
log: '日志',
|
||||
port: '端口',
|
||||
proc: '进程',
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Row, Col, Input, Divider, Dropdown, Button, Icon, Menu, Select, Popconfirm, Modal, Table, message } from 'antd';
|
||||
|
@ -10,7 +11,7 @@ import api from '@common/api';
|
|||
import { typeMap } from './config';
|
||||
import BatchCloneToNidModal from './BatchCloneToNidModal';
|
||||
|
||||
class Collect extends Component {
|
||||
class Collect extends Component<WrappedComponentProps> {
|
||||
static contextTypes = {
|
||||
getNodes: PropTypes.func,
|
||||
getSelectedNode: PropTypes.func,
|
||||
|
@ -18,7 +19,7 @@ class Collect extends Component {
|
|||
selectedNodeId: number | undefined = undefined;
|
||||
state = {
|
||||
loading: false,
|
||||
data: [],
|
||||
data: [] as any[],
|
||||
collectType: undefined,
|
||||
searchValue: '',
|
||||
selectedRowKeys: [],
|
||||
|
@ -65,7 +66,7 @@ class Collect extends Component {
|
|||
ids: [record.id],
|
||||
}]),
|
||||
}).then(() => {
|
||||
message.success('删除成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.delete.success' }));
|
||||
this.fetchData();
|
||||
});
|
||||
}
|
||||
|
@ -73,8 +74,8 @@ class Collect extends Component {
|
|||
handleBatchDelete = () => {
|
||||
const { selectedRows } = this.state;
|
||||
Modal.confirm({
|
||||
title: '批量删除',
|
||||
content: '确定要删除所选的策略吗?',
|
||||
title: this.props.intl.formatMessage({ id: 'table.delete.batch' }),
|
||||
content: this.props.intl.formatMessage({ id: 'table.delete.there.sure' }),
|
||||
onOk: () => {
|
||||
const typeGroup = _.groupBy(selectedRows, 'collect_type');
|
||||
const reqBody = _.map(typeGroup, (value, key) => {
|
||||
|
@ -87,7 +88,7 @@ class Collect extends Component {
|
|||
method: 'DELETE',
|
||||
body: JSON.stringify(reqBody),
|
||||
}).then(() => {
|
||||
message.success('批量删除成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.delete.success' }));
|
||||
this.fetchData();
|
||||
});
|
||||
},
|
||||
|
@ -101,7 +102,7 @@ class Collect extends Component {
|
|||
BatchCloneToNidModal({
|
||||
treeNodes,
|
||||
onOk: (nid: number) => {
|
||||
const reqBody = _.map(selectedRows, (item) => {
|
||||
const reqBody = _.map(selectedRows, (item: any) => {
|
||||
const pureItem = _.pickBy(item, (v, k) => {
|
||||
return !_.includes(['id', 'creator', 'created', 'last_updator', 'last_updated', 'tags'], k);
|
||||
});
|
||||
|
@ -117,7 +118,7 @@ class Collect extends Component {
|
|||
method: 'POST',
|
||||
body: JSON.stringify(reqBody),
|
||||
}).then(() => {
|
||||
message.success('批量克隆到节点成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'clone.to.other.node.success' }));
|
||||
this.fetchData();
|
||||
});
|
||||
},
|
||||
|
@ -128,12 +129,12 @@ class Collect extends Component {
|
|||
const { searchValue, collectType } = this.state;
|
||||
let { data } = this.state;
|
||||
if (searchValue) {
|
||||
data = _.filter(data, (item) => {
|
||||
data = _.filter(data, (item: any) => {
|
||||
return item.name.indexOf(searchValue) > -1;
|
||||
});
|
||||
}
|
||||
if (collectType) {
|
||||
data = _.filter(data, (item) => {
|
||||
data = _.filter(data, (item: any) => {
|
||||
return item.collect_type === collectType;
|
||||
});
|
||||
}
|
||||
|
@ -152,7 +153,7 @@ class Collect extends Component {
|
|||
allowClear
|
||||
style={{ width: 100, marginRight: 8 }}
|
||||
className="mr10"
|
||||
placeholder="类型"
|
||||
placeholder={this.props.intl.formatMessage({ id: 'collect.common.type' })}
|
||||
value={this.state.collectType}
|
||||
onChange={(value: string) => {
|
||||
this.setState({ collectType: value });
|
||||
|
@ -160,14 +161,13 @@ class Collect extends Component {
|
|||
>
|
||||
{
|
||||
_.map(typeMap, (value, key) => {
|
||||
return <Select.Option key={key} value={key}>{value}</Select.Option>;
|
||||
return <Select.Option key={key} value={key}><FormattedMessage id={`collect.${key}`} /></Select.Option>;
|
||||
})
|
||||
}
|
||||
</Select>
|
||||
<Input.Search
|
||||
style={{ width: 200 }}
|
||||
onSearch={this.handleSearchChange}
|
||||
placeholder="搜索名称"
|
||||
/>
|
||||
</Col>
|
||||
<Col span={12} style={{ textAlign: 'right' }}>
|
||||
|
@ -178,7 +178,7 @@ class Collect extends Component {
|
|||
_.map(typeMap, (value, key) => {
|
||||
return (
|
||||
<Menu.Item key={key}>
|
||||
<Link to={{ pathname: `/monitor/collect/add/${key}` }}>{value}</Link>
|
||||
<Link to={{ pathname: `/monitor/collect/add/${key}` }}><FormattedMessage id={`collect.${key}`} /></Link>
|
||||
</Menu.Item>
|
||||
);
|
||||
})
|
||||
|
@ -187,29 +187,33 @@ class Collect extends Component {
|
|||
}
|
||||
>
|
||||
<Button style={{ marginRight: 8 }}>
|
||||
新增采集 <Icon type="down" />
|
||||
<FormattedMessage id="table.create" /> <Icon type="down" />
|
||||
</Button>
|
||||
</Dropdown>
|
||||
<Dropdown
|
||||
overlay={
|
||||
<Menu>
|
||||
<Menu.Item>
|
||||
<Button type="link" disabled={!canBatchOper} onClick={this.handleBatchDelete}>删除配置</Button>
|
||||
<Button type="link" disabled={!canBatchOper} onClick={this.handleBatchDelete}>
|
||||
<FormattedMessage id="table.delete" />
|
||||
</Button>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<Button type="link" disabled={!canBatchOper} onClick={this.handleBatchCloneToOtherNid}>克隆到其他节点</Button>
|
||||
<Button type="link" disabled={!canBatchOper} onClick={this.handleBatchCloneToOtherNid}>
|
||||
<FormattedMessage id="clone.to.other.node" />
|
||||
</Button>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
}
|
||||
>
|
||||
<Button>
|
||||
批量操作 <Icon type="down" />
|
||||
<FormattedMessage id="table.batch.operations" /> <Icon type="down" />
|
||||
</Button>
|
||||
</Dropdown>
|
||||
</Col>
|
||||
</Row>
|
||||
<Table
|
||||
rowKey={record => record.id + record.collect_type}
|
||||
rowKey={(record: any) => record.id + record.collect_type}
|
||||
rowSelection={{
|
||||
selectedRowKeys: this.state.selectedRowKeys,
|
||||
onChange: (selectedRowKeys, selectedRows) => {
|
||||
|
@ -222,37 +226,41 @@ class Collect extends Component {
|
|||
dataSource={data}
|
||||
columns= {[
|
||||
{
|
||||
title: '名称',
|
||||
title: <FormattedMessage id="collect.common.name" />,
|
||||
dataIndex: 'name',
|
||||
}, {
|
||||
title: '类型',
|
||||
title: <FormattedMessage id="collect.common.type" />,
|
||||
dataIndex: 'collect_type',
|
||||
render: (text) => {
|
||||
return typeMap[text];
|
||||
return <FormattedMessage id={`collect.${text}`} />;
|
||||
},
|
||||
}, {
|
||||
title: '创建者',
|
||||
title: <FormattedMessage id="collect.common.creator" />,
|
||||
dataIndex: 'creator',
|
||||
}, {
|
||||
title: '修改时间',
|
||||
title: <FormattedMessage id="collect.common.last_updated" />,
|
||||
dataIndex: 'last_updated',
|
||||
render: (text) => {
|
||||
return moment(text).format('YYYY-MM-DD HH:mm:ss');
|
||||
},
|
||||
}, {
|
||||
title: '操作',
|
||||
render: (text, record) => {
|
||||
title: <FormattedMessage id="table.operations" />,
|
||||
render: (_text, record: any) => {
|
||||
return (
|
||||
<span>
|
||||
<Link to={{ pathname: `/monitor/collect/modify/${_.lowerCase(record.collect_type)}/${record.id}` }}>修改</Link>
|
||||
<Link to={{ pathname: `/monitor/collect/modify/${_.lowerCase(record.collect_type)}/${record.id}` }}>
|
||||
<FormattedMessage id="table.modify" />
|
||||
</Link>
|
||||
<Divider type="vertical" />
|
||||
<Link to={{ pathname: `/monitor/collect/clone/${_.lowerCase(record.collect_type)}/${record.id}` }}>克隆</Link>
|
||||
<Link to={{ pathname: `/monitor/collect/clone/${_.lowerCase(record.collect_type)}/${record.id}` }}>
|
||||
<FormattedMessage id="table.clone" />
|
||||
</Link>
|
||||
<Divider type="vertical" />
|
||||
<Popconfirm
|
||||
title="确认删除这条配置吗?"
|
||||
title={<FormattedMessage id="table.delete.sure" />}
|
||||
onConfirm={() => { this.handleDelete(record); }}
|
||||
>
|
||||
<a>删除</a>
|
||||
<a><FormattedMessage id="table.delete" /></a>
|
||||
</Popconfirm>
|
||||
</span>
|
||||
);
|
||||
|
@ -265,4 +273,4 @@ class Collect extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default CreateIncludeNsTree(Collect, { visible: true });
|
||||
export default CreateIncludeNsTree(injectIntl(Collect), { visible: true });
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Row, Col, Icon, Dropdown, Menu } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import Graph, { GraphConfig, Info } from '@cpts/Graph';
|
||||
|
@ -63,7 +64,7 @@ export default class Graphs extends Component<Props> {
|
|||
onChange={onChange}
|
||||
extraRender={(graph: GraphData) => {
|
||||
return [
|
||||
<span className="graph-operationbar-item" key="info" title="详情">
|
||||
<span className="graph-operationbar-item" key="info">
|
||||
<Info
|
||||
graphConfig={graph.getGraphConfig(graph.props.data)}
|
||||
counterList={graph.counterList}
|
||||
|
@ -71,24 +72,24 @@ export default class Graphs extends Component<Props> {
|
|||
<Icon type="info-circle-o" />
|
||||
</Info>
|
||||
</span>,
|
||||
<span className="graph-operationbar-item" key="setting" title="编辑">
|
||||
<span className="graph-operationbar-item" key="setting">
|
||||
<Icon type="setting" onClick={() => {
|
||||
this.graphConfigForm.showModal('update', '保存', o);
|
||||
this.graphConfigForm.showModal('update', <FormattedMessage id="graph.save" />, o);
|
||||
}} />
|
||||
</span>,
|
||||
<span className="graph-operationbar-item" key="close" title="关闭">
|
||||
<span className="graph-operationbar-item" key="close">
|
||||
<Icon type="close-circle-o" onClick={() => {
|
||||
this.props.onChange('delete', o.id);
|
||||
}} />
|
||||
</span>,
|
||||
<span className="graph-extra-item" key="more" title="更多">
|
||||
<span className="graph-extra-item" key="more">
|
||||
<Dropdown trigger={['click']} overlay={
|
||||
<Menu>
|
||||
<Menu.Item>
|
||||
<a onClick={() => { this.handleSubscribeGraph(o); }}>订阅图表</a>
|
||||
<a onClick={() => { this.handleSubscribeGraph(o); }}><FormattedMessage id="graph.subscribe" /></a>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<a onClick={() => { this.handleShareGraph(o); }}>分享图表</a>
|
||||
<a onClick={() => { this.handleShareGraph(o); }}><FormattedMessage id="graph.share" /></a>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
}>
|
||||
|
@ -109,12 +110,12 @@ export default class Graphs extends Component<Props> {
|
|||
<div
|
||||
className={`${prefixCls}-graph ${prefixCls}-graph-add`}
|
||||
onClick={() => {
|
||||
this.graphConfigForm.showModal('push', '看图');
|
||||
this.graphConfigForm.showModal('push', <FormattedMessage id="graph.view" />);
|
||||
}}
|
||||
style={{ height: 350, cursor: 'pointer' }}
|
||||
>
|
||||
<div style={{ textAlign: 'center', width: '100%' }}>
|
||||
<Icon type="plus" /> 查看
|
||||
<Icon type="plus" /> <FormattedMessage id="graph.view" />
|
||||
</div>
|
||||
</div>
|
||||
</Col>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Switch, Popover, Input, Button, Card, Spin } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import Multipicker from '@cpts/Multipicker';
|
||||
|
@ -92,7 +93,7 @@ export default class HostSelect extends Component<Props, State> {
|
|||
const { dynamicSwitch, reloadBtnVisible } = this.state;
|
||||
return (
|
||||
<Spin spinning={loading}>
|
||||
<Card title="机器列表" className={`${prefixCls}-card`}>
|
||||
<Card title={<FormattedMessage id="graph.machine.list.title" />} className={`${prefixCls}-card`}>
|
||||
<Multipicker
|
||||
width="100%"
|
||||
manualEntry
|
||||
|
@ -104,14 +105,14 @@ export default class HostSelect extends Component<Props, State> {
|
|||
{
|
||||
dynamicSwitch ?
|
||||
<span>
|
||||
<a onClick={() => { this.handleDynamicSelect('=all'); }}>全选</a>
|
||||
<a onClick={() => { this.handleDynamicSelect('=all'); }}><FormattedMessage id="select.all" /></a>
|
||||
<span className="ant-divider" />
|
||||
<Popover
|
||||
trigger="click"
|
||||
content={
|
||||
<div style={{ width: 200 }}>
|
||||
<Input
|
||||
placeholder="请输入关键词,Enter键提交"
|
||||
placeholder="Press enter to submit"
|
||||
onKeyDown={(e: any) => {
|
||||
if (e.keyCode === 13) {
|
||||
this.handleDynamicSelect('=+', e.target.value);
|
||||
|
@ -120,9 +121,8 @@ export default class HostSelect extends Component<Props, State> {
|
|||
/>
|
||||
</div>
|
||||
}
|
||||
title="包含"
|
||||
>
|
||||
<a>包含</a>
|
||||
<a><FormattedMessage id="select.include" /></a>
|
||||
</Popover>
|
||||
<span className="ant-divider" />
|
||||
<Popover
|
||||
|
@ -130,7 +130,7 @@ export default class HostSelect extends Component<Props, State> {
|
|||
content={
|
||||
<div style={{ width: 200 }}>
|
||||
<Input
|
||||
placeholder="请输入关键词,Enter键提交"
|
||||
placeholder="Press enter to submit"
|
||||
onKeyDown={(e: any) => {
|
||||
if (e.keyCode === 13) {
|
||||
this.handleDynamicSelect('=-', e.target.value);
|
||||
|
@ -139,20 +139,19 @@ export default class HostSelect extends Component<Props, State> {
|
|||
/>
|
||||
</div>
|
||||
}
|
||||
title="排除"
|
||||
>
|
||||
<a>排除</a>
|
||||
<a><FormattedMessage id="select.exclude" /></a>
|
||||
</Popover>
|
||||
</span> :
|
||||
<div>
|
||||
动态值 <Switch onChange={this.handleDynamicSwitchChange} size="small" />
|
||||
<FormattedMessage id="select.dynamic" /> <Switch onChange={this.handleDynamicSwitchChange} size="small" />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
{
|
||||
reloadBtnVisible ?
|
||||
<div style={{ position: 'absolute', bottom: 3, right: 5 }}>
|
||||
<Button type="primary" onClick={this.handleReloadBtnClick}>更新图表</Button>
|
||||
<Button type="primary" onClick={this.handleReloadBtnClick}><FormattedMessage id="graph.machine.list.update" /></Button>
|
||||
</div> : null
|
||||
}
|
||||
</Card>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl';
|
||||
import { Card, Input, Tabs, Tooltip, Spin } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import moment from 'moment';
|
||||
|
@ -51,7 +52,7 @@ function getSelectedMetricsLen(metric: string, graphs: GraphData[]) {
|
|||
return null;
|
||||
}
|
||||
|
||||
export default class MetricSelect extends Component<Props, State> {
|
||||
class MetricSelect extends Component<Props & WrappedComponentProps, State> {
|
||||
static defaultProps = {
|
||||
nid: undefined,
|
||||
hosts: [],
|
||||
|
@ -152,18 +153,18 @@ export default class MetricSelect extends Component<Props, State> {
|
|||
key={`${metricTabKey}_${metric}`}
|
||||
placement="right"
|
||||
visible={this.state.metricTipVisible[`${metricTabKey}_${metric}`]}
|
||||
title={() => {
|
||||
const currentMetricMeta = getCurrentMetricMeta(metric);
|
||||
if (currentMetricMeta) {
|
||||
return (
|
||||
<div>
|
||||
<p>含义:{currentMetricMeta.meaning}</p>
|
||||
<p>单位:{currentMetricMeta.unit}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return '';
|
||||
}}
|
||||
// title={() => {
|
||||
// const currentMetricMeta = getCurrentMetricMeta(metric);
|
||||
// if (currentMetricMeta) {
|
||||
// return (
|
||||
// <div>
|
||||
// <p>含义:{currentMetricMeta.meaning}</p>
|
||||
// <p>单位:{currentMetricMeta.unit}</p>
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
// return '';
|
||||
// }}
|
||||
onVisibleChange={(visible) => {
|
||||
const key = `${metricTabKey}_${metric}`;
|
||||
const currentMetricMeta = getCurrentMetricMeta(metric);
|
||||
|
@ -186,7 +187,7 @@ export default class MetricSelect extends Component<Props, State> {
|
|||
})
|
||||
}
|
||||
</ul> :
|
||||
<div style={{ textAlign: 'center' }}>暂无数据</div>
|
||||
<div style={{ textAlign: 'center' }}>No data</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
|
@ -209,14 +210,15 @@ export default class MetricSelect extends Component<Props, State> {
|
|||
|
||||
const newMetricMap = this.dynamicMetricMaps();
|
||||
const tabPanes = _.map(newMetricMap, (val) => {
|
||||
const tabName = this.props.intl.locale == 'zh' ? val.alias : val.key;
|
||||
return (
|
||||
<TabPane tab={val.alias} key={val.key}>
|
||||
<TabPane tab={tabName} key={val.key}>
|
||||
{ this.renderMetricList(newMetrics, val.key) }
|
||||
</TabPane>
|
||||
);
|
||||
});
|
||||
tabPanes.unshift(
|
||||
<TabPane tab="全部" key="ALL">
|
||||
<TabPane tab={<FormattedMessage id="graph.metric.list.all" />} key="ALL">
|
||||
{ this.renderMetricList(newMetrics, 'ALL') }
|
||||
</TabPane>,
|
||||
);
|
||||
|
@ -239,10 +241,10 @@ export default class MetricSelect extends Component<Props, State> {
|
|||
className={`${prefixCls}-card`}
|
||||
title={
|
||||
<span className={`${prefixCls}-metrics-title`}>
|
||||
<span>指标列表</span>
|
||||
<span><FormattedMessage id="graph.metric.list.title" /></span>
|
||||
<Input
|
||||
size="small"
|
||||
placeholder="搜索指标"
|
||||
placeholder="Search"
|
||||
onChange={this.handleMetricsSearch}
|
||||
/>
|
||||
</span>
|
||||
|
@ -254,3 +256,5 @@ export default class MetricSelect extends Component<Props, State> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default injectIntl(MetricSelect);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl';
|
||||
import { Modal, Form, TreeSelect, Select, message } from 'antd';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
import _ from 'lodash';
|
||||
|
@ -27,9 +28,9 @@ interface State {
|
|||
|
||||
const FormItem = Form.Item;
|
||||
const { Option } = Select;
|
||||
class SubscribeModal extends Component<Props & FormProps, State> {
|
||||
static defaultProps = {
|
||||
title: '订阅到大盘',
|
||||
class SubscribeModal extends Component<Props & FormProps & WrappedComponentProps, State> {
|
||||
static defaultProps: any = {
|
||||
title: '',
|
||||
visible: true,
|
||||
onOk: _.noop,
|
||||
onCancel: _.noop,
|
||||
|
@ -95,7 +96,7 @@ class SubscribeModal extends Component<Props & FormProps, State> {
|
|||
});
|
||||
}),
|
||||
);
|
||||
message.success('图表订阅成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'graph.subscribe.success' }));
|
||||
this.props.onOk();
|
||||
this.props.destroy();
|
||||
} catch (e) {
|
||||
|
@ -121,15 +122,15 @@ class SubscribeModal extends Component<Props & FormProps, State> {
|
|||
onOk={this.handleOk}
|
||||
onCancel={this.handleCancel}
|
||||
bodyStyle={{ padding: 14 }}
|
||||
okText="订阅"
|
||||
okText={<FormattedMessage id="graph.subscribe" />}
|
||||
>
|
||||
<Form layout="vertical" onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
this.handleOk();
|
||||
}}>
|
||||
<FormItem label="所属节点">
|
||||
<FormItem label={<FormattedMessage id="graph.subscribe.node" />}>
|
||||
{getFieldDecorator('nid', {
|
||||
rules: [{ required: true, message: '请选择所属节点!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<TreeSelect
|
||||
showSearch
|
||||
|
@ -143,9 +144,9 @@ class SubscribeModal extends Component<Props & FormProps, State> {
|
|||
</TreeSelect>,
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem label="选择大盘">
|
||||
<FormItem label={<FormattedMessage id="graph.subscribe.screen" />}>
|
||||
{getFieldDecorator('scrrenId', {
|
||||
rules: [{ required: true, message: '请选择所属大盘!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<Select
|
||||
onDropdownVisibleChange={(dropdownVisible) => {
|
||||
|
@ -162,9 +163,9 @@ class SubscribeModal extends Component<Props & FormProps, State> {
|
|||
</Select>,
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem label="选择分类">
|
||||
<FormItem label={<FormattedMessage id="graph.subscribe.tag" />}>
|
||||
{getFieldDecorator('subclassId', {
|
||||
rules: [{ required: true, message: '请选择所属分类!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<Select
|
||||
onDropdownVisibleChange={(dropdownVisible) => {
|
||||
|
@ -187,4 +188,4 @@ class SubscribeModal extends Component<Props & FormProps, State> {
|
|||
}
|
||||
}
|
||||
|
||||
export default ModalControl(Form.create()(SubscribeModal));
|
||||
export default ModalControl(Form.create()(injectIntl(SubscribeModal)));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl';
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import update from 'react-addons-update';
|
||||
|
@ -39,7 +40,7 @@ interface State {
|
|||
|
||||
const { Content } = Layout;
|
||||
|
||||
class MonitorDashboard extends Component<Props, State> {
|
||||
class MonitorDashboard extends Component<Props & WrappedComponentProps, State> {
|
||||
metricSelect: any;
|
||||
static contextTypes = {
|
||||
nsTreeVisibleChange: PropTypes.func,
|
||||
|
@ -52,7 +53,7 @@ class MonitorDashboard extends Component<Props, State> {
|
|||
onceLoad = false;
|
||||
sidebarWidth = 200;
|
||||
|
||||
constructor(props: Props) {
|
||||
constructor(props: Props & WrappedComponentProps) {
|
||||
super(props);
|
||||
const now = moment();
|
||||
this.state = {
|
||||
|
@ -264,6 +265,8 @@ class MonitorDashboard extends Component<Props, State> {
|
|||
return JSON.stringify(data);
|
||||
});
|
||||
SubscribeModal({
|
||||
title: <FormattedMessage id="graph.subscribe" />,
|
||||
language: this.props.intl.locale,
|
||||
configsList,
|
||||
});
|
||||
}
|
||||
|
@ -301,7 +304,7 @@ class MonitorDashboard extends Component<Props, State> {
|
|||
if (!this.allHostsMode && !selectedTreeNode) {
|
||||
return (
|
||||
<div>
|
||||
请选择节点
|
||||
<FormattedMessage id="please.select.node" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -364,21 +367,21 @@ class MonitorDashboard extends Component<Props, State> {
|
|||
disabled={!graphs.length}
|
||||
style={{ background: '#fff', marginRight: 8 }}
|
||||
>
|
||||
订阅图表
|
||||
<FormattedMessage id="graph.subscribe" />
|
||||
</Button>
|
||||
<Button
|
||||
onClick={this.handleShareGraphs}
|
||||
disabled={!graphs.length}
|
||||
style={{ background: '#fff', marginRight: 8 }}
|
||||
>
|
||||
分享图表
|
||||
<FormattedMessage id="graph.share" />
|
||||
</Button>
|
||||
<Button
|
||||
onClick={this.handleRemoveGraphs}
|
||||
disabled={!graphs.length}
|
||||
style={{ background: '#fff' }}
|
||||
>
|
||||
清空图表
|
||||
<FormattedMessage id="graph.clear" />
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
|
@ -394,4 +397,4 @@ class MonitorDashboard extends Component<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
export default CreateIncludeNsTree(MonitorDashboard as any, { visible: true });
|
||||
export default CreateIncludeNsTree(injectIntl(MonitorDashboard), { visible: true });
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl';
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import { Card, Table, Divider, Popconfirm, Icon, message } from 'antd';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
@ -22,7 +23,7 @@ export function normalizeGraphData(data: any) {
|
|||
});
|
||||
return cloneData;
|
||||
}
|
||||
class Detail extends Component<RouteComponentProps> {
|
||||
class Detail extends Component<RouteComponentProps & WrappedComponentProps> {
|
||||
state: {
|
||||
loading: boolean,
|
||||
data: any,
|
||||
|
@ -176,7 +177,7 @@ class Detail extends Component<RouteComponentProps> {
|
|||
</div>
|
||||
<div className={`${nPrefixCls}-detail mt10`}>
|
||||
<Card
|
||||
title="报警事件详情"
|
||||
title={<FormattedMessage id="event.table.detail.title" />}
|
||||
bodyStyle={{
|
||||
padding: '10px 16px',
|
||||
}}
|
||||
|
@ -186,14 +187,14 @@ class Detail extends Component<RouteComponentProps> {
|
|||
pathname: '/monitor/silence/add',
|
||||
search: `${historyType}=${historyId}&nid=${nid}`,
|
||||
}}>
|
||||
屏蔽
|
||||
<FormattedMessage id="event.table.shield" />
|
||||
</Link>
|
||||
{
|
||||
historyType === 'cur' ?
|
||||
<span>
|
||||
<Divider type="vertical" />
|
||||
<Popconfirm title="确定要认领这条报警吗?" onConfirm={() => this.handleClaim(historyId)}>
|
||||
<a>认领</a>
|
||||
<Popconfirm title={<FormattedMessage id="event.table.claim.sure" />} onConfirm={() => this.handleClaim(historyId)}>
|
||||
<a><FormattedMessage id="event.table.claim" /></a>
|
||||
</Popconfirm>
|
||||
</span> : null
|
||||
}
|
||||
|
@ -202,47 +203,47 @@ class Detail extends Component<RouteComponentProps> {
|
|||
>
|
||||
<div className={`${nPrefixCls}-detail-list`}>
|
||||
<div>
|
||||
<span className="label">策略名称:</span>
|
||||
<span className="label"><FormattedMessage id="event.table.stra" />:</span>
|
||||
<Link target="_blank" to={{ pathname: `/monitor/strategy/${data.sid}` }}>{data.sname}</Link>
|
||||
</div>
|
||||
<div>
|
||||
<span className="label">报警状态:</span>
|
||||
<span className="label"><FormattedMessage id="event.table.status" />:</span>
|
||||
{_.get(_.find(priorityOptions, { value: data.priority }), 'label')}
|
||||
<span style={{ paddingLeft: 8 }}>{_.get(_.find(eventTypeOptions, { value: data.event_type }), 'label')}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="label">通知结果:</span>
|
||||
<span className="label"><FormattedMessage id="event.table.notify" />:</span>
|
||||
{_.join(data.status, ', ')}
|
||||
</div>
|
||||
<div>
|
||||
<span className="label">发生时间:</span>
|
||||
<span className="label"><FormattedMessage id="event.table.time" />:</span>
|
||||
{moment.unix(data.etime).format('YYYY-MM-DD HH:mm:ss')}
|
||||
</div>
|
||||
<div>
|
||||
<span className="label">节点:</span>
|
||||
<span className="label"><FormattedMessage id="event.table.node" />:</span>
|
||||
{data.node_path}
|
||||
</div>
|
||||
<div>
|
||||
<span className="label">endpoint:</span>
|
||||
<span className="label">Endpoint:</span>
|
||||
{data.endpoint}
|
||||
</div>
|
||||
<div>
|
||||
<span className="label">指标:</span>
|
||||
<span className="label"><FormattedMessage id="event.table.metric" />:</span>
|
||||
{_.get(data.detail, '[0].metric')}
|
||||
</div>
|
||||
<div>
|
||||
<span className="label">tags:</span>
|
||||
<span className="label">Tags:</span>
|
||||
{data.tags}
|
||||
</div>
|
||||
<div>
|
||||
<span className="label">表达式:</span>
|
||||
<span className="label"><FormattedMessage id="event.table.expression" />:</span>
|
||||
{data.info}
|
||||
</div>
|
||||
{
|
||||
_.map(points, (item) => {
|
||||
return (
|
||||
<div>
|
||||
<div className="label">现场值:</div>
|
||||
<div className="label"><FormattedMessage id="event.table.scene" />:</div>
|
||||
{item.metric}
|
||||
<Table
|
||||
style={{
|
||||
|
@ -254,14 +255,14 @@ class Detail extends Component<RouteComponentProps> {
|
|||
dataSource={item.points}
|
||||
columns={[
|
||||
{
|
||||
title: '时间',
|
||||
title: <FormattedMessage id="event.table.scene.time" />,
|
||||
dataIndex: 'timestamp',
|
||||
width: 200,
|
||||
render(text) {
|
||||
return <span>{moment.unix(text).format('YYYY-MM-DD HH:mm:ss')}</span>;
|
||||
},
|
||||
}, {
|
||||
title: '数值',
|
||||
title: <FormattedMessage id="event.table.scene.value" />,
|
||||
dataIndex: 'value',
|
||||
},
|
||||
]}
|
||||
|
@ -279,4 +280,4 @@ class Detail extends Component<RouteComponentProps> {
|
|||
}
|
||||
}
|
||||
|
||||
export default CreateIncludeNsTree(Detail as any);
|
||||
export default CreateIncludeNsTree(injectIntl(Detail));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Row, Col, Select, Input, DatePicker, Tag, Divider, message, Popconfirm, Badge, Button } from 'antd';
|
||||
import { ColumnProps } from 'antd/lib/table';
|
||||
|
@ -33,14 +34,14 @@ const nPrefixCls = `${prefixCls}-history`;
|
|||
const { Option } = Select;
|
||||
const { Search } = Input;
|
||||
|
||||
export default class index extends Component<Props, State> {
|
||||
class index extends Component<Props & WrappedComponentProps, State> {
|
||||
static defaultProps = {
|
||||
nodepath: undefined,
|
||||
nid: undefined,
|
||||
};
|
||||
fetchTable: any;
|
||||
otherParamsKey: string[];
|
||||
constructor(props: Props) {
|
||||
constructor(props: Props & WrappedComponentProps) {
|
||||
super(props);
|
||||
const now = moment();
|
||||
if (props.type === 'alert') {
|
||||
|
@ -138,7 +139,7 @@ export default class index extends Component<Props, State> {
|
|||
getColumns() {
|
||||
const columns: ColumnProps<DataItem>[] = [
|
||||
{
|
||||
title: '发生时间',
|
||||
title: <FormattedMessage id="event.table.time" />,
|
||||
dataIndex: 'etime',
|
||||
fixed: 'left',
|
||||
width: 100,
|
||||
|
@ -146,12 +147,12 @@ export default class index extends Component<Props, State> {
|
|||
return moment.unix(text).format('YYYY-MM-DD HH:mm:ss');
|
||||
},
|
||||
}, {
|
||||
title: '策略名称',
|
||||
title: <FormattedMessage id="event.table.stra" />,
|
||||
dataIndex: 'sname',
|
||||
width: 100,
|
||||
fixed: 'left',
|
||||
}, {
|
||||
title: '级别',
|
||||
title: <FormattedMessage id="event.table.priority" />,
|
||||
dataIndex: 'priority',
|
||||
width: 50,
|
||||
render: (text) => {
|
||||
|
@ -169,7 +170,7 @@ export default class index extends Component<Props, State> {
|
|||
title: 'tags',
|
||||
dataIndex: 'tags',
|
||||
}, {
|
||||
title: '通知结果',
|
||||
title: <FormattedMessage id="event.table.notify" />,
|
||||
dataIndex: 'status',
|
||||
fixed: 'right',
|
||||
width: 70,
|
||||
|
@ -177,9 +178,10 @@ export default class index extends Component<Props, State> {
|
|||
return _.join(text, ', ');
|
||||
},
|
||||
}, {
|
||||
title: '操作',
|
||||
title: <FormattedMessage id="table.operations" />,
|
||||
fixed: 'right',
|
||||
width: this.props.type === 'alert' ? 165 : 90,
|
||||
// width: this.props.type === 'alert' ? 100 : 90,
|
||||
width: this.props.intl.locale === 'zh' ? 100 : 130,
|
||||
render: (text, record) => {
|
||||
return (
|
||||
<span>
|
||||
|
@ -189,18 +191,18 @@ export default class index extends Component<Props, State> {
|
|||
}}
|
||||
target="_blank"
|
||||
>
|
||||
详情
|
||||
<FormattedMessage id="table.detail" />
|
||||
</Link>
|
||||
{
|
||||
this.props.type === 'alert' ?
|
||||
<span>
|
||||
<Divider type="vertical" />
|
||||
<Popconfirm title="确定要忽略这条报警吗?" onConfirm={() => this.handleDelete(record.id)}>
|
||||
<a>忽略</a>
|
||||
<Popconfirm title={<FormattedMessage id="event.table.ignore.sure" />} onConfirm={() => this.handleDelete(record.id)}>
|
||||
<a><FormattedMessage id="event.table.ignore" /></a>
|
||||
</Popconfirm>
|
||||
<Divider type="vertical" />
|
||||
<Popconfirm title="确定要认领这条报警吗?" onConfirm={() => this.handleClaim(record.id)}>
|
||||
<a>认领</a>
|
||||
<Popconfirm title={<FormattedMessage id="event.table.claim.sure" />} onConfirm={() => this.handleClaim(record.id)}>
|
||||
<a><FormattedMessage id="event.table.claim" /></a>
|
||||
</Popconfirm>
|
||||
</span> : null
|
||||
}
|
||||
|
@ -212,7 +214,7 @@ export default class index extends Component<Props, State> {
|
|||
}}
|
||||
target="_blank"
|
||||
>
|
||||
屏蔽
|
||||
<FormattedMessage id="event.table.shield" />
|
||||
</Link>
|
||||
</span>
|
||||
);
|
||||
|
@ -221,7 +223,7 @@ export default class index extends Component<Props, State> {
|
|||
];
|
||||
if (this.props.type === 'alert') {
|
||||
columns.splice(5, 0, {
|
||||
title: '认领人',
|
||||
title: <FormattedMessage id="event.table.assignees" />,
|
||||
dataIndex: 'claimants',
|
||||
width: 50,
|
||||
fixed: 'right',
|
||||
|
@ -232,7 +234,7 @@ export default class index extends Component<Props, State> {
|
|||
}
|
||||
if (this.props.type === 'all') {
|
||||
columns.splice(3, 0, {
|
||||
title: '状态',
|
||||
title: <FormattedMessage id="event.table.status" />,
|
||||
dataIndex: 'event_type',
|
||||
width: 70,
|
||||
render: (text) => {
|
||||
|
@ -240,7 +242,7 @@ export default class index extends Component<Props, State> {
|
|||
return (
|
||||
<span style={{ color: eventTypeObj.color }}>
|
||||
<Badge status={eventTypeObj.status} />
|
||||
{eventTypeObj.label}
|
||||
<FormattedMessage id={`event.table.status.${eventTypeObj.value}`} />
|
||||
</span>
|
||||
);
|
||||
},
|
||||
|
@ -276,7 +278,7 @@ export default class index extends Component<Props, State> {
|
|||
>
|
||||
{
|
||||
_.map(timeOptions, (option) => {
|
||||
return <Option key={option.value} value={option.value}>{option.label}</Option>;
|
||||
return <Option key={option.value} value={option.value}><FormattedMessage id={option.label} /></Option>;
|
||||
})
|
||||
}
|
||||
</Select>
|
||||
|
@ -317,7 +319,7 @@ export default class index extends Component<Props, State> {
|
|||
this.props.type === 'all' ?
|
||||
<Select
|
||||
style={{ minWidth: 90, marginRight: 8 }}
|
||||
placeholder="报警状态"
|
||||
placeholder={this.props.intl.formatMessage({ id: 'event.table.status' })}
|
||||
allowClear
|
||||
value={type}
|
||||
onChange={(value: string) => {
|
||||
|
@ -330,14 +332,14 @@ export default class index extends Component<Props, State> {
|
|||
>
|
||||
{
|
||||
_.map(eventTypeOptions, (option) => {
|
||||
return <Option key={option.value} value={option.value}>{option.label}</Option>;
|
||||
return <Option key={option.value} value={option.value}><FormattedMessage id={`event.table.status.${option.value}`} /></Option>;
|
||||
})
|
||||
}
|
||||
</Select> : null
|
||||
}
|
||||
<Select
|
||||
style={{ minWidth: 90, marginRight: 8 }}
|
||||
placeholder="报警级别"
|
||||
placeholder={this.props.intl.formatMessage({ id: 'event.table.priority' })}
|
||||
allowClear
|
||||
mode="multiple"
|
||||
value={priorities ? _.map(_.split(priorities, ','), _.toNumber) : []}
|
||||
|
@ -366,8 +368,8 @@ export default class index extends Component<Props, State> {
|
|||
<Col span={6} style={{ textAlign: 'right' }}>
|
||||
{
|
||||
this.props.type === 'alert' ?
|
||||
<Popconfirm title="确定认领该节点下所有未恢复的报警吗?" onConfirm={() => this.handleClaimAll()}>
|
||||
<Button>一健认领</Button>
|
||||
<Popconfirm title={<FormattedMessage id="event.table.claim.all.sure" />} onConfirm={() => this.handleClaimAll()}>
|
||||
<Button><FormattedMessage id="event.table.claim.all" /></Button>
|
||||
</Popconfirm> : null
|
||||
}
|
||||
</Col>
|
||||
|
@ -388,3 +390,5 @@ export default class index extends Component<Props, State> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default injectIntl(index);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Tabs } from 'antd';
|
||||
import _ from 'lodash';
|
||||
|
@ -36,10 +37,10 @@ class index extends Component {
|
|||
this.setState({ activeKey });
|
||||
}}
|
||||
>
|
||||
<TabPane tab="未恢复报警" key="alert">
|
||||
<TabPane tab={<FormattedMessage id="event.tab.alert" />} key="alert">
|
||||
<List nodepath={this.state.nodepath} nid={this.state.nid} type="alert" activeKey={this.state.activeKey} />
|
||||
</TabPane>
|
||||
<TabPane tab="所有历史报警" key="all">
|
||||
<TabPane tab={<FormattedMessage id="event.tab.all" />} key="all">
|
||||
<List nodepath={this.state.nodepath} nid={this.state.nid} type="all" activeKey={this.state.activeKey} />
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
}
|
||||
.label {
|
||||
display: inline-block;
|
||||
width: 80px;
|
||||
width: 100px;
|
||||
text-align: right;
|
||||
}
|
||||
.ant-table-wrapper {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Modal, Form, Input } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
|
@ -51,9 +52,9 @@ class AddModal extends Component<Props & FormProps> {
|
|||
e.preventDefault();
|
||||
this.handleOk();
|
||||
}}>
|
||||
<FormItem label="名称">
|
||||
<FormItem label={<FormattedMessage id="table.name" />}>
|
||||
{getFieldDecorator('name', {
|
||||
rules: [{ required: true, message: '请填写大盘名称!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<Input />,
|
||||
)}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Modal, Form, Input } from 'antd';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
import _ from 'lodash';
|
||||
|
@ -52,10 +53,10 @@ class ModifyModal extends Component<Props & FormProps> {
|
|||
e.preventDefault();
|
||||
this.handleOk();
|
||||
}}>
|
||||
<FormItem label="名称">
|
||||
<FormItem label={<FormattedMessage id="table.name" />}>
|
||||
{getFieldDecorator('name', {
|
||||
initialValue: this.props.name,
|
||||
rules: [{ required: true, message: '请填写大盘名称!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<Input />,
|
||||
)}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Modal, Form, Input } from 'antd';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
import _ from 'lodash';
|
||||
|
@ -51,9 +52,9 @@ class AddModal extends Component<Props> {
|
|||
e.preventDefault();
|
||||
this.handleOk();
|
||||
}}>
|
||||
<FormItem label="名称">
|
||||
<FormItem label={<FormattedMessage id="table.name" />}>
|
||||
{getFieldDecorator('name', {
|
||||
rules: [{ required: true, message: '请填写分类名称!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<Input />,
|
||||
)}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Modal, Form, TreeSelect, Select } from 'antd';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
import _ from 'lodash';
|
||||
|
@ -22,7 +23,7 @@ const { Option } = Select;
|
|||
|
||||
class BatchMoveSubclass extends Component<Props> {
|
||||
static defaultProps = {
|
||||
title: '批量移动分类',
|
||||
title: '',
|
||||
visible: true,
|
||||
onOk: _.noop,
|
||||
onCancel: _.noop,
|
||||
|
@ -58,7 +59,7 @@ class BatchMoveSubclass extends Component<Props> {
|
|||
|
||||
return (
|
||||
<Modal
|
||||
title={title}
|
||||
title={<FormattedMessage id="screen.tag.batch.modify" />}
|
||||
visible={visible}
|
||||
onOk={this.handleOk}
|
||||
onCancel={this.handleCancel}
|
||||
|
@ -67,9 +68,9 @@ class BatchMoveSubclass extends Component<Props> {
|
|||
e.preventDefault();
|
||||
this.handleOk();
|
||||
}}>
|
||||
<FormItem label="需要移动的分类">
|
||||
<FormItem label={<FormattedMessage id="screen.tag.batch.modify.tag" />}>
|
||||
{getFieldDecorator('subclasses', {
|
||||
rules: [{ required: true, message: '请选择分类!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<Select mode="multiple">
|
||||
{
|
||||
|
@ -80,9 +81,9 @@ class BatchMoveSubclass extends Component<Props> {
|
|||
</Select>,
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem label="将要移动到的节点">
|
||||
<FormItem label={<FormattedMessage id="screen.tag.batch.modify.target.node" />}>
|
||||
{getFieldDecorator('nid', {
|
||||
rules: [{ required: true, message: '请选择节点!' }],
|
||||
rules: [{ required: true }],
|
||||
onChange: this.handleSelectedTreeNodeIdChange,
|
||||
})(
|
||||
<TreeSelect
|
||||
|
@ -96,9 +97,9 @@ class BatchMoveSubclass extends Component<Props> {
|
|||
</TreeSelect>,
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem label="将要移动到的大盘">
|
||||
<FormItem label={<FormattedMessage id="screen.tag.batch.modify.target.screen" />}>
|
||||
{getFieldDecorator('screenId', {
|
||||
rules: [{ required: true, message: '请选择大盘!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<Select>
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Modal, Form, Input } from 'antd';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
import _ from 'lodash';
|
||||
|
@ -52,10 +53,10 @@ class ModifyModal extends Component<Props> {
|
|||
e.preventDefault();
|
||||
this.handleOk();
|
||||
}}>
|
||||
<FormItem label="名称">
|
||||
<FormItem label={<FormattedMessage id="table.name" />}>
|
||||
{getFieldDecorator('name', {
|
||||
initialValue: this.props.name,
|
||||
rules: [{ required: true, message: '请填写分类名称!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<Input />,
|
||||
)}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Popconfirm, Menu, Col } from 'antd';
|
||||
import { SortableElement } from 'react-sortable-hoc';
|
||||
import _ from 'lodash';
|
||||
|
@ -57,14 +58,14 @@ class RenderGraph extends Component<any> {
|
|||
}}
|
||||
extraMoreList={[
|
||||
<Menu.Item key="share">
|
||||
<a onClick={() => { this.handleShareGraph(data.configs); }}>分享图表</a>
|
||||
<a onClick={() => { this.handleShareGraph(data.configs); }}><FormattedMessage id="screen.graph.extraMoreList.share" /></a>
|
||||
</Menu.Item>,
|
||||
<Menu.Item key="clone">
|
||||
<a onClick={() => { this.handleCloneGraph(data.configs); }}>克隆图表</a>
|
||||
<a onClick={() => { this.handleCloneGraph(data.configs); }}><FormattedMessage id="screen.graph.extraMoreList.clone" /></a>
|
||||
</Menu.Item>,
|
||||
<Menu.Item key="del">
|
||||
<Popconfirm title="确定要删除这个图表吗?" onConfirm={() => { this.props.onDelChart(data.id); }}>
|
||||
<a>删除图表</a>
|
||||
<Popconfirm title={<FormattedMessage id="screen.graph.extraMoreList.delete.sure" />} onConfirm={() => { this.props.onDelChart(data.id); }}>
|
||||
<a><FormattedMessage id="screen.graph.extraMoreList.delete" /></a>
|
||||
</Popconfirm>
|
||||
</Menu.Item>,
|
||||
]}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl';
|
||||
import { Button, Card, Divider, Popconfirm, message, Row, Col, Select, Checkbox } from 'antd';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
import moment from 'moment';
|
||||
|
@ -37,7 +38,7 @@ function updateTime(nowMoment: moment.Moment, graphConfig: any) {
|
|||
|
||||
const COUNTDOWN = 9; // 0 ~ 9
|
||||
|
||||
class ScreenDetail extends Component<FormProps> {
|
||||
class ScreenDetail extends Component<FormProps & WrappedComponentProps> {
|
||||
timer: NodeJS.Timeout | undefined = undefined;
|
||||
state = {
|
||||
subclassLoading: false,
|
||||
|
@ -398,30 +399,30 @@ class ScreenDetail extends Component<FormProps> {
|
|||
<a onClick={() => {
|
||||
if (this.graphConfigForm) {
|
||||
this.currentSubclassId = subclassObj.id;
|
||||
this.graphConfigForm.showModal('push', '新增');
|
||||
this.graphConfigForm.showModal('push', this.props.intl.formatMessage({ id: 'table.create' }));
|
||||
}
|
||||
}}>
|
||||
新增图表
|
||||
<FormattedMessage id="screen.tag.graph.add" />
|
||||
</a>
|
||||
<Divider type="vertical" />
|
||||
<a onClick={() => this.handleModSubclass(subclassObj)}>修改</a>
|
||||
<a onClick={() => this.handleModSubclass(subclassObj)}><FormattedMessage id="table.modify" /></a>
|
||||
<Divider type="vertical" />
|
||||
<Popconfirm title="确认要删除这个分类吗?" onConfirm={() => this.handleDelSubclass(subclassObj.id)}>
|
||||
<a>删除</a>
|
||||
<Popconfirm title={<FormattedMessage id="table.delete.sure" />} onConfirm={() => this.handleDelSubclass(subclassObj.id)}>
|
||||
<a><FormattedMessage id="table.delete" /></a>
|
||||
</Popconfirm>
|
||||
<Divider type="vertical" />
|
||||
<a
|
||||
disabled={idx === 0}
|
||||
onClick={() => this.handleMoveSubclass('up', idx)}
|
||||
>
|
||||
上移
|
||||
<FormattedMessage id="screen.tag.up" />
|
||||
</a>
|
||||
<Divider type="vertical" />
|
||||
<a
|
||||
disabled={idx === subclassData.length - 1}
|
||||
onClick={() => this.handleMoveSubclass('down', idx)}
|
||||
>
|
||||
下移
|
||||
<FormattedMessage id="screen.tag.down" />
|
||||
</a>
|
||||
</span>
|
||||
}
|
||||
|
@ -481,7 +482,7 @@ class ScreenDetail extends Component<FormProps> {
|
|||
}}
|
||||
onCloneGraph={(configs: any) => {
|
||||
this.currentSubclassId = subclassObj.id;
|
||||
this.graphConfigForm.showModal('push', '克隆图表', {
|
||||
this.graphConfigForm.showModal('push', this.props.intl.formatMessage({ id: 'table.create' }), {
|
||||
...configs,
|
||||
});
|
||||
}}
|
||||
|
@ -502,12 +503,12 @@ class ScreenDetail extends Component<FormProps> {
|
|||
<div>
|
||||
<Row className="mb10">
|
||||
<Col span={6}>
|
||||
<Button onClick={this.handleAddSubclass} style={{ marginRight: 8 }}>新增分类</Button>
|
||||
<Button onClick={this.handleBatchMoveSubclass}>批量移动分类</Button>
|
||||
<Button onClick={this.handleAddSubclass} style={{ marginRight: 8 }}><FormattedMessage id="screen.tag.add" /></Button>
|
||||
<Button onClick={this.handleBatchMoveSubclass}><FormattedMessage id="screen.tag.batch.modify" /></Button>
|
||||
</Col>
|
||||
<Col span={18} className="textAlignRight">
|
||||
<span style={{ paddingRight: 10 }}>
|
||||
时间:
|
||||
<FormattedMessage id="graph.config.time" />:
|
||||
<Select size="default" style={
|
||||
timeVal === 'custom' ?
|
||||
{
|
||||
|
@ -517,12 +518,12 @@ class ScreenDetail extends Component<FormProps> {
|
|||
width: 80,
|
||||
}
|
||||
}
|
||||
placeholder="无"
|
||||
// placeholder="无"
|
||||
value={timeVal}
|
||||
onChange={this.handleTimeOptionChange}
|
||||
>
|
||||
{
|
||||
_.map(graphcConfig.time, o => <Option key={o.value} value={o.value}>{o.label}</Option>)
|
||||
_.map(graphcConfig.time, o => <Option key={o.value} value={o.value}><FormattedMessage id={o.label} /></Option>)
|
||||
}
|
||||
</Select>
|
||||
{
|
||||
|
@ -566,7 +567,7 @@ class ScreenDetail extends Component<FormProps> {
|
|||
});
|
||||
}}
|
||||
>
|
||||
自动刷新 { this.state.autoRefresh ? `(${this.state.countdown})` : '' }
|
||||
<FormattedMessage id="screen.auto.refresh" /> { this.state.autoRefresh ? `(${this.state.countdown})` : '' }
|
||||
</Checkbox>
|
||||
<Select
|
||||
style={{ width: 70 }}
|
||||
|
@ -577,10 +578,10 @@ class ScreenDetail extends Component<FormProps> {
|
|||
});
|
||||
}}
|
||||
>
|
||||
<Option key="1" value={1}>1列</Option>
|
||||
<Option key="2" value={2}>2列</Option>
|
||||
<Option key="3" value={3}>3列</Option>
|
||||
<Option key="4" value={4}>4列</Option>
|
||||
<Option key="1" value={1}>1 <FormattedMessage id="screen.col" /></Option>
|
||||
<Option key="2" value={2}>2 <FormattedMessage id="screen.col" /></Option>
|
||||
<Option key="3" value={3}>3 <FormattedMessage id="screen.col" /></Option>
|
||||
<Option key="4" value={4}>4 <FormattedMessage id="screen.col" /></Option>
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
|
@ -600,4 +601,4 @@ class ScreenDetail extends Component<FormProps> {
|
|||
}
|
||||
}
|
||||
|
||||
export default CreateIncludeNsTree(ScreenDetail);
|
||||
export default CreateIncludeNsTree(injectIntl(ScreenDetail));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { FormattedMessage, WrappedComponentProps, injectIntl } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Button, Input, Divider, Popconfirm, Table, message } from 'antd';
|
||||
|
@ -89,7 +90,7 @@ const DragableBodyRow = DropTarget(
|
|||
)(BodyRow),
|
||||
);
|
||||
|
||||
class Screen extends Component {
|
||||
class Screen extends Component<WrappedComponentProps> {
|
||||
static contextTypes = {
|
||||
getSelectedNode: PropTypes.func,
|
||||
};
|
||||
|
@ -137,7 +138,8 @@ class Screen extends Component {
|
|||
|
||||
handleAdd = () => {
|
||||
AddModal({
|
||||
title: '新增大盘',
|
||||
language: this.props.intl.locale,
|
||||
title: this.props.intl.formatMessage({ id: 'table.create' }),
|
||||
onOk: (values: any) => {
|
||||
request(`${api.node}/${this.selectedNodeId}/screen`, {
|
||||
method: 'POST',
|
||||
|
@ -155,8 +157,9 @@ class Screen extends Component {
|
|||
|
||||
handleModify = (record: any) => {
|
||||
ModifyModal({
|
||||
language: this.props.intl.locale,
|
||||
name: record.name,
|
||||
title: '修改大盘',
|
||||
title: this.props.intl.formatMessage({ id: 'table.modify' }),
|
||||
onOk: (values: any) => {
|
||||
request(`${api.screen}/${record.id}`, {
|
||||
method: 'PUT',
|
||||
|
@ -165,7 +168,7 @@ class Screen extends Component {
|
|||
node_id: record.node_id,
|
||||
}),
|
||||
}).then(() => {
|
||||
message.success('修改大盘成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.modify.success' }));
|
||||
this.fetchData();
|
||||
});
|
||||
},
|
||||
|
@ -176,7 +179,7 @@ class Screen extends Component {
|
|||
request(`${api.screen}/${id}`, {
|
||||
method: 'DELETE',
|
||||
}).then(() => {
|
||||
message.success('删除大盘成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.delete.success' }));
|
||||
this.fetchData();
|
||||
});
|
||||
}
|
||||
|
@ -193,7 +196,7 @@ class Screen extends Component {
|
|||
},
|
||||
}),
|
||||
() => {
|
||||
const reqBody = _.map(this.state.data, (item, i) => {
|
||||
const reqBody = _.map(this.state.data, (item: any, i) => {
|
||||
return {
|
||||
id: item.id,
|
||||
weight: i,
|
||||
|
@ -203,7 +206,7 @@ class Screen extends Component {
|
|||
method: 'PUT',
|
||||
body: JSON.stringify(reqBody),
|
||||
}).then(() => {
|
||||
message.success('大盘排序成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.sort.success' }));
|
||||
});
|
||||
},
|
||||
);
|
||||
|
@ -212,7 +215,7 @@ class Screen extends Component {
|
|||
filterData() {
|
||||
const { data, search } = this.state;
|
||||
if (search) {
|
||||
return _.filter(data, (item) => {
|
||||
return _.filter(data, (item: any) => {
|
||||
return item.name.indexOf(search) > -1;
|
||||
});
|
||||
}
|
||||
|
@ -226,10 +229,10 @@ class Screen extends Component {
|
|||
return (
|
||||
<div className={prefixCls}>
|
||||
<div className="mb10">
|
||||
<Button className="mr10" onClick={this.handleAdd}>新增大盘</Button>
|
||||
<Button className="mr10" onClick={this.handleAdd}><FormattedMessage id="screen.create" /></Button>
|
||||
<Input
|
||||
style={{ width: 200 }}
|
||||
placeholder="搜索"
|
||||
placeholder="Search"
|
||||
value={search}
|
||||
onChange={(e) => {
|
||||
this.setState({ search: e.target.value });
|
||||
|
@ -251,25 +254,25 @@ class Screen extends Component {
|
|||
})}
|
||||
columns={[
|
||||
{
|
||||
title: '名称',
|
||||
title: <FormattedMessage id="table.name" />,
|
||||
dataIndex: 'name',
|
||||
render: (text, record) => {
|
||||
return <Link to={{ pathname: `/monitor/screen/${record.id}` }}>{text}</Link>;
|
||||
},
|
||||
}, {
|
||||
title: '创建人',
|
||||
title: <FormattedMessage id="table.creator" />,
|
||||
width: 200,
|
||||
dataIndex: 'last_updator',
|
||||
}, {
|
||||
title: '操作',
|
||||
title: <FormattedMessage id="table.operations" />,
|
||||
width: 200,
|
||||
render: (text, record) => {
|
||||
render: (text, record: any) => {
|
||||
return (
|
||||
<span>
|
||||
<a onClick={() => this.handleModify(record)}>修改</a>
|
||||
<a onClick={() => this.handleModify(record)}><FormattedMessage id="table.modify" /></a>
|
||||
<Divider type="vertical" />
|
||||
<Popconfirm title="确定要删除这个大盘吗?" onConfirm={() => this.handleDel(record.id)}>
|
||||
<a>删除</a>
|
||||
<Popconfirm title={<FormattedMessage id="table.delete.sure" />} onConfirm={() => this.handleDel(record.id)}>
|
||||
<a><FormattedMessage id="table.delete" /></a>
|
||||
</Popconfirm>
|
||||
</span>
|
||||
);
|
||||
|
@ -282,4 +285,4 @@ class Screen extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default CreateIncludeNsTree(DragDropContext(HTML5Backend)(Screen), { visible: true });
|
||||
export default CreateIncludeNsTree(DragDropContext(HTML5Backend)(injectIntl(Screen)), { visible: true });
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl';
|
||||
import { Button, Row, Col, message } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import moment from 'moment';
|
||||
|
@ -9,7 +10,7 @@ import api from '@common/api';
|
|||
import CustomForm from './CustomForm';
|
||||
import { normalizReqData } from './utils';
|
||||
|
||||
class Add extends Component<any> {
|
||||
class Add extends Component<WrappedComponentProps> {
|
||||
customForm: any;
|
||||
state = {
|
||||
nid: undefined,
|
||||
|
@ -55,12 +56,12 @@ class Add extends Component<any> {
|
|||
method: 'POST',
|
||||
body: JSON.stringify(reqData),
|
||||
}).then(() => {
|
||||
message.success('新增屏蔽成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.create.success' }));
|
||||
history.push({
|
||||
pathname: '/monitor/silence',
|
||||
});
|
||||
}).catch(() => {
|
||||
message.error('新增屏蔽失败!');
|
||||
// message.error('新增屏蔽失败!');
|
||||
}).finally(() => {
|
||||
this.setState({ submitLoading: false });
|
||||
});
|
||||
|
@ -79,13 +80,15 @@ class Add extends Component<any> {
|
|||
initialValues={{
|
||||
btime: now.clone().unix(),
|
||||
etime: now.clone().add(1, 'hours').unix(),
|
||||
cause: '快速屏蔽',
|
||||
cause: this.props.intl.formatMessage({ id: 'silence.cause.default' }),
|
||||
...initialValues,
|
||||
}}
|
||||
/>
|
||||
<Row>
|
||||
<Col offset={6}>
|
||||
<Button onClick={this.handleSubmit} loading={submitLoading} type="primary">保存</Button>
|
||||
<Button onClick={this.handleSubmit} loading={submitLoading} type="primary">
|
||||
<FormattedMessage id="form.submit" />
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
|
@ -93,4 +96,4 @@ class Add extends Component<any> {
|
|||
}
|
||||
}
|
||||
|
||||
export default CreateIncludeNsTree(Add);
|
||||
export default CreateIncludeNsTree(injectIntl(Add));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Button, Form, Input, DatePicker } from 'antd';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
import moment from 'moment';
|
||||
|
@ -88,7 +89,7 @@ class CustomForm extends Component<Props> {
|
|||
key={o.value}
|
||||
type={o.value === timeSpan ? 'primary' : undefined}
|
||||
>
|
||||
{o.label}
|
||||
<FormattedMessage id={o.label} />
|
||||
</Button>
|
||||
))
|
||||
}
|
||||
|
@ -105,12 +106,12 @@ class CustomForm extends Component<Props> {
|
|||
<Form className={readOnly ? 'readOnly' : ''}>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="屏蔽指标"
|
||||
label={<FormattedMessage id="silence.form.metric" />}
|
||||
>
|
||||
{getFieldDecorator('metric', {
|
||||
initialValue: initialValues.metric,
|
||||
rules: [
|
||||
{ required: true, message: '不能为空' },
|
||||
{ required: true },
|
||||
],
|
||||
})(
|
||||
<Input />,
|
||||
|
@ -118,12 +119,12 @@ class CustomForm extends Component<Props> {
|
|||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="屏蔽 endpoints"
|
||||
label={<FormattedMessage id="silence.form.endpoints" />}
|
||||
>
|
||||
{getFieldDecorator('endpoints', {
|
||||
initialValue: _.isArray(initialValues.endpoints) ? _.join(initialValues.endpoints, '\n') : initialValues.endpoints,
|
||||
rules: [
|
||||
{ required: true, message: '不能为空' },
|
||||
{ required: true },
|
||||
],
|
||||
})(
|
||||
<TextArea
|
||||
|
@ -134,14 +135,11 @@ class CustomForm extends Component<Props> {
|
|||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="屏蔽 tags"
|
||||
help="示例:key1=value1,key2=value2"
|
||||
label={<FormattedMessage id="silence.form.tags" />}
|
||||
help="eg. key1=value1,key2=value2"
|
||||
>
|
||||
{getFieldDecorator('tags', {
|
||||
initialValue: initialValues.tags,
|
||||
rules: [
|
||||
// { required: true, message: '不能为空' },
|
||||
],
|
||||
})(
|
||||
<TextArea
|
||||
autosize={{ minRows: 2, maxRows: 6 }}
|
||||
|
@ -156,12 +154,12 @@ class CustomForm extends Component<Props> {
|
|||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="开始时间"
|
||||
label={<FormattedMessage id="silence.form.stime" />}
|
||||
>
|
||||
{getFieldDecorator('btime', {
|
||||
initialValue: moment.unix(initialValues.btime),
|
||||
rules: [
|
||||
{ required: true, message: '不能为空' },
|
||||
{ required: true },
|
||||
],
|
||||
})(
|
||||
<DatePicker
|
||||
|
@ -173,12 +171,12 @@ class CustomForm extends Component<Props> {
|
|||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="结束时间"
|
||||
label={<FormattedMessage id="silence.form.etime" />}
|
||||
>
|
||||
{getFieldDecorator('etime', {
|
||||
initialValue: moment.unix(initialValues.etime),
|
||||
rules: [
|
||||
{ required: true, message: '不能为空' },
|
||||
{ required: true },
|
||||
],
|
||||
})(
|
||||
<DatePicker
|
||||
|
@ -190,12 +188,12 @@ class CustomForm extends Component<Props> {
|
|||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="屏蔽原因"
|
||||
label={<FormattedMessage id="silence.cause" />}
|
||||
>
|
||||
{getFieldDecorator('cause', {
|
||||
initialValue: initialValues.cause,
|
||||
rules: [
|
||||
{ required: true, message: '不能为空' },
|
||||
{ required: true },
|
||||
],
|
||||
})(
|
||||
<TextArea
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Modal } from 'antd';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
|
@ -17,7 +18,7 @@ interface Props extends FormProps {
|
|||
|
||||
class DetailModal extends Component<Props> {
|
||||
static defaultProps = {
|
||||
title: '屏蔽详情',
|
||||
title: '',
|
||||
visible: true,
|
||||
onOk: _.noop,
|
||||
onCancel: _.noop,
|
||||
|
@ -48,7 +49,7 @@ class DetailModal extends Component<Props> {
|
|||
<div>
|
||||
<Modal
|
||||
width={900}
|
||||
title={title}
|
||||
title={<FormattedMessage id="silence.detail.title" />}
|
||||
visible={visible}
|
||||
onOk={this.handleOk}
|
||||
onCancel={this.handleCancel}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Button, Popconfirm, Input, Table, message } from 'antd';
|
||||
|
@ -16,7 +17,7 @@ const timeFormatMap = {
|
|||
moment: 'YYYY-MM-DD HH:mm:ss',
|
||||
};
|
||||
|
||||
class index extends Component {
|
||||
class index extends Component<WrappedComponentProps> {
|
||||
static contextTypes = {
|
||||
getSelectedNode: PropTypes.func,
|
||||
};
|
||||
|
@ -66,27 +67,12 @@ class index extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
handleBatchDelConfirm = () => {
|
||||
const { selectedRowKeys } = this.state;
|
||||
request(`${api.maskconf}/${selectedRowKeys}`, {
|
||||
method: 'DELETE',
|
||||
}).then(() => {
|
||||
this.setState({ selectedRowKeys: [] });
|
||||
message.success('批量解除成功!');
|
||||
this.fetchData();
|
||||
}).catch(() => {
|
||||
message.error('批量解除失败!');
|
||||
});
|
||||
}
|
||||
|
||||
handleDelConfirm = (id: number) => {
|
||||
request(`${api.maskconf}/${id}`, {
|
||||
method: 'DELETE',
|
||||
}).then(() => {
|
||||
message.success('解除成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.delete.success' }));
|
||||
this.fetchData();
|
||||
}).catch(() => {
|
||||
message.error('解除失败!');
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -118,11 +104,13 @@ class index extends Component {
|
|||
<Button
|
||||
style={{ marginRight: 8 }}
|
||||
>
|
||||
<Link to={{ pathname: '/monitor/silence/add', search: `nid=${this.selectedNodeId}` }}>新增屏蔽</Link>
|
||||
<Link to={{ pathname: '/monitor/silence/add', search: `nid=${this.selectedNodeId}` }}>
|
||||
<FormattedMessage id="silence.add" />
|
||||
</Link>
|
||||
</Button>
|
||||
<Input.Search
|
||||
style={{ width: 200, marginLeft: 8 }}
|
||||
placeholder="搜索"
|
||||
placeholder="Search"
|
||||
value={filterValue.search}
|
||||
onChange={(e) => {
|
||||
this.setState({
|
||||
|
@ -140,7 +128,7 @@ class index extends Component {
|
|||
dataSource={data}
|
||||
columns={[
|
||||
{
|
||||
title: '指标',
|
||||
title: <FormattedMessage id="silence.metric" />,
|
||||
dataIndex: 'metric',
|
||||
width: 150,
|
||||
render: (text, record) => {
|
||||
|
@ -160,10 +148,10 @@ class index extends Component {
|
|||
});
|
||||
},
|
||||
}, {
|
||||
title: '关联节点',
|
||||
title: <FormattedMessage id="silence.bindNode" />,
|
||||
dataIndex: 'node_path',
|
||||
}, {
|
||||
title: '屏蔽时间',
|
||||
title: <FormattedMessage id="silence.time" />,
|
||||
width: 180,
|
||||
render(text, record) {
|
||||
const beginTs = record.btime;
|
||||
|
@ -178,19 +166,19 @@ class index extends Component {
|
|||
return <span>unknown</span>;
|
||||
},
|
||||
}, {
|
||||
title: '屏蔽原因',
|
||||
title: <FormattedMessage id="silence.cause" />,
|
||||
dataIndex: 'cause',
|
||||
width: 120,
|
||||
}, {
|
||||
title: '操作者',
|
||||
title: <FormattedMessage id="silence.user" />,
|
||||
dataIndex: 'user',
|
||||
}, {
|
||||
title: '操作',
|
||||
title: <FormattedMessage id="table.operations" />,
|
||||
width: 60,
|
||||
render: (text, record) => (
|
||||
<span>
|
||||
<Popconfirm title="确定要解除这个策略吗?" onConfirm={() => { this.handleDelConfirm(record.id); }}>
|
||||
<a>解除</a>
|
||||
<Popconfirm title={<FormattedMessage id="table.delete.sure" />} onConfirm={() => { this.handleDelConfirm(record.id); }}>
|
||||
<a><FormattedMessage id="table.delete" /></a>
|
||||
</Popconfirm>
|
||||
</span>
|
||||
),
|
||||
|
@ -203,4 +191,4 @@ class index extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default CreateIncludeNsTree(index, { visible: true });
|
||||
export default CreateIncludeNsTree(injectIntl(index), { visible: true });
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps } from 'react-intl';
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import { message } from 'antd';
|
||||
import queryString from 'query-string';
|
||||
|
@ -9,14 +10,14 @@ import api from '@common/api';
|
|||
import SettingFields from './SettingFields';
|
||||
import './style.less';
|
||||
|
||||
class Add extends Component<RouteComponentProps> {
|
||||
class Add extends Component<RouteComponentProps & WrappedComponentProps> {
|
||||
handleSubmit = (values: any) => {
|
||||
const { history } = this.props;
|
||||
request(api.stra, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(values),
|
||||
}).then(() => {
|
||||
message.success('添加报警策略成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.add.success' }));
|
||||
history.push({
|
||||
pathname: '/monitor/strategy',
|
||||
});
|
||||
|
@ -40,4 +41,4 @@ class Add extends Component<RouteComponentProps> {
|
|||
}
|
||||
}
|
||||
|
||||
export default CreateIncludeNsTree(Add as any);
|
||||
export default CreateIncludeNsTree(injectIntl(Add));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps } from 'react-intl';
|
||||
import { Modal, Form, Input, message } from 'antd';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
import _ from 'lodash';
|
||||
|
@ -20,7 +21,7 @@ interface Props extends FormProps{
|
|||
const FormItem = Form.Item;
|
||||
const { TextArea } = Input;
|
||||
|
||||
class BatchImportExportModal extends Component<Props> {
|
||||
class BatchImportExportModal extends Component<Props & WrappedComponentProps> {
|
||||
static defaultProps = {
|
||||
data: undefined,
|
||||
selectedNid: undefined,
|
||||
|
@ -55,7 +56,7 @@ class BatchImportExportModal extends Component<Props> {
|
|||
});
|
||||
});
|
||||
Promise.all(promises).then(() => {
|
||||
message.success('批量导入成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'stra.batch.import.success' }));
|
||||
this.props.onOk();
|
||||
this.props.destroy();
|
||||
});
|
||||
|
@ -102,4 +103,4 @@ class BatchImportExportModal extends Component<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
export default ModalControl(Form.create()(BatchImportExportModal));
|
||||
export default ModalControl(Form.create()(injectIntl(BatchImportExportModal)));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl';
|
||||
import { Modal, Form, Select, TreeSelect, message } from 'antd';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
import _ from 'lodash';
|
||||
|
@ -22,7 +23,7 @@ interface Props extends FormProps{
|
|||
const FormItem = Form.Item;
|
||||
const { Option } = Select;
|
||||
|
||||
class BatchModModal extends Component<Props> {
|
||||
class BatchModModal extends Component<Props & WrappedComponentProps> {
|
||||
static defaultProps = {
|
||||
selectedNid: undefined,
|
||||
treeNodes: [],
|
||||
|
@ -84,9 +85,9 @@ class BatchModModal extends Component<Props> {
|
|||
});
|
||||
});
|
||||
await Promise.all(requests).then(() => {
|
||||
message.success('批量操作成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.modify.success' }));
|
||||
}).catch(() => {
|
||||
message.error('批量操作失败!');
|
||||
// message.error('批量操作失败!');
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
|
@ -118,7 +119,7 @@ class BatchModModal extends Component<Props> {
|
|||
{
|
||||
this.props.type === 'exclNid' ?
|
||||
<FormItem
|
||||
label="排除节点"
|
||||
label={<FormattedMessage id="stra.node.exclude" />}
|
||||
>
|
||||
{
|
||||
getFieldDecorator('excl_nid', {
|
||||
|
@ -144,7 +145,7 @@ class BatchModModal extends Component<Props> {
|
|||
[
|
||||
<FormItem
|
||||
key="group"
|
||||
label="报警接收团队"
|
||||
label={<FormattedMessage id="stra.notify.team" />}
|
||||
>
|
||||
{
|
||||
getFieldDecorator('notify_group', {
|
||||
|
@ -155,7 +156,6 @@ class BatchModModal extends Component<Props> {
|
|||
size="default"
|
||||
defaultActiveFirstOption={false}
|
||||
filterOption={false}
|
||||
placeholder="报警接收团队"
|
||||
>
|
||||
{
|
||||
_.map(this.state.notifyGroupData, (item: any, i) => {
|
||||
|
@ -170,7 +170,7 @@ class BatchModModal extends Component<Props> {
|
|||
</FormItem>,
|
||||
<FormItem
|
||||
key="user"
|
||||
label="报警接收人"
|
||||
label={<FormattedMessage id="stra.notify.user" />}
|
||||
>
|
||||
{
|
||||
getFieldDecorator('notify_user', {
|
||||
|
@ -181,7 +181,6 @@ class BatchModModal extends Component<Props> {
|
|||
size="default"
|
||||
defaultActiveFirstOption={false}
|
||||
filterOption={false}
|
||||
placeholder="报警接收人"
|
||||
>
|
||||
{
|
||||
_.map(this.state.notifyUserData, (item: any, i) => {
|
||||
|
@ -199,7 +198,7 @@ class BatchModModal extends Component<Props> {
|
|||
{
|
||||
this.props.type === 'clone' ?
|
||||
<FormItem
|
||||
label="生效节点"
|
||||
label={<FormattedMessage id="stra.node" />}
|
||||
>
|
||||
{
|
||||
getFieldDecorator('nid', {
|
||||
|
@ -224,4 +223,4 @@ class BatchModModal extends Component<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
export default ModalControl(Form.create()(BatchModModal));
|
||||
export default ModalControl(Form.create()(injectIntl(BatchModModal)));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps } from 'react-intl';
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import { message } from 'antd';
|
||||
import _ from 'lodash';
|
||||
|
@ -9,7 +10,7 @@ import SettingFields from './SettingFields';
|
|||
import { normalizeFormData } from './utils';
|
||||
import './style.less';
|
||||
|
||||
class Clone extends Component<RouteComponentProps> {
|
||||
class Clone extends Component<RouteComponentProps & WrappedComponentProps> {
|
||||
state = {
|
||||
values: undefined,
|
||||
};
|
||||
|
@ -35,7 +36,7 @@ class Clone extends Component<RouteComponentProps> {
|
|||
method: 'POST',
|
||||
body: JSON.stringify(values),
|
||||
}).then(() => {
|
||||
message.success('添加报警策略成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.add.success' }));
|
||||
history.push({
|
||||
pathname: '/monitor/strategy',
|
||||
});
|
||||
|
@ -59,4 +60,4 @@ class Clone extends Component<RouteComponentProps> {
|
|||
}
|
||||
}
|
||||
|
||||
export default CreateIncludeNsTree(Clone as any);
|
||||
export default CreateIncludeNsTree(injectIntl(Clone));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps } from 'react-intl';
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import { message } from 'antd';
|
||||
import _ from 'lodash';
|
||||
|
@ -9,7 +10,7 @@ import SettingFields from './SettingFields';
|
|||
import { normalizeFormData } from './utils';
|
||||
import './style.less';
|
||||
|
||||
class Modify extends Component<RouteComponentProps> {
|
||||
class Modify extends Component<RouteComponentProps & WrappedComponentProps> {
|
||||
state = {
|
||||
values: undefined,
|
||||
} as { values: any };
|
||||
|
@ -39,7 +40,7 @@ class Modify extends Component<RouteComponentProps> {
|
|||
id: values.id,
|
||||
}),
|
||||
}).then(() => {
|
||||
message.success('修改报警策略成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.modify.success' }));
|
||||
history.push({
|
||||
pathname: '/monitor/strategy',
|
||||
});
|
||||
|
@ -62,4 +63,4 @@ class Modify extends Component<RouteComponentProps> {
|
|||
}
|
||||
}
|
||||
|
||||
export default CreateIncludeNsTree(Modify as any);
|
||||
export default CreateIncludeNsTree(injectIntl(Modify));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Form, Button, Input, Radio, Tooltip, Icon, InputNumber, TreeSelect, Checkbox, Row, Col } from 'antd';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
|
@ -20,7 +21,7 @@ interface Props extends FormProps{
|
|||
const FormItem = Form.Item;
|
||||
const RadioGroup = Radio.Group;
|
||||
|
||||
class SettingFields extends Component<Props> {
|
||||
class SettingFields extends Component<Props & WrappedComponentProps> {
|
||||
static contextTypes = {
|
||||
habitsId: PropTypes.string,
|
||||
};
|
||||
|
@ -42,7 +43,7 @@ class SettingFields extends Component<Props> {
|
|||
advanced: false,
|
||||
};
|
||||
|
||||
constructor(props: Props) {
|
||||
constructor(props: Props & WrappedComponentProps) {
|
||||
super(props);
|
||||
this.fetchNotifyData = _.debounce(this.fetchNotifyData, 500);
|
||||
}
|
||||
|
@ -180,13 +181,13 @@ class SettingFields extends Component<Props> {
|
|||
<Form className={`${prefixCls}-strategy-form`} layout="horizontal" onSubmit={this.handleSubmit}>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="策略名称:"
|
||||
label={<FormattedMessage id="stra.name" />}
|
||||
>
|
||||
{
|
||||
getFieldDecorator('name', {
|
||||
initialValue: this.props.initialValues.name,
|
||||
rules: [{
|
||||
required: true, message: '请输入策略名称!',
|
||||
required: true
|
||||
}],
|
||||
})(
|
||||
<Input />,
|
||||
|
@ -195,7 +196,7 @@ class SettingFields extends Component<Props> {
|
|||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="生效节点:"
|
||||
label={<FormattedMessage id="stra.node" />}
|
||||
>
|
||||
{
|
||||
getFieldDecorator('nid', {
|
||||
|
@ -222,7 +223,7 @@ class SettingFields extends Component<Props> {
|
|||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="排除节点:"
|
||||
label={<FormattedMessage id="stra.node.exclude" />}
|
||||
>
|
||||
{
|
||||
getFieldDecorator('excl_nid', {
|
||||
|
@ -247,12 +248,12 @@ class SettingFields extends Component<Props> {
|
|||
label={
|
||||
<Tooltip title={
|
||||
<div>
|
||||
一级报警:发送语音, 短信, IM, 邮件<br />
|
||||
二级报警:发送短信, IM, 邮件<br />
|
||||
三级报警:发送IM,邮件
|
||||
<FormattedMessage id="stra.priority.1.tip" /><br />
|
||||
<FormattedMessage id="stra.priority.2.tip" /><br />
|
||||
<FormattedMessage id="stra.priority.3.tip" />
|
||||
</div>
|
||||
}>
|
||||
<span>报警级别 <Icon type="info-circle-o" /></span>
|
||||
<span><FormattedMessage id="stra.priority" /> <Icon type="info-circle-o" /></span>
|
||||
</Tooltip>
|
||||
}
|
||||
required
|
||||
|
@ -265,15 +266,15 @@ class SettingFields extends Component<Props> {
|
|||
{
|
||||
_.map({
|
||||
1: {
|
||||
alias: '一级报警',
|
||||
alias: <FormattedMessage id="stra.priority.1" />,
|
||||
color: 'red',
|
||||
},
|
||||
2: {
|
||||
alias: '二级报警',
|
||||
alias: <FormattedMessage id="stra.priority.2" />,
|
||||
color: 'yellow',
|
||||
},
|
||||
3: {
|
||||
alias: '三级报警',
|
||||
alias: <FormattedMessage id="stra.priority.3" />,
|
||||
color: 'blue',
|
||||
},
|
||||
}, (val, key) => {
|
||||
|
@ -286,7 +287,7 @@ class SettingFields extends Component<Props> {
|
|||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="统计周期:"
|
||||
label={<FormattedMessage id="stra.alertDur" />}
|
||||
>
|
||||
{
|
||||
getFieldDecorator('alert_dur', {
|
||||
|
@ -295,11 +296,11 @@ class SettingFields extends Component<Props> {
|
|||
<InputNumber min={0} />,
|
||||
)
|
||||
}
|
||||
秒
|
||||
<FormattedMessage id="stra.seconds" />
|
||||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="触发条件:"
|
||||
label={<FormattedMessage id="stra.trigger" />}
|
||||
validateStatus="success" // 兼容
|
||||
help="" // 兼容
|
||||
>
|
||||
|
@ -321,7 +322,7 @@ class SettingFields extends Component<Props> {
|
|||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="Tag 过滤:"
|
||||
label={<FormattedMessage id="stra.tag" />}
|
||||
>
|
||||
{
|
||||
getFieldDecorator('tags', {
|
||||
|
@ -335,7 +336,7 @@ class SettingFields extends Component<Props> {
|
|||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="执行动作:"
|
||||
label={<FormattedMessage id="stra.action" />}
|
||||
validateStatus="success" // 兼容
|
||||
help="" // 兼容
|
||||
>
|
||||
|
@ -362,14 +363,14 @@ class SettingFields extends Component<Props> {
|
|||
onClick={() => {
|
||||
this.setState({ advanced: !this.state.advanced });
|
||||
}}
|
||||
>高级 <Icon type={this.state.advanced ? 'up' : 'down'} />
|
||||
><FormattedMessage id="stra.advanced" /> <Icon type={this.state.advanced ? 'up' : 'down'} />
|
||||
</a>
|
||||
</Col>
|
||||
</Row>
|
||||
<div style={{ display: this.state.advanced ? 'block' : 'none' }}>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="留观时长:"
|
||||
label={<FormattedMessage id="stra.recovery.dur" />}
|
||||
>
|
||||
{
|
||||
getFieldDecorator('recovery_dur', {
|
||||
|
@ -378,11 +379,12 @@ class SettingFields extends Component<Props> {
|
|||
<InputNumber min={0} />,
|
||||
)
|
||||
}
|
||||
秒(告警恢复后持续观察{getFieldValue('recovery_dur')}秒,未再触发阈值才发送恢复通知)
|
||||
<FormattedMessage id="stra.seconds" /> (
|
||||
<FormattedMessage id="stra.recovery.dur.help.1" /> {getFieldValue('recovery_dur')} <FormattedMessage id="stra.recovery.dur.help.2" /> )
|
||||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="静默恢复:"
|
||||
label={<FormattedMessage id="stra.recovery.notify" />}
|
||||
>
|
||||
{
|
||||
getFieldDecorator('recovery_notify', {
|
||||
|
@ -390,14 +392,14 @@ class SettingFields extends Component<Props> {
|
|||
valuePropName: 'checked',
|
||||
})(
|
||||
<Checkbox>
|
||||
不发送恢复通知
|
||||
<FormattedMessage id="stra.recovery.notify.checkbox" />
|
||||
</Checkbox>,
|
||||
)
|
||||
}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="生效时间:"
|
||||
label={<FormattedMessage id="stra.period.time" />}
|
||||
>
|
||||
{
|
||||
getFieldDecorator('period_time', {
|
||||
|
@ -409,7 +411,7 @@ class SettingFields extends Component<Props> {
|
|||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="报警升级:"
|
||||
label={<FormattedMessage id="stra.alert.upgrade" />}
|
||||
validateStatus="success" // 兼容
|
||||
help="" // 兼容
|
||||
>
|
||||
|
@ -432,11 +434,11 @@ class SettingFields extends Component<Props> {
|
|||
</FormItem>
|
||||
</div>
|
||||
<FormItem wrapperCol={{ span: 16, offset: 4 }} style={{ marginTop: 24 }}>
|
||||
<Button type="primary" htmlType="submit">确定</Button>
|
||||
<Button type="primary" htmlType="submit"><FormattedMessage id="form.submit" /></Button>
|
||||
</FormItem>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Form.create()(SettingFields);
|
||||
export default Form.create()(injectIntl(SettingFields));
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React, { Component } from 'react';
|
||||
import { InputNumber, Select, Input, Tag, Spin } from 'antd';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { InputNumber, Select, Input, Spin } from 'antd';
|
||||
import _ from 'lodash';
|
||||
|
||||
interface Props {
|
||||
|
@ -75,23 +76,10 @@ export default class Actions extends Component<Props> {
|
|||
const { converge } = value;
|
||||
const errors = checkActions(null, this.props.value, _.noop) || {} as any;
|
||||
|
||||
if (readOnly) {
|
||||
return (
|
||||
<div className="strategy-actions">
|
||||
<div> 在 {converge[0]} 分钟内, 最多报警 {converge[1]} 次 </div>
|
||||
<div>
|
||||
报警接收组: {_.map(value.notify_group, o => <Tag key={o}>{o}</Tag>)}
|
||||
</div>
|
||||
{
|
||||
value.callback ? <div>回调地址: {value.callback}</div> : null
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className="strategy-actions">
|
||||
<div className={!_.isEmpty(errors.converge) ? 'has-error' : undefined}>
|
||||
在
|
||||
<FormattedMessage id="stra.action.d1" />
|
||||
<InputNumber
|
||||
style={{ marginLeft: 8 }}
|
||||
size="default"
|
||||
|
@ -99,8 +87,7 @@ export default class Actions extends Component<Props> {
|
|||
value={converge[0] / 60}
|
||||
onChange={(val) => { this.handleConvergeChange(0, val); }}
|
||||
/>
|
||||
分钟内,
|
||||
最多报警
|
||||
<FormattedMessage id="stra.action.d2" />, <FormattedMessage id="stra.action.d3" />
|
||||
<InputNumber
|
||||
style={{ marginLeft: 8 }}
|
||||
size="default"
|
||||
|
@ -108,11 +95,11 @@ export default class Actions extends Component<Props> {
|
|||
value={converge[1]}
|
||||
onChange={(val) => { this.handleConvergeChange(1, val); }}
|
||||
/>
|
||||
次
|
||||
<FormattedMessage id="stra.action.d4" />
|
||||
<div className="ant-form-explain">{errors.converge}</div>
|
||||
</div>
|
||||
<div>
|
||||
报警接收团队
|
||||
<FormattedMessage id="stra.notify.team" />
|
||||
</div>
|
||||
<div className={errors.notifyGroup ? 'has-error' : undefined}>
|
||||
<Select
|
||||
|
@ -122,7 +109,7 @@ export default class Actions extends Component<Props> {
|
|||
notFoundContent={this.props.notifyGroupLoading ? <Spin size="small" /> : null}
|
||||
defaultActiveFirstOption={false}
|
||||
filterOption={false}
|
||||
placeholder="报警接收团队"
|
||||
// placeholder="报警接收团队"
|
||||
value={value.notify_group}
|
||||
onChange={this.handleNotifyGroupChange}
|
||||
onSearch={(val) => {
|
||||
|
@ -140,7 +127,7 @@ export default class Actions extends Component<Props> {
|
|||
<div className="ant-form-explain">{errors.notifyGroup}</div>
|
||||
</div>
|
||||
<div>
|
||||
报警接收人
|
||||
<FormattedMessage id="stra.notify.user" />
|
||||
</div>
|
||||
<div className={errors.notifyGroup ? 'has-error' : undefined}>
|
||||
<Select
|
||||
|
@ -150,7 +137,7 @@ export default class Actions extends Component<Props> {
|
|||
notFoundContent={this.props.notifyUserLoading ? <Spin size="small" /> : null}
|
||||
defaultActiveFirstOption={false}
|
||||
filterOption={false}
|
||||
placeholder="报警接收人"
|
||||
// placeholder="报警接收人"
|
||||
value={value.notify_user}
|
||||
onChange={this.handleNotifyUserChange}
|
||||
onSearch={(val) => {
|
||||
|
@ -168,7 +155,7 @@ export default class Actions extends Component<Props> {
|
|||
<div className="ant-form-explain">{errors.notifyUser}</div>
|
||||
</div>
|
||||
<div>
|
||||
通知我自己开发的系统(报警回调, 请确认是 IDC 内可访问的地址)
|
||||
<FormattedMessage id="stra.notify.callback" />
|
||||
</div>
|
||||
<div className={errors.callback ? 'has-error' : undefined}>
|
||||
<Input
|
||||
|
@ -185,7 +172,7 @@ export default class Actions extends Component<Props> {
|
|||
}
|
||||
|
||||
function checkActions(rule: any, value: any, callbackFunc: any) {
|
||||
const emptyErrorText = '不能为空';
|
||||
const emptyErrorText = 'is required';
|
||||
const { converge } = value;
|
||||
const errors: any = {
|
||||
converge: '',
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { InputNumber, Select, Spin, Checkbox } from 'antd';
|
||||
import _ from 'lodash';
|
||||
|
||||
|
@ -51,11 +52,11 @@ export default class AlarmUpgrade extends Component<Props> {
|
|||
});
|
||||
}}
|
||||
>
|
||||
是否启动报警升级
|
||||
<FormattedMessage id="stra.alert.upgrade.checkbox" />
|
||||
</Checkbox>
|
||||
</div>
|
||||
<div>
|
||||
持续
|
||||
<FormattedMessage id="stra.alert.upgrade.d1" />
|
||||
<InputNumber
|
||||
min={0}
|
||||
style={{ margin: '0 8px' }}
|
||||
|
@ -67,7 +68,7 @@ export default class AlarmUpgrade extends Component<Props> {
|
|||
});
|
||||
}}
|
||||
/>
|
||||
分钟,未处理或者未恢复的持续报警,将以
|
||||
<FormattedMessage id="stra.minutes" />, <FormattedMessage id="stra.alert.upgrade.d2" />, <FormattedMessage id="stra.alert.upgrade.d3" />
|
||||
<Select
|
||||
style={{ width: 100, margin: '0 8px' }}
|
||||
value={value.level}
|
||||
|
@ -78,14 +79,14 @@ export default class AlarmUpgrade extends Component<Props> {
|
|||
});
|
||||
}}
|
||||
>
|
||||
<Option key="1" value={1}>一级报警</Option>
|
||||
<Option key="2" value={2}>二级报警</Option>
|
||||
<Option key="3" value={3}>三级报警</Option>
|
||||
<Option key="1" value={1}><FormattedMessage id="stra.priority.1" /></Option>
|
||||
<Option key="2" value={2}><FormattedMessage id="stra.priority.2" /></Option>
|
||||
<Option key="3" value={3}><FormattedMessage id="stra.priority.3" /></Option>
|
||||
</Select>
|
||||
发送给
|
||||
<FormattedMessage id="stra.alert.upgrade.d4" />
|
||||
</div>
|
||||
<div>
|
||||
报警接收团队
|
||||
<FormattedMessage id="stra.notify.team" />
|
||||
</div>
|
||||
<div className={errors.notify ? 'has-error' : undefined}>
|
||||
<Select
|
||||
|
@ -95,7 +96,7 @@ export default class AlarmUpgrade extends Component<Props> {
|
|||
notFoundContent={this.props.notifyGroupLoading ? <Spin size="small" /> : null}
|
||||
defaultActiveFirstOption={false}
|
||||
filterOption={false}
|
||||
placeholder="报警接收团队"
|
||||
// placeholder="报警接收团队"
|
||||
value={value.groups}
|
||||
onChange={(val: any) => {
|
||||
this.props.onChange({
|
||||
|
@ -118,7 +119,7 @@ export default class AlarmUpgrade extends Component<Props> {
|
|||
<div className="ant-form-explain">{errors.notify}</div>
|
||||
</div>
|
||||
<div>
|
||||
报警接收人
|
||||
<FormattedMessage id="stra.notify.user" />
|
||||
</div>
|
||||
<div className={errors.notify ? 'has-error' : undefined}>
|
||||
<Select
|
||||
|
@ -128,7 +129,7 @@ export default class AlarmUpgrade extends Component<Props> {
|
|||
notFoundContent={this.props.notifyUserLoading ? <Spin size="small" /> : null}
|
||||
defaultActiveFirstOption={false}
|
||||
filterOption={false}
|
||||
placeholder="报警接收人"
|
||||
// placeholder="报警接收人"
|
||||
value={value.users}
|
||||
onChange={(val: any) => {
|
||||
this.props.onChange({
|
||||
|
@ -163,7 +164,7 @@ function checkAlarmUpgrade(rule: any, value: any, callbackFunc: any) {
|
|||
|
||||
if (value.enabled && _.isEmpty(value.users) && _.isEmpty(value.groups)) {
|
||||
hasError = true;
|
||||
errors.notify = '必须存在一个报警接收人或接收组';
|
||||
errors.notify = 'Must be an alarm receiver or receiving group';
|
||||
}
|
||||
|
||||
if (hasError) {
|
||||
|
|
|
@ -1,29 +1,27 @@
|
|||
/* eslint-disable no-template-curly-in-string */
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Card, Select, InputNumber } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { funcMap, defaultExpressionValue, commonPropDefaultValue } from './config';
|
||||
|
||||
interface Props {
|
||||
metricError: string,
|
||||
value: any,
|
||||
alertDuration: number,
|
||||
readOnly: boolean,
|
||||
metrics: any[],
|
||||
onChange: (values: any) => void,
|
||||
renderHeader: (value: any) => React.ReactNode,
|
||||
renderFooter: (value: any) => React.ReactNode,
|
||||
}
|
||||
import { FormattedMessage, injectIntl } from 'react-intl';
|
||||
import { funcMap, defaultExpressionValue, commonPropTypes, commonPropDefaultValue } from './config';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
export default class Expression extends Component<Props> {
|
||||
class Expression extends Component {
|
||||
static propTypes = {
|
||||
...commonPropTypes,
|
||||
value: PropTypes.object,
|
||||
metricError: PropTypes.string,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
...commonPropDefaultValue,
|
||||
value: defaultExpressionValue,
|
||||
metricError: '',
|
||||
};
|
||||
|
||||
handleMetricChange = (val: string) => {
|
||||
handleMetricChange = (val) => {
|
||||
const { value, onChange } = this.props;
|
||||
|
||||
onChange({
|
||||
|
@ -32,7 +30,7 @@ export default class Expression extends Component<Props> {
|
|||
});
|
||||
}
|
||||
|
||||
handleFuncChange = (val: string) => {
|
||||
handleFuncChange = (val) => {
|
||||
const { value, onChange } = this.props;
|
||||
const currentFuncDefaultValue = _.get(funcMap[val], 'defaultValue', []);
|
||||
|
||||
|
@ -43,7 +41,7 @@ export default class Expression extends Component<Props> {
|
|||
});
|
||||
}
|
||||
|
||||
handleParamsChange = (index: number, val: any) => {
|
||||
handleParamsChange = (index, val) => {
|
||||
const { value, onChange } = this.props;
|
||||
const currentFuncDefaultValue = _.get(funcMap[value.func], 'defaultValue', []);
|
||||
const { params = [] } = value;
|
||||
|
@ -60,7 +58,7 @@ export default class Expression extends Component<Props> {
|
|||
});
|
||||
}
|
||||
|
||||
handleEoptChange = (val: string) => {
|
||||
handleEoptChange = (val) => {
|
||||
const { value, onChange } = this.props;
|
||||
|
||||
onChange({
|
||||
|
@ -69,7 +67,7 @@ export default class Expression extends Component<Props> {
|
|||
});
|
||||
}
|
||||
|
||||
handleThresholdChange = (val: any) => {
|
||||
handleThresholdChange = (val) => {
|
||||
const { value, onChange } = this.props;
|
||||
let newVal = val;
|
||||
|
||||
|
@ -83,21 +81,24 @@ export default class Expression extends Component<Props> {
|
|||
});
|
||||
}
|
||||
|
||||
renderPreview(readOnly?: boolean) {
|
||||
renderPreview(readOnly: boolean) {
|
||||
const { value, alertDuration } = this.props;
|
||||
const { metric, func, eopt, threshold } = value;
|
||||
|
||||
if (func === 'canary') return '智能报警 - canary';
|
||||
|
||||
const { params = [] } = value;
|
||||
const str = _.get(funcMap[func], 'meaning', '');
|
||||
const index1 = str.indexOf('n');
|
||||
const index2 = str.indexOf('m');
|
||||
const index3 = _.lastIndexOf(str, 'v');
|
||||
const meaningKey = this.props.intl.locale === 'en' ? 'meaningEn' : 'meaning';
|
||||
const str = _.get(funcMap[func], meaningKey, '');
|
||||
const index1 = str.indexOf('$n');
|
||||
const index2 = str.indexOf('$m');
|
||||
const index3 = str.lastIndexOf('$v');
|
||||
const nPrefix = str.substring(0, index1);
|
||||
const vPostfix = str.substring(index3 + 1);
|
||||
const vPostfix = str.substring(index3 + 2);
|
||||
let mVal;
|
||||
if (func === 'c_avg_rate_abs' || func === 'c_avg_rate') {
|
||||
if (
|
||||
func === 'c_avg_rate_abs'
|
||||
|| func === 'c_avg_rate'
|
||||
|| func === 'c_avg_abs'
|
||||
|| func === 'c_avg'
|
||||
) {
|
||||
mVal = params[0] !== 1 ? params[0] / 86400 : 1;
|
||||
} else {
|
||||
mVal = params[0] || 1;
|
||||
|
@ -119,7 +120,7 @@ export default class Expression extends Component<Props> {
|
|||
);
|
||||
|
||||
if (index2 > -1) {
|
||||
const mPrefix = str.substring(index1 + 1, index2);
|
||||
const mPrefix = str.substring(index1 + 2, index2);
|
||||
previewNode = (
|
||||
<span>
|
||||
{previewNode}
|
||||
|
@ -132,7 +133,7 @@ export default class Expression extends Component<Props> {
|
|||
if (func !== 'nodata') {
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
const _index = index2 > -1 ? index2 : index1;
|
||||
const vPrefix = str.substring(_index + 1, index3);
|
||||
const vPrefix = str.substring(_index + 2, index3);
|
||||
previewNode = (
|
||||
<span>
|
||||
{previewNode}
|
||||
|
@ -142,7 +143,7 @@ export default class Expression extends Component<Props> {
|
|||
</span>
|
||||
);
|
||||
} else {
|
||||
const nPostfix = str.substring(index1 + 1);
|
||||
const nPostfix = str.substring(index1 + 2);
|
||||
previewNode = (
|
||||
<span>
|
||||
{previewNode}
|
||||
|
@ -152,45 +153,54 @@ export default class Expression extends Component<Props> {
|
|||
}
|
||||
return (
|
||||
<div>
|
||||
{ !readOnly && <span style={{ color: '#999' }}>预览:</span> }
|
||||
{ !readOnly && <span style={{ color: '#999' }}><FormattedMessage id="stra.preview" />:</span> }
|
||||
<span style={{ paddingRight: 5 }}>{metric || '${metric}' }</span>
|
||||
{ previewNode }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderFuncParams(i: number) {
|
||||
renderFuncParams(i) {
|
||||
const { value } = this.props;
|
||||
const { func, params = [] } = value;
|
||||
const minnum = ['diff', 'pdiff'].indexOf(func) > -1 ? 2 : 1;
|
||||
let val = _.toNumber(params[i]) as any;
|
||||
// const maxnum = func === 'nodata' ? 7200 : 60;
|
||||
let val = _.toNumber(params[i]);
|
||||
|
||||
if (func === 'c_avg_rate_abs' || func === 'c_avg_rate') {
|
||||
// 相对天数
|
||||
val = _.toString(params[i] !== 1 ? params[i] : 86400);
|
||||
return (
|
||||
<Select
|
||||
style={{ display: 'inline-block', width: 80, marginRight: 8 }}
|
||||
value={val}
|
||||
onChange={(newVal: string) => { this.handleParamsChange(i, _.toNumber(newVal)); }}
|
||||
>
|
||||
<Option value="86400">1</Option>
|
||||
<Option value="604800">7</Option>
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
if (func === 'happen' || func === 'ndiff') {
|
||||
// 发生次数
|
||||
return (
|
||||
<InputNumber
|
||||
key={i}
|
||||
value={val}
|
||||
min={minnum}
|
||||
max={_.toNumber(params[0])}
|
||||
style={{ display: 'inline-block' }}
|
||||
onChange={(newVal) => { this.handleParamsChange(i, newVal); }}
|
||||
/>
|
||||
);
|
||||
if (i === 0) {
|
||||
if (
|
||||
func === 'c_avg_rate_abs'
|
||||
|| func === 'c_avg_rate'
|
||||
|| func === 'c_avg_abs'
|
||||
|| func === 'c_avg'
|
||||
) {
|
||||
// 相对天数
|
||||
val = _.toString(params[i] !== 1 ? params[i] : 86400);
|
||||
return (
|
||||
<Select
|
||||
style={{ display: 'inline-block', width: 80, marginRight: 8 }}
|
||||
value={val}
|
||||
onChange={(newVal) => { this.handleParamsChange(i, _.toNumber(newVal)); }}
|
||||
>
|
||||
<Option value="86400">1</Option>
|
||||
<Option value="604800">7</Option>
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
if (func === 'happen' || func === 'ndiff') {
|
||||
// 发生次数
|
||||
return (
|
||||
<InputNumber
|
||||
key={i}
|
||||
value={val}
|
||||
min={minnum}
|
||||
max={_.toNumber(params[0])}
|
||||
style={{ display: 'inline-block' }}
|
||||
onChange={(newVal) => { this.handleParamsChange(i, newVal); }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return <span>不是合法的 param</span>;
|
||||
}
|
||||
return <span>不是合法的 param</span>;
|
||||
}
|
||||
|
@ -205,7 +215,7 @@ export default class Expression extends Component<Props> {
|
|||
<div style={{ marginTop: 5 }}>
|
||||
{
|
||||
// render params
|
||||
_.map(_.get(funcMap[value.func], 'params', []), (o, i: number) => {
|
||||
_.map(_.get(funcMap[value.func], 'params', []), (o, i) => {
|
||||
return (
|
||||
<div key={o} style={{ display: 'inline-block', verticalAlign: 'top' }}>
|
||||
<span style={{ color: i === 0 ? '#2DB7F5' : '#FFB727' }}>{o}</span>
|
||||
|
@ -250,18 +260,8 @@ export default class Expression extends Component<Props> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { value, readOnly, metrics, renderHeader, renderFooter, metricError } = this.props;
|
||||
const { value, metrics, renderHeader, renderFooter, metricError } = this.props;
|
||||
|
||||
if (readOnly) {
|
||||
return (
|
||||
<Card
|
||||
bodyStyle={{ padding: 10 }}
|
||||
style={{ marginTop: 10 }}
|
||||
>
|
||||
{ this.renderPreview(readOnly) }
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Card
|
||||
bodyStyle={{ padding: 10 }}
|
||||
|
@ -278,7 +278,7 @@ export default class Expression extends Component<Props> {
|
|||
notFoundContent=""
|
||||
size="default"
|
||||
style={{ width: 250 }}
|
||||
placeholder="指标名称"
|
||||
placeholder="Metric name"
|
||||
defaultActiveFirstOption={false}
|
||||
dropdownMatchSelectWidth={false}
|
||||
showSearch
|
||||
|
@ -304,12 +304,10 @@ export default class Expression extends Component<Props> {
|
|||
</div>
|
||||
{this.renderParams()}
|
||||
</div>
|
||||
{
|
||||
value.func !== 'canary' ? this.renderPreview() : null
|
||||
}
|
||||
{ this.renderPreview() }
|
||||
{
|
||||
value.func === 'all' ?
|
||||
<div style={{ color: '#f50', lineHeight: 1 }}>断线情况,即为不连续。若要增加容错,可选择happen</div> : null
|
||||
<div style={{ color: '#f50', lineHeight: 1 }}><FormattedMessage id="stra.preview.all.help" /></div> : null
|
||||
}
|
||||
<div className="expression-footerExtra">
|
||||
{renderFooter(value)}
|
||||
|
@ -318,3 +316,5 @@ export default class Expression extends Component<Props> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default injectIntl(Expression);
|
||||
|
|
|
@ -1,57 +1,66 @@
|
|||
import PropTypes from 'prop-types';
|
||||
|
||||
export const funcMap: { [index: string]: any } = {
|
||||
export const funcMap = {
|
||||
all: {
|
||||
label: '连续发生',
|
||||
meaning: '持续 n 秒每个值都 v',
|
||||
meaning: '持续 $n 秒每个值都 $v',
|
||||
meaningEn: 'duration $n s, every value $v',
|
||||
params: [],
|
||||
defaultValue: [],
|
||||
},
|
||||
happen: {
|
||||
label: '发生次数',
|
||||
meaning: '持续 n 秒内 m 次值 v',
|
||||
meaning: '持续 $n 秒内 $m 次值 $v',
|
||||
meaningEn: 'duration $n s, $m times value $v',
|
||||
params: ['m'],
|
||||
defaultValue: [1],
|
||||
},
|
||||
nodata: {
|
||||
label: '数据上报中断',
|
||||
meaning: '持续 n 秒无数据上报',
|
||||
meaning: '持续 $n 秒无数据上报',
|
||||
meaningEn: 'duration $n s, no data',
|
||||
params: [],
|
||||
defaultValue: [],
|
||||
},
|
||||
max: {
|
||||
label: '最大值',
|
||||
meaning: '持续 n 秒最大值 v',
|
||||
meaning: '持续 $n 秒最大值 $v',
|
||||
meaningEn: 'duration $n s, max $v',
|
||||
params: [],
|
||||
defaultValue: [],
|
||||
},
|
||||
min: {
|
||||
label: '最小值',
|
||||
meaning: '持续 n 秒最小值 v',
|
||||
meaning: '持续 $n 秒最小值 $v',
|
||||
meaningEn: 'duration $n s, min $v',
|
||||
params: [],
|
||||
defaultValue: [],
|
||||
},
|
||||
avg: {
|
||||
label: '均值',
|
||||
meaning: '持续 n 秒均值 v',
|
||||
meaning: '持续 $n 秒均值 $v',
|
||||
meaningEn: 'duration $n s, avg $v',
|
||||
params: [],
|
||||
defaultValue: [],
|
||||
},
|
||||
sum: {
|
||||
label: '求和',
|
||||
meaning: '持续 n 秒求和值 v',
|
||||
meaning: '持续 $n 秒求和值 $v',
|
||||
meaningEn: 'duration $n s, sum $v',
|
||||
params: [],
|
||||
defaultValue: [],
|
||||
},
|
||||
diff: {
|
||||
label: '突增突降值',
|
||||
meaning: '最新值与其之前 n 秒的任意值之差 (区分正负) v',
|
||||
meaning: '最新值与其之前 $n 秒的任意值之差 (区分正负) $v',
|
||||
meaningEn: 'The difference between the latest value and any previous value of $n seconds $v',
|
||||
params: [],
|
||||
defaultValue: [],
|
||||
},
|
||||
pdiff: {
|
||||
label: '突增突降率',
|
||||
meaning: '(最新值与其之前 n 秒的任意值之差)除以对应历史值 (区分正负) v %',
|
||||
meaning: '(最新值与其之前 $n 秒的任意值之差)除以对应历史值 (区分正负) $v %',
|
||||
meaningEn: '(the difference between the latest value and any previous value of $n seconds) divided by the corresponding historical value $v',
|
||||
params: [],
|
||||
defaultValue: [],
|
||||
},
|
||||
|
|
|
@ -1,33 +1,28 @@
|
|||
/* eslint-disable no-use-before-define */
|
||||
import React, { Component } from 'react';
|
||||
import { Select, Tag } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import Expression from './Expression';
|
||||
import { defaultExpressionValue, commonPropDefaultValue } from './config';
|
||||
import { defaultExpressionValue, commonPropTypes, commonPropDefaultValue } from './config';
|
||||
import './style.less';
|
||||
|
||||
interface Props {
|
||||
metricError: string,
|
||||
value: any,
|
||||
alertDuration: number,
|
||||
readOnly: boolean,
|
||||
metrics: any[],
|
||||
onChange: (values: any) => void,
|
||||
renderHeader: (value: any) => React.ReactNode,
|
||||
renderFooter: (value: any) => React.ReactNode,
|
||||
}
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
export default class Expressions extends Component<Props> {
|
||||
export default class Expressions extends Component {
|
||||
static defaultExpressionValue = defaultExpressionValue;
|
||||
|
||||
static checkExpressions = checkExpressions;
|
||||
|
||||
static propTypes = {
|
||||
...commonPropTypes,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
...commonPropDefaultValue,
|
||||
};
|
||||
|
||||
handleTypeChange = (type: string) => {
|
||||
handleTypeChange = (type) => {
|
||||
const { value } = this.props;
|
||||
const valueClone = _.cloneDeep(value);
|
||||
|
||||
|
@ -39,7 +34,7 @@ export default class Expressions extends Component<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
handleExpressionChange = (index: number, val: any) => {
|
||||
handleExpressionChange = (index, val) => {
|
||||
const { value, onChange } = this.props;
|
||||
const valueClone = _.cloneDeep(value);
|
||||
|
||||
|
@ -50,6 +45,7 @@ export default class Expressions extends Component<Props> {
|
|||
render() {
|
||||
const { alertDuration, value, readOnly, metrics, renderHeader, renderFooter } = this.props;
|
||||
const type = value[1] ? 'and' : 'normal';
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
const errors = checkExpressions(null, value, _.noop) || [];
|
||||
|
||||
return (
|
||||
|
@ -57,13 +53,13 @@ export default class Expressions extends Component<Props> {
|
|||
{
|
||||
!readOnly &&
|
||||
<Select
|
||||
style={{ width: 80 }}
|
||||
style={{ width: 90 }}
|
||||
size="default"
|
||||
value={type}
|
||||
onChange={this.handleTypeChange}
|
||||
>
|
||||
<Option value="normal">常用</Option>
|
||||
<Option value="and">与条件</Option>
|
||||
<Option value="normal"><FormattedMessage id="stra.trigger.normal" /></Option>
|
||||
<Option value="and"><FormattedMessage id="stra.trigger.and" /></Option>
|
||||
</Select>
|
||||
}
|
||||
<div>
|
||||
|
@ -82,7 +78,7 @@ export default class Expressions extends Component<Props> {
|
|||
<div className="expressions-and">
|
||||
<div className="expressions-and-tagBorder" />
|
||||
<span className="expressions-and-tag">
|
||||
<Tag>与</Tag>
|
||||
<Tag><FormattedMessage id="stra.trigger.and" /></Tag>
|
||||
</span>
|
||||
<Expression
|
||||
alertDuration={alertDuration}
|
||||
|
@ -102,14 +98,14 @@ export default class Expressions extends Component<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
function checkExpressions(rule: any, value: any, callback: any) {
|
||||
function checkExpressions(rule, value, callback) {
|
||||
let error0;
|
||||
let error1;
|
||||
const emptyErrorText = '不能为空';
|
||||
const samenameErrorText = '与条件, 不能选择相同的 metric';
|
||||
const emptyErrorText = 'is required';
|
||||
const samenameErrorText = 'Cannot select the same metric';
|
||||
let hasError = false;
|
||||
|
||||
_.each(value, (item, i: number) => {
|
||||
_.each(value, (item, i) => {
|
||||
if (item.metric === '') {
|
||||
if (i === 0) {
|
||||
error0 = emptyErrorText;
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import React from 'react';
|
||||
import { Card, Tag } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
const toptMap: any = {
|
||||
'=': '包含',
|
||||
'!=': '排除',
|
||||
const toptMap = {
|
||||
'=': 'stra.tag.include',
|
||||
'!=': 'stra.tag.exclude',
|
||||
};
|
||||
|
||||
export default function Filter(props: any) {
|
||||
export default function Filter(props) {
|
||||
const { data, extra } = props;
|
||||
const { tkey, topt, tval } = data;
|
||||
|
||||
|
@ -17,7 +18,7 @@ export default function Filter(props: any) {
|
|||
title={
|
||||
<span>
|
||||
{tkey}
|
||||
<span style={{ paddingLeft: 10 }}>{toptMap[topt]}</span>
|
||||
<span style={{ paddingLeft: 10 }}>{<FormattedMessage id={toptMap[topt]} />}</span>
|
||||
</span>
|
||||
}
|
||||
extra={extra}
|
||||
|
|
|
@ -1,20 +1,9 @@
|
|||
import React, { Component } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Modal, Form, Select, Radio } from 'antd';
|
||||
import _ from 'lodash';
|
||||
|
||||
interface Props {
|
||||
title: string,
|
||||
visible: boolean,
|
||||
data: any,
|
||||
tags: any,
|
||||
onOk: (values: any) => void | boolean,
|
||||
destroy: () => void,
|
||||
}
|
||||
|
||||
interface State {
|
||||
data: any;
|
||||
}
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import ModalControl from '@cpts/ModalControl';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
const { Option } = Select;
|
||||
|
@ -24,11 +13,20 @@ const formItemLayout = {
|
|||
wrapperCol: { span: 16 },
|
||||
};
|
||||
const toptMap = {
|
||||
'=': '包含',
|
||||
'!=': '排除',
|
||||
'=': 'stra.tag.include',
|
||||
'!=': 'stra.tag.exclude',
|
||||
};
|
||||
|
||||
class FilterFormModal extends Component<Props, State> {
|
||||
class FilterFormModal extends Component {
|
||||
static propTypes = {
|
||||
title: PropTypes.string,
|
||||
visible: PropTypes.bool,
|
||||
data: PropTypes.object,
|
||||
tags: PropTypes.object,
|
||||
onOk: PropTypes.func,
|
||||
destroy: PropTypes.func,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
title: '',
|
||||
visible: false,
|
||||
|
@ -38,18 +36,18 @@ class FilterFormModal extends Component<Props, State> {
|
|||
destroy: _.noop,
|
||||
};
|
||||
|
||||
formId = _.uniqueId('tagFilterConditionForm');
|
||||
constructor(props: Props) {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.formId = _.uniqueId('tagFilterConditionForm');
|
||||
this.state = {
|
||||
data: {
|
||||
topt: '=',
|
||||
...props.data,
|
||||
},
|
||||
} as State;
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps: Props) {
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (!_.isEqual(nextProps.data, this.props.data)) {
|
||||
this.setState({
|
||||
data: {
|
||||
|
@ -63,10 +61,10 @@ class FilterFormModal extends Component<Props, State> {
|
|||
getTvalOptions() {
|
||||
const { tags } = this.props;
|
||||
const { data } = this.state;
|
||||
let tvalOptions: any[] = [];
|
||||
let tvalOptions = [];
|
||||
|
||||
if (!_.isEmpty(tags) && data.tkey) {
|
||||
const tval = _.filter(tags[data.tkey], (item, i: number) => i < 500);
|
||||
const tval = _.filter(tags[data.tkey], (item, i) => i < 500);
|
||||
tvalOptions = _.map(tval, item => <Option key={item} value={item}>{item}</Option>);
|
||||
}
|
||||
return tvalOptions;
|
||||
|
@ -88,7 +86,7 @@ class FilterFormModal extends Component<Props, State> {
|
|||
this.props.destroy();
|
||||
}
|
||||
|
||||
handleFieldChange = (field: string, val: any) => {
|
||||
handleFieldChange = (field, val) => {
|
||||
const { data } = this.state;
|
||||
this.setState({
|
||||
data: {
|
||||
|
@ -117,18 +115,18 @@ class FilterFormModal extends Component<Props, State> {
|
|||
>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="Tag 名称"
|
||||
label="Tag name"
|
||||
validateStatus={_.isEmpty(data.tkey) ? 'error' : ''}
|
||||
help={_.isEmpty(data.tkey) && '不能为空'}
|
||||
help={_.isEmpty(data.tkey) && 'is required'}
|
||||
>
|
||||
<Select
|
||||
mode="combobox"
|
||||
notFoundContent=""
|
||||
placeholder="支持自定义,非叶子节点或者'与'条件时没有自动补全功能"
|
||||
// placeholder="支持自定义,非叶子节点或者'与'条件时没有自动补全功能"
|
||||
defaultActiveFirstOption={false}
|
||||
// getPopupContainer={() => document.getElementById(this.formId)}
|
||||
value={data.tkey}
|
||||
onChange={(val: any) => this.handleFieldChange('tkey', val)}
|
||||
onChange={val => this.handleFieldChange('tkey', val)}
|
||||
>
|
||||
{
|
||||
_.map(tags, (tval, tkey) => <Option key={tkey} value={tkey}>{tkey}</Option>)
|
||||
|
@ -141,24 +139,24 @@ class FilterFormModal extends Component<Props, State> {
|
|||
onChange={e => this.handleFieldChange('topt', e.target.value)}
|
||||
>
|
||||
{
|
||||
_.map(toptMap, (val, key) => <Radio key={key} value={key}>{val}</Radio>)
|
||||
_.map(toptMap, (val, key) => <Radio key={key} value={key}><FormattedMessage id={val} /></Radio>)
|
||||
}
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="Tag 取值"
|
||||
label="Tag value"
|
||||
validateStatus={_.isEmpty(data.tval) ? 'error' : ''}
|
||||
help={_.isEmpty(data.tval) && '不能为空'}
|
||||
help={_.isEmpty(data.tval) && 'is required'}
|
||||
>
|
||||
<Select
|
||||
mode="tags"
|
||||
showSearch
|
||||
notFoundContent=""
|
||||
placeholder="支持自定义,必须完全匹配不支持正则"
|
||||
// placeholder="支持自定义,必须完全匹配不支持正则"
|
||||
// getPopupContainer={() => document.getElementById(this.formId)}
|
||||
value={data.tval}
|
||||
onChange={(val: any) => this.handleFieldChange('tval', val)}
|
||||
onChange={val => this.handleFieldChange('tval', val)}
|
||||
>
|
||||
{tvalOptions}
|
||||
</Select>
|
||||
|
@ -169,24 +167,4 @@ class FilterFormModal extends Component<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
export default function filterFormModal(config: any) {
|
||||
const div = document.createElement('div');
|
||||
document.body.appendChild(div);
|
||||
|
||||
function destroy() {
|
||||
const unmountResult = ReactDOM.unmountComponentAtNode(div);
|
||||
if (unmountResult && div.parentNode) {
|
||||
div.parentNode.removeChild(div);
|
||||
}
|
||||
}
|
||||
|
||||
function render(props: any) {
|
||||
ReactDOM.render(<FilterFormModal {...props} />, div);
|
||||
}
|
||||
|
||||
render({ ...config, visible: true, destroy });
|
||||
|
||||
return {
|
||||
destroy,
|
||||
};
|
||||
}
|
||||
export default ModalControl(FilterFormModal);
|
||||
|
|
|
@ -1,23 +1,28 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Row, Col, Button, Icon, message, Popconfirm } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { FormattedMessage, injectIntl } from 'react-intl';
|
||||
import Filter from './Filter';
|
||||
import filterFormModal from './FilterFormModal';
|
||||
import './style.less';
|
||||
|
||||
interface Props {
|
||||
value: any[],
|
||||
onChange: (values: any) => void,
|
||||
readOnly: boolean,
|
||||
tags: any,
|
||||
}
|
||||
const commonPropTypes = {
|
||||
value: PropTypes.array,
|
||||
onChange: PropTypes.func,
|
||||
readOnly: PropTypes.bool,
|
||||
tags: PropTypes.object,
|
||||
};
|
||||
|
||||
const commonPropDefaultValue = {
|
||||
readOnly: false,
|
||||
tags: {},
|
||||
};
|
||||
|
||||
export default class Filters extends Component<Props> {
|
||||
class Filters extends Component {
|
||||
static propTypes = {
|
||||
...commonPropTypes,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
...commonPropDefaultValue,
|
||||
|
@ -28,9 +33,10 @@ export default class Filters extends Component<Props> {
|
|||
const valueClone = _.cloneDeep(value);
|
||||
|
||||
filterFormModal({
|
||||
title: '添加 Tag 条件',
|
||||
language: this.props.intl.locale,
|
||||
title: <FormattedMessage id="stra.tag.add" />,
|
||||
tags,
|
||||
onOk: (data: any) => {
|
||||
onOk: (data) => {
|
||||
if (!_.find(value, { tkey: data.tkey })) {
|
||||
valueClone.push(data);
|
||||
onChange(valueClone);
|
||||
|
@ -41,15 +47,16 @@ export default class Filters extends Component<Props> {
|
|||
});
|
||||
}
|
||||
|
||||
updateFilter = (val: any) => {
|
||||
updateFilter = (val) => {
|
||||
const { tags, value, onChange } = this.props;
|
||||
const valueClone = _.cloneDeep(value);
|
||||
|
||||
filterFormModal({
|
||||
title: '修改 Tag 条件',
|
||||
language: this.props.intl.locale,
|
||||
title: <FormattedMessage id="stra.tag.modify" />,
|
||||
tags,
|
||||
data: val,
|
||||
onOk: (data: any) => {
|
||||
onOk: (data) => {
|
||||
if (!_.find(value, { tkey: data.tkey }) || val.tkey === data.tkey) {
|
||||
_.remove(valueClone, o => o.tkey === val.tkey);
|
||||
valueClone.push(data);
|
||||
|
@ -61,7 +68,7 @@ export default class Filters extends Component<Props> {
|
|||
});
|
||||
}
|
||||
|
||||
deleteFilter = (val: any) => {
|
||||
deleteFilter = (val) => {
|
||||
const { value, onChange } = this.props;
|
||||
const valueClone = _.cloneDeep(value);
|
||||
|
||||
|
@ -80,7 +87,7 @@ export default class Filters extends Component<Props> {
|
|||
!readOnly &&
|
||||
<span className="strategy-filter-operation">
|
||||
<Icon type="edit" onClick={() => this.updateFilter(item)} />
|
||||
<Popconfirm title="确定要删除该 Tag 条件吗?" onConfirm={() => this.deleteFilter(item)}>
|
||||
<Popconfirm title={<FormattedMessage id="table.delete.sure" />} onConfirm={() => this.deleteFilter(item)}>
|
||||
<Icon type="cross" />
|
||||
</Popconfirm>
|
||||
</span>
|
||||
|
@ -110,7 +117,7 @@ export default class Filters extends Component<Props> {
|
|||
size="default"
|
||||
onClick={this.addFilter}
|
||||
>
|
||||
添加筛选条件
|
||||
<FormattedMessage id="stra.tag.add" />
|
||||
</Button>
|
||||
{
|
||||
value.length ? this.renderFilters() : null
|
||||
|
@ -119,3 +126,5 @@ export default class Filters extends Component<Props> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default injectIntl(Filters);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Row, Col, Table, Button, Input, Select, Tag, Divider, message, Popconfirm, Dropdown, Menu, Modal } from 'antd';
|
||||
|
@ -13,7 +14,7 @@ import BatchImportExportModal from './BatchImportExportModal';
|
|||
|
||||
const { Option } = Select;
|
||||
|
||||
class index extends Component {
|
||||
class index extends Component<WrappedComponentProps> {
|
||||
static contextTypes = {
|
||||
getNodes: PropTypes.func,
|
||||
getSelectedNode: PropTypes.func,
|
||||
|
@ -86,7 +87,7 @@ class index extends Component {
|
|||
ids: [id],
|
||||
}),
|
||||
}).then(() => {
|
||||
message.success('删除成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.delete.success' }));
|
||||
this.fetchData();
|
||||
});
|
||||
}
|
||||
|
@ -96,6 +97,7 @@ class index extends Component {
|
|||
const { getNodes } = this.context;
|
||||
const treeNodes = getNodes();
|
||||
BatchModModal({
|
||||
language: this.props.intl.locale,
|
||||
type: 'exclNid',
|
||||
selectedNid: this.selectedNodeId,
|
||||
treeNodes,
|
||||
|
@ -109,6 +111,7 @@ class index extends Component {
|
|||
handleBatchModNotifyBtnClick = () => {
|
||||
const { selectedRows } = this.state;
|
||||
BatchModModal({
|
||||
language: this.props.intl.locale,
|
||||
type: 'notify',
|
||||
data: selectedRows,
|
||||
onOk: () => {
|
||||
|
@ -122,6 +125,7 @@ class index extends Component {
|
|||
const { getNodes } = this.context;
|
||||
const treeNodes = getNodes();
|
||||
BatchModModal({
|
||||
language: this.props.intl.locale,
|
||||
type: 'clone',
|
||||
data: selectedRows,
|
||||
treeNodes,
|
||||
|
@ -137,8 +141,8 @@ class index extends Component {
|
|||
|
||||
if (ids.length) {
|
||||
Modal.confirm({
|
||||
title: '批量删除',
|
||||
content: '确定要删除所选的策略吗?',
|
||||
title: this.props.intl.formatMessage({ id: 'stra.batch.delete' }),
|
||||
content: this.props.intl.formatMessage({ id: 'table.delete.sure' }),
|
||||
onOk: () => {
|
||||
request(api.stra, {
|
||||
method: 'DELETE',
|
||||
|
@ -146,7 +150,7 @@ class index extends Component {
|
|||
ids,
|
||||
}),
|
||||
}).then(() => {
|
||||
message.success('批量删除成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.delete.success' }));
|
||||
this.fetchData();
|
||||
});
|
||||
},
|
||||
|
@ -157,7 +161,8 @@ class index extends Component {
|
|||
handleBatchImportBtnClick = () => {
|
||||
BatchImportExportModal({
|
||||
type: 'import',
|
||||
title: '批量导入策略',
|
||||
title: this.props.intl.formatMessage({ id: 'stra.batch.import' }),
|
||||
language: this.props.intl.locale,
|
||||
selectedNid: this.selectedNodeId,
|
||||
onOk: () => {
|
||||
this.fetchData();
|
||||
|
@ -187,7 +192,8 @@ class index extends Component {
|
|||
BatchImportExportModal({
|
||||
data: newSelectedRows,
|
||||
type: 'export',
|
||||
title: '批量导出策略',
|
||||
title: this.props.intl.formatMessage({ id: 'stra.batch.export' }),
|
||||
language: this.props.intl.locale,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -243,13 +249,15 @@ class index extends Component {
|
|||
<Row className="mb10">
|
||||
<Col span={18}>
|
||||
<Button className="mr10">
|
||||
<Link to={{ pathname: '/monitor/strategy/add', search: `nid=${this.selectedNodeId}` }}>新增报警策略</Link>
|
||||
<Link to={{ pathname: '/monitor/strategy/add', search: `nid=${this.selectedNodeId}` }}>
|
||||
<FormattedMessage id="stra.add" />
|
||||
</Link>
|
||||
</Button>
|
||||
<Select
|
||||
allowClear
|
||||
style={{ width: 100 }}
|
||||
className="mr10"
|
||||
placeholder="策略级别"
|
||||
placeholder={this.props.intl.formatMessage({ id: 'stra.priority' })}
|
||||
value={this.state.priority}
|
||||
onChange={(value: number) => {
|
||||
this.setState({ priority: value });
|
||||
|
@ -264,7 +272,7 @@ class index extends Component {
|
|||
<Input
|
||||
style={{ width: 300 }}
|
||||
className="mr10"
|
||||
placeholder="策略名称、指标、报警接受组、人员关键词搜索"
|
||||
placeholder="Search"
|
||||
value={this.state.search}
|
||||
onChange={(e) => {
|
||||
this.setState({ search: e.target.value });
|
||||
|
@ -276,27 +284,27 @@ class index extends Component {
|
|||
overlay={
|
||||
<Menu>
|
||||
<Menu.Item>
|
||||
<Button type="link" disabled={!canBatchOper} onClick={() => { this.handleBatchModExclNidBtnClick(); }}>修改排除节点</Button>
|
||||
<Button type="link" disabled={!canBatchOper} onClick={() => { this.handleBatchModExclNidBtnClick(); }}><FormattedMessage id="stra.batch.modify.excludeNs" /></Button>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<Button type="link" disabled={!canBatchOper} onClick={() => { this.handleBatchModNotifyBtnClick(); }}>修改报警接收组</Button>
|
||||
<Button type="link" disabled={!canBatchOper} onClick={() => { this.handleBatchModNotifyBtnClick(); }}><FormattedMessage id="stra.batch.modify.notify" /></Button>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<Button type="link" disabled={!canBatchOper} onClick={() => { this.handleBatchCloneToOtherNidBtnClick(); }}>克隆到其他节点</Button>
|
||||
<Button type="link" disabled={!canBatchOper} onClick={() => { this.handleBatchCloneToOtherNidBtnClick(); }}><FormattedMessage id="stra.batch.cloneTo.otherNode" /></Button>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<Button type="link" disabled={!canBatchOper} onClick={() => { this.handleBatchDelBtnClick(); }}>删除策略</Button>
|
||||
<Button type="link" disabled={!canBatchOper} onClick={() => { this.handleBatchDelBtnClick(); }}><FormattedMessage id="stra.batch.delete" /></Button>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<Button type="link" onClick={() => { this.handleBatchImportBtnClick(); }}>导入策略</Button>
|
||||
<Button type="link" onClick={() => { this.handleBatchImportBtnClick(); }}><FormattedMessage id="stra.batch.import" /></Button>
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<Button type="link" disabled={!canBatchOper} onClick={() => { this.handleBatchExportBtnClick(); }}>导出策略</Button>
|
||||
<Button type="link" disabled={!canBatchOper} onClick={() => { this.handleBatchExportBtnClick(); }}><FormattedMessage id="stra.batch.export" /></Button>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
}
|
||||
>
|
||||
<Button icon="down">批量操作</Button>
|
||||
<Button icon="down"><FormattedMessage id="table.batch.operations" /></Button>
|
||||
</Dropdown>
|
||||
</Col>
|
||||
</Row>
|
||||
|
@ -316,14 +324,14 @@ class index extends Component {
|
|||
}}
|
||||
columns={[
|
||||
{
|
||||
title: '策略名称',
|
||||
title: <FormattedMessage id="stra.name" />,
|
||||
dataIndex: 'name',
|
||||
width: 150,
|
||||
render: (text, record) => {
|
||||
return <Link to={{ pathname: `/monitor/strategy/${record.id}` }}>{text}</Link>;
|
||||
},
|
||||
}, {
|
||||
title: '级别',
|
||||
title: <FormattedMessage id="stra.priority" />,
|
||||
width: 40,
|
||||
dataIndex: 'priority',
|
||||
render: (text) => {
|
||||
|
@ -331,7 +339,7 @@ class index extends Component {
|
|||
return <Tag color={currentPriority.color}>{currentPriority.label}</Tag>;
|
||||
},
|
||||
}, {
|
||||
title: '指标',
|
||||
title: <FormattedMessage id="stra.metric" />,
|
||||
width: 100,
|
||||
render: (text, record) => {
|
||||
const { exprs } = record;
|
||||
|
@ -342,7 +350,7 @@ class index extends Component {
|
|||
});
|
||||
},
|
||||
}, {
|
||||
title: '报警接收',
|
||||
title: <FormattedMessage id="stra.notify" />,
|
||||
render: (text, record) => {
|
||||
const { userData, teamData } = this.state;
|
||||
const team = _.map(record.notify_group, (item) => {
|
||||
|
@ -357,7 +365,7 @@ class index extends Component {
|
|||
},
|
||||
}, {
|
||||
width: 90,
|
||||
title: '更新时间',
|
||||
title: <FormattedMessage id="table.lastupdated" />,
|
||||
render: (text, record) => {
|
||||
return (
|
||||
<div>
|
||||
|
@ -367,16 +375,16 @@ class index extends Component {
|
|||
},
|
||||
}, {
|
||||
width: 140,
|
||||
title: '操作',
|
||||
title: <FormattedMessage id="table.operations" />,
|
||||
render: (text, record) => {
|
||||
return (
|
||||
<span className="operation-btns">
|
||||
<Link to={{ pathname: `/monitor/strategy/${record.id}` }}>修改</Link>
|
||||
<Link to={{ pathname: `/monitor/strategy/${record.id}` }}><FormattedMessage id="table.modify" /></Link>
|
||||
<Divider type="vertical" />
|
||||
<Link to={{ pathname: `/monitor/strategy/${record.id}/clone` }}>克隆</Link>
|
||||
<Link to={{ pathname: `/monitor/strategy/${record.id}/clone` }}><FormattedMessage id="table.clone" /></Link>
|
||||
<Divider type="vertical" />
|
||||
<Popconfirm title="是否删除这条策略?" onConfirm={() => { this.handleDel(record.id); }}>
|
||||
<a>删除</a>
|
||||
<Popconfirm title={<FormattedMessage id="table.delete.sure" />} onConfirm={() => { this.handleDel(record.id); }}>
|
||||
<a><FormattedMessage id="table.delete" /></a>
|
||||
</Popconfirm>
|
||||
</span>
|
||||
);
|
||||
|
@ -389,4 +397,4 @@ class index extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default CreateIncludeNsTree(index, { visible: true });
|
||||
export default CreateIncludeNsTree(injectIntl(index), { visible: true });
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component }from 'react';
|
||||
import { injectIntl, WrappedComponentProps } from 'react-intl';
|
||||
import { Modal, Form, Input, message } from 'antd';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
import _ from 'lodash';
|
||||
|
@ -17,10 +18,10 @@ interface Props {
|
|||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
class BatchDel extends Component<Props & FormProps> {
|
||||
class BatchDel extends Component<Props & FormProps & WrappedComponentProps> {
|
||||
static defaultProps = {
|
||||
selectedIps: [],
|
||||
title: '批量删除',
|
||||
title: '',
|
||||
visible: true,
|
||||
onOk: _.noop,
|
||||
onCancel: _.noop,
|
||||
|
@ -28,7 +29,6 @@ class BatchDel extends Component<Props & FormProps> {
|
|||
};
|
||||
|
||||
handleOk = () => {
|
||||
const { title } = this.props;
|
||||
this.props.form!.validateFields((err, values) => {
|
||||
if (!err) {
|
||||
const idents = _.split(values.idents, '\n');
|
||||
|
@ -39,7 +39,7 @@ class BatchDel extends Component<Props & FormProps> {
|
|||
method: 'DELETE',
|
||||
body: JSON.stringify(reqBody),
|
||||
}).then(() => {
|
||||
message.success(`${title}成功`);
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.delete.success' }));
|
||||
this.props.onOk();
|
||||
this.props.destroy();
|
||||
});
|
||||
|
@ -63,10 +63,10 @@ class BatchDel extends Component<Props & FormProps> {
|
|||
onCancel={this.handleCancel}
|
||||
>
|
||||
<Form layout="vertical">
|
||||
<FormItem label="已选 endpoints">
|
||||
<FormItem label="Endpoints">
|
||||
{getFieldDecorator('idents', {
|
||||
initialValue: _.join(selectedIdents, '\n'),
|
||||
rules: [{ required: true, message: '请填写批量操作的 endpoints!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<Input.TextArea
|
||||
autosize={{ minRows: 2, maxRows: 10 }}
|
||||
|
@ -79,4 +79,4 @@ class BatchDel extends Component<Props & FormProps> {
|
|||
}
|
||||
}
|
||||
|
||||
export default ModalControl(Form.create()(BatchDel));
|
||||
export default ModalControl(Form.create()(injectIntl(BatchDel)));
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import React, { Component }from 'react';
|
||||
import { injectIntl, WrappedComponentProps } from 'react-intl';
|
||||
import { Modal, Form, Input, message } from 'antd';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
import _ from 'lodash';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import ModalControl from '@cpts/ModalControl';
|
||||
import request from '@common/request';
|
||||
import api from '@common/api';
|
||||
|
@ -16,9 +18,9 @@ interface Props {
|
|||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
class BatchImport extends Component<Props & FormProps> {
|
||||
class BatchImport extends Component<Props & FormProps & WrappedComponentProps> {
|
||||
static defaultProps = {
|
||||
title: '批量导入',
|
||||
title: '',
|
||||
visible: true,
|
||||
onOk: _.noop,
|
||||
onCancel: _.noop,
|
||||
|
@ -26,7 +28,6 @@ class BatchImport extends Component<Props & FormProps> {
|
|||
};
|
||||
|
||||
handleOk = () => {
|
||||
const { title } = this.props;
|
||||
this.props.form!.validateFields((err, values) => {
|
||||
if (!err) {
|
||||
request(api.endpoint, {
|
||||
|
@ -35,7 +36,7 @@ class BatchImport extends Component<Props & FormProps> {
|
|||
endpoints: _.split(values.endpoints, '\n'),
|
||||
}),
|
||||
}).then(() => {
|
||||
message.success(`${title}成功`);
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.submit.success' }));
|
||||
this.props.onOk();
|
||||
this.props.destroy();
|
||||
});
|
||||
|
@ -60,11 +61,11 @@ class BatchImport extends Component<Props & FormProps> {
|
|||
>
|
||||
<Form layout="vertical">
|
||||
<FormItem
|
||||
label="导入的 endpoints"
|
||||
help="每一条是 ident::alias 拼接在一起"
|
||||
label="Endpoints"
|
||||
help={<FormattedMessage id="endpoints.import.batch.help" />}
|
||||
>
|
||||
{getFieldDecorator('endpoints', {
|
||||
rules: [{ required: true, message: '请填写导入的机器 endpoints!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<Input.TextArea
|
||||
autosize={{ minRows: 2, maxRows: 10 }}
|
||||
|
@ -77,4 +78,4 @@ class BatchImport extends Component<Props & FormProps> {
|
|||
}
|
||||
}
|
||||
|
||||
export default ModalControl(Form.create()(BatchImport));
|
||||
export default ModalControl(Form.create()(injectIntl(BatchImport)));
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Menu, Divider, Popconfirm, message } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import CreateIncludeNsTree from '@cpts/Layout/CreateIncludeNsTree';
|
||||
import exportXlsx from '@common/exportXlsx';
|
||||
import request from '@common/request';
|
||||
|
@ -15,6 +17,10 @@ class index extends Component {
|
|||
endpointList: any;
|
||||
state = {};
|
||||
|
||||
static contextTypes = {
|
||||
intl: PropTypes.any,
|
||||
};
|
||||
|
||||
async exportEndpoints(endpoints: Endpoint[]) {
|
||||
const data = _.map(endpoints, (item) => {
|
||||
return {
|
||||
|
@ -27,7 +33,8 @@ class index extends Component {
|
|||
|
||||
handleModifyBtnClick(record: Endpoint) {
|
||||
EditEndpoint({
|
||||
title: '修改信息',
|
||||
title: this.context.intl.formatMessage({ id: 'table.modify' }),
|
||||
language: this.context.intl.locale,
|
||||
type: 'admin',
|
||||
data: record,
|
||||
onOk: () => {
|
||||
|
@ -50,6 +57,8 @@ class index extends Component {
|
|||
|
||||
handleBatchImport() {
|
||||
BatchImport({
|
||||
title: this.context.intl.formatMessage({ id: 'endpoints.import' }),
|
||||
language: this.context.intl.locale,
|
||||
onOk: () => {
|
||||
this.endpointList.reload();
|
||||
},
|
||||
|
@ -58,6 +67,7 @@ class index extends Component {
|
|||
|
||||
handleBatchDel(selectedIdents: string[]) {
|
||||
BatchDel({
|
||||
language: this.context.intl.locale,
|
||||
selectedIdents,
|
||||
onOk: () => {
|
||||
this.endpointList.reload();
|
||||
|
@ -81,10 +91,12 @@ class index extends Component {
|
|||
renderOper={(record) => {
|
||||
return (
|
||||
<span>
|
||||
<a onClick={() => { this.handleModifyBtnClick(record); }}>修改</a>
|
||||
<a onClick={() => { this.handleModifyBtnClick(record); }}>
|
||||
<FormattedMessage id="table.modify" />
|
||||
</a>
|
||||
<Divider type="vertical" />
|
||||
<Popconfirm title="确认要删除吗?" onConfirm={() => { this.handleDeleteBtnClick(record.ident); }}>
|
||||
<a>删除</a>
|
||||
<Popconfirm title={<FormattedMessage id="table.delete.sure" />} onConfirm={() => { this.handleDeleteBtnClick(record.ident); }}>
|
||||
<a><FormattedMessage id="table.delete" /></a>
|
||||
</Popconfirm>
|
||||
</span>
|
||||
);
|
||||
|
@ -92,10 +104,10 @@ class index extends Component {
|
|||
renderBatchOper={(selectedIdents) => {
|
||||
return [
|
||||
<Menu.Item key="batch-import">
|
||||
<a onClick={() => { this.handleBatchImport(); }}>导入 endpoints</a>
|
||||
<a onClick={() => { this.handleBatchImport(); }}><FormattedMessage id="endpoints.import" /></a>
|
||||
</Menu.Item>,
|
||||
<Menu.Item key="batch-delete">
|
||||
<a onClick={() => { this.handleBatchDel(selectedIdents); }}>删除 endpoints</a>
|
||||
<a onClick={() => { this.handleBatchDel(selectedIdents); }}><FormattedMessage id="endpoints.delete" /></a>
|
||||
</Menu.Item>,
|
||||
];
|
||||
}}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps } from 'react-intl';
|
||||
import { Modal, Form, Input, Checkbox, message } from 'antd';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
import _ from 'lodash';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import ModalControl from '@cpts/ModalControl';
|
||||
import { TreeNode } from '@interface';
|
||||
import request from '@common/request';
|
||||
|
@ -18,9 +20,9 @@ interface Props {
|
|||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
class BatchBind extends Component<Props & FormProps> {
|
||||
class BatchBind extends Component<Props & FormProps & WrappedComponentProps> {
|
||||
static defaultProps = {
|
||||
title: '挂载 endpoints',
|
||||
title: '',
|
||||
visible: true,
|
||||
onOk: _.noop,
|
||||
onCancel: _.noop,
|
||||
|
@ -39,7 +41,7 @@ class BatchBind extends Component<Props & FormProps> {
|
|||
method: 'POST',
|
||||
body: JSON.stringify(reqBody),
|
||||
}).then(() => {
|
||||
message.success('挂载成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.submit.success' }));
|
||||
this.props.onOk();
|
||||
this.props.destroy();
|
||||
});
|
||||
|
@ -63,12 +65,12 @@ class BatchBind extends Component<Props & FormProps> {
|
|||
onCancel={this.handleCancel}
|
||||
>
|
||||
<Form layout="vertical">
|
||||
<FormItem label="挂载的节点">
|
||||
<FormItem label={<FormattedMessage id="endpoints.bind.node" />}>
|
||||
<span className="ant-form-text" style={{ wordBreak: 'break-word' }}>{_.get(selectedNode, 'path')}</span>
|
||||
</FormItem>
|
||||
<FormItem label="待挂载的 endpoint">
|
||||
<FormItem label={<span>Endpoints <FormattedMessage id="endpoints.ident" /></span>}>
|
||||
{getFieldDecorator('idents', {
|
||||
rules: [{ required: true, message: '请填写需要挂载的 endpoints!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<Input.TextArea
|
||||
autosize={{ minRows: 2, maxRows: 10 }}
|
||||
|
@ -77,7 +79,7 @@ class BatchBind extends Component<Props & FormProps> {
|
|||
</FormItem>
|
||||
{getFieldDecorator('del_old', {
|
||||
})(
|
||||
<Checkbox className="mt10">是否删除旧的挂载关系</Checkbox>,
|
||||
<Checkbox className="mt10"><FormattedMessage id="endpoints.delete.old.bind" /></Checkbox>,
|
||||
)}
|
||||
</Form>
|
||||
</Modal>
|
||||
|
@ -85,4 +87,4 @@ class BatchBind extends Component<Props & FormProps> {
|
|||
}
|
||||
}
|
||||
|
||||
export default ModalControl(Form.create()(BatchBind));
|
||||
export default ModalControl(Form.create()(injectIntl(BatchBind)));
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps } from 'react-intl';
|
||||
import { Modal, Form, Input, message } from 'antd';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
import _ from 'lodash';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import ModalControl from '@cpts/ModalControl';
|
||||
import { TreeNode } from '@interface';
|
||||
import request from '@common/request';
|
||||
|
@ -19,9 +21,9 @@ interface Props {
|
|||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
class BatchHostUnbind extends Component<Props & FormProps> {
|
||||
class BatchHostUnbind extends Component<Props & FormProps & WrappedComponentProps> {
|
||||
static defaultProps = {
|
||||
title: '解挂 endpoints',
|
||||
title: '',
|
||||
visible: true,
|
||||
onOk: _.noop,
|
||||
onCancel: _.noop,
|
||||
|
@ -39,7 +41,7 @@ class BatchHostUnbind extends Component<Props & FormProps> {
|
|||
method: 'POST',
|
||||
body: JSON.stringify(reqBody),
|
||||
}).then(() => {
|
||||
message.success('解除挂载成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.submit.success' }));
|
||||
this.props.onOk();
|
||||
this.props.destroy();
|
||||
});
|
||||
|
@ -63,13 +65,13 @@ class BatchHostUnbind extends Component<Props & FormProps> {
|
|||
onCancel={this.handleCancel}
|
||||
>
|
||||
<Form layout="vertical">
|
||||
<FormItem label="解除挂载的节点">
|
||||
<FormItem label={<FormattedMessage id="endpoints.unbind.node" />}>
|
||||
<span className="ant-form-text" style={{ wordBreak: 'break-word' }}>{_.get(selectedNode, 'path')}</span>
|
||||
</FormItem>
|
||||
<FormItem label="待解除挂载的 endpoints">
|
||||
<FormItem label={<span>Endpoints <FormattedMessage id="endpoints.ident" /></span>}>
|
||||
{getFieldDecorator('idents', {
|
||||
initialValue: _.join(selectedIdents, '\n'),
|
||||
rules: [{ required: true, message: '请填写需要解除挂载的机器列表!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<Input.TextArea
|
||||
autosize={{ minRows: 2, maxRows: 10 }}
|
||||
|
@ -82,4 +84,4 @@ class BatchHostUnbind extends Component<Props & FormProps> {
|
|||
}
|
||||
}
|
||||
|
||||
export default ModalControl(Form.create()(BatchHostUnbind));
|
||||
export default ModalControl(Form.create()(injectIntl(BatchHostUnbind)));
|
||||
|
|
|
@ -2,6 +2,7 @@ import React, { Component } from 'react';
|
|||
import PropTypes from 'prop-types';
|
||||
import { Menu } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import CreateIncludeNsTree from '@cpts/Layout/CreateIncludeNsTree';
|
||||
import exportXlsx from '@common/exportXlsx';
|
||||
import api from '@common/api';
|
||||
|
@ -16,6 +17,7 @@ class index extends Component {
|
|||
selectedNodeId: number | undefined = undefined;
|
||||
static contextTypes = {
|
||||
getSelectedNode: PropTypes.func,
|
||||
intl: PropTypes.any,
|
||||
};
|
||||
|
||||
componentWillMount = () => {
|
||||
|
@ -53,6 +55,8 @@ class index extends Component {
|
|||
const { getSelectedNode } = this.context;
|
||||
const selectedNode = getSelectedNode();
|
||||
BatchBind({
|
||||
title: this.context.intl.formatMessage({ id: 'endpoints.bind' }),
|
||||
language: this.context.intl.locale,
|
||||
selectedNode,
|
||||
onOk: () => {
|
||||
this.endpointList.reload();
|
||||
|
@ -64,6 +68,8 @@ class index extends Component {
|
|||
const { getSelectedNode } = this.context;
|
||||
const selectedNode = getSelectedNode();
|
||||
BatchUnbind({
|
||||
title: this.context.intl.formatMessage({ id: 'endpoints.unbind' }),
|
||||
language: this.context.intl.locale,
|
||||
selectedNode,
|
||||
selectedIdents,
|
||||
onOk: () => {
|
||||
|
@ -74,7 +80,8 @@ class index extends Component {
|
|||
|
||||
handleModifyAliasBtnClick = (record: Endpoint) => {
|
||||
EditEndpoint({
|
||||
title: '修改别名',
|
||||
title: this.context.intl.formatMessage({ id: 'table.modify' }),
|
||||
language: this.context.intl.locale,
|
||||
data: record,
|
||||
onOk: () => {
|
||||
this.endpointList.reload();
|
||||
|
@ -86,7 +93,7 @@ class index extends Component {
|
|||
if (!this.selectedNodeId) {
|
||||
return (
|
||||
<div>
|
||||
请先选择左侧服务节点
|
||||
<FormattedMessage id="please.select.node" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -100,17 +107,23 @@ class index extends Component {
|
|||
renderOper={(record) => {
|
||||
return (
|
||||
<span>
|
||||
<a onClick={() => { this.handleModifyAliasBtnClick(record); }}>改别名</a>
|
||||
<a onClick={() => { this.handleModifyAliasBtnClick(record); }}>
|
||||
<FormattedMessage id="endpoints.modify.alias" />
|
||||
</a>
|
||||
</span>
|
||||
);
|
||||
}}
|
||||
renderBatchOper={(selectedIdents) => {
|
||||
return [
|
||||
<Menu.Item key="batch-bind">
|
||||
<a onClick={() => { this.handleHostBindBtnClick(); }}>挂载 endpoint</a>
|
||||
<a onClick={() => { this.handleHostBindBtnClick(); }}>
|
||||
<FormattedMessage id="endpoints.bind" />
|
||||
</a>
|
||||
</Menu.Item>,
|
||||
<Menu.Item key="batch-unbind">
|
||||
<a onClick={() => { this.handleHostUnbindBtnClick(selectedIdents); }}>解挂 endpoint</a>
|
||||
<a onClick={() => { this.handleHostUnbindBtnClick(selectedIdents); }}>
|
||||
<FormattedMessage id="endpoints.unbind" />
|
||||
</a>
|
||||
</Menu.Item>,
|
||||
];
|
||||
}}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Row, Col, Input, Button, Checkbox, Popconfirm, message } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import CreateIncludeNsTree from '@cpts/Layout/CreateIncludeNsTree';
|
||||
import request from '@common/request';
|
||||
import api from '@common/api';
|
||||
|
@ -24,7 +26,7 @@ function updatePathByName(path: string, name: string) {
|
|||
return path;
|
||||
}
|
||||
|
||||
class index extends Component<null, State> {
|
||||
class index extends Component<WrappedComponentProps, State> {
|
||||
static contextTypes = {
|
||||
getSelectedNode: PropTypes.func,
|
||||
updateSelectedNode: PropTypes.func,
|
||||
|
@ -86,7 +88,7 @@ class index extends Component<null, State> {
|
|||
name: selectedNodeName,
|
||||
path: updatePathByName(selectedNode.path, selectedNodeName),
|
||||
});
|
||||
message.success('节点重命名成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'node.rename.success' }));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +111,7 @@ class index extends Component<null, State> {
|
|||
}),
|
||||
}).then(() => {
|
||||
reloadNsTree();
|
||||
message.success('创建子节点成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'node.child.create.success' }));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +125,7 @@ class index extends Component<null, State> {
|
|||
}).then(() => {
|
||||
reloadNsTree();
|
||||
deleteSelectedNode();
|
||||
message.success('节点删除成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'node.delete.success' }));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -135,7 +137,7 @@ class index extends Component<null, State> {
|
|||
if (!selectedNode) {
|
||||
return (
|
||||
<div>
|
||||
请先选择左侧服务节点
|
||||
<FormattedMessage id="please.select.node" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -143,25 +145,25 @@ class index extends Component<null, State> {
|
|||
<div>
|
||||
<Row gutter={20}>
|
||||
<Col span={8} className="mb10">
|
||||
节点重命名:
|
||||
<FormattedMessage id="node.rename" />:
|
||||
<div className="mt10 mb10">
|
||||
<Input
|
||||
style={{ width: 200 }}
|
||||
value={selectedNodeName}
|
||||
onChange={this.handlePutNodeChange}
|
||||
placeholder="新节点名称"
|
||||
placeholder={this.props.intl.formatMessage({ id: 'node.rename.newname' })}
|
||||
/>
|
||||
</div>
|
||||
<Button onClick={this.handlePutNode}>保存</Button>
|
||||
<Button onClick={this.handlePutNode}><FormattedMessage id="form.save" /></Button>
|
||||
</Col>
|
||||
<Col span={8} className="mb10">
|
||||
创建子节点:
|
||||
<FormattedMessage id="node.child.create" />:
|
||||
<div className="mt10 mb10">
|
||||
<Input
|
||||
style={{ width: 200 }}
|
||||
value={newNodeName}
|
||||
onChange={this.handleNewNodeNameChange}
|
||||
placeholder="子节点名称"
|
||||
placeholder={this.props.intl.formatMessage({ id: 'node.child.newname' })}
|
||||
disabled={isLeafNode}
|
||||
/>
|
||||
</div>
|
||||
|
@ -171,24 +173,26 @@ class index extends Component<null, State> {
|
|||
onChange={this.handleNewNodeLeafChange}
|
||||
disabled={isLeafNode}
|
||||
>
|
||||
是否叶子节点
|
||||
<FormattedMessage id="node.isLeaf" />
|
||||
</Checkbox>
|
||||
</div>
|
||||
<Button disabled={isLeafNode} onClick={this.handlePostNode}>创建</Button>
|
||||
<Button disabled={isLeafNode} onClick={this.handlePostNode}>
|
||||
<FormattedMessage id="form.create" />
|
||||
</Button>
|
||||
{
|
||||
isLeafNode ? <p className="fc50 mt10">叶子节点无法继续创建子节点</p> : null
|
||||
isLeafNode ? <p className="fc50 mt10"><FormattedMessage id="node.leaf.cannot.create" /></p> : null
|
||||
}
|
||||
</Col>
|
||||
<Col span={8} className="mb10">
|
||||
删除该节点:
|
||||
<FormattedMessage id="node.delete" />:
|
||||
<div className="mt10 mb10" style={{ wordBreak: 'break-word' }}>
|
||||
{_.get(selectedNode, 'path')}
|
||||
</div>
|
||||
<Popconfirm disabled={isPdlNode} title="确定要删除这个节点吗?" onConfirm={this.handleDelNode}>
|
||||
<Button disabled={isPdlNode}>删除</Button>
|
||||
<Popconfirm disabled={isPdlNode} title={<FormattedMessage id="table.delete.sure" />} onConfirm={this.handleDelNode}>
|
||||
<Button disabled={isPdlNode}><FormattedMessage id="form.delete" /></Button>
|
||||
</Popconfirm>
|
||||
{
|
||||
isPdlNode ? <p className="fc50 mt10">{config.aliasMap.dept}节点不能删除</p> : null
|
||||
isPdlNode ? <p className="fc50 mt10"><FormattedMessage id={`${config.aliasMap.dept}节点不能删除`} /></p> : null
|
||||
}
|
||||
</Col>
|
||||
</Row>
|
||||
|
@ -197,4 +201,4 @@ class index extends Component<null, State> {
|
|||
}
|
||||
}
|
||||
|
||||
export default CreateIncludeNsTree(index, { visible: true });
|
||||
export default CreateIncludeNsTree(injectIntl(index), { visible: true });
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps } from 'react-intl';
|
||||
import { Modal, message } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import ModalControl from '@cpts/ModalControl';
|
||||
|
@ -15,10 +16,10 @@ interface Props {
|
|||
destroy: () => void,
|
||||
}
|
||||
|
||||
class CreateUser extends Component<Props> {
|
||||
class CreateUser extends Component<Props & WrappedComponentProps> {
|
||||
profileFormRef: any;
|
||||
static defaultProps = {
|
||||
title: '新建用户',
|
||||
title: '',
|
||||
visible: true,
|
||||
onOk: _.noop,
|
||||
onCancel: _.noop,
|
||||
|
@ -35,7 +36,7 @@ class CreateUser extends Component<Props> {
|
|||
is_root: values.is_root ? 1 : 0,
|
||||
}),
|
||||
}).then(() => {
|
||||
message.success('新建用户成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.create.success' }));
|
||||
this.props.onOk();
|
||||
this.props.destroy();
|
||||
});
|
||||
|
@ -66,4 +67,4 @@ class CreateUser extends Component<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
export default ModalControl(CreateUser);
|
||||
export default ModalControl(injectIntl(CreateUser));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl';
|
||||
import { Modal, Form, Input, Icon, message } from 'antd';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
import _ from 'lodash';
|
||||
|
@ -17,9 +18,9 @@ interface Props {
|
|||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
class PutPassword extends Component<Props & FormProps> {
|
||||
class PutPassword extends Component<Props & FormProps & WrappedComponentProps> {
|
||||
static defaultProps = {
|
||||
title: '修改密码',
|
||||
title: '',
|
||||
visible: true,
|
||||
onOk: _.noop,
|
||||
onCancel: _.noop,
|
||||
|
@ -33,7 +34,7 @@ class PutPassword extends Component<Props & FormProps> {
|
|||
method: 'PUT',
|
||||
body: JSON.stringify(values),
|
||||
}).then(() => {
|
||||
message.success('密码修改成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'user.reset.password.success' }));
|
||||
this.props.onOk();
|
||||
this.props.destroy();
|
||||
});
|
||||
|
@ -57,9 +58,9 @@ class PutPassword extends Component<Props & FormProps> {
|
|||
onCancel={this.handleCancel}
|
||||
>
|
||||
<Form layout="vertical">
|
||||
<FormItem label="新密码" required>
|
||||
<FormItem label={<FormattedMessage id="password.new" />} required>
|
||||
{getFieldDecorator('password', {
|
||||
rules: [{ required: true, message: '请输入新密码!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<Input
|
||||
prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />}
|
||||
|
@ -73,4 +74,4 @@ class PutPassword extends Component<Props & FormProps> {
|
|||
}
|
||||
}
|
||||
|
||||
export default ModalControl(Form.create()(PutPassword as any));
|
||||
export default ModalControl(Form.create()(injectIntl(PutPassword)));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps } from 'react-intl';
|
||||
import { Modal, message } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import ModalControl from '@cpts/ModalControl';
|
||||
|
@ -17,7 +18,7 @@ interface Props {
|
|||
destroy: () => void,
|
||||
}
|
||||
|
||||
class PutProfile extends Component<Props> {
|
||||
class PutProfile extends Component<Props & WrappedComponentProps> {
|
||||
profileForm: any;
|
||||
|
||||
static defaultProps = {
|
||||
|
@ -38,7 +39,7 @@ class PutProfile extends Component<Props> {
|
|||
is_root: values.is_root ? 1 : 0,
|
||||
}),
|
||||
}).then(() => {
|
||||
message.success('用户信息修改成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.modify.success' }));
|
||||
this.props.onOk();
|
||||
this.props.destroy();
|
||||
});
|
||||
|
@ -72,4 +73,4 @@ class PutProfile extends Component<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
export default ModalControl(PutProfile);
|
||||
export default ModalControl(injectIntl(PutProfile));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl';
|
||||
import { Row, Col, Input, Button, Divider, Popover, Popconfirm, message, Tooltip, Alert } from 'antd';
|
||||
import { ColumnProps } from 'antd/lib/table';
|
||||
import { UserProfile } from '@interface';
|
||||
|
@ -22,7 +23,7 @@ interface State {
|
|||
|
||||
const ButtonGroup = Button.Group;
|
||||
|
||||
class User extends Component<null, State> {
|
||||
class User extends Component<WrappedComponentProps, State> {
|
||||
fetchtable: any;
|
||||
state = {
|
||||
inviteTooltipVisible: false,
|
||||
|
@ -48,6 +49,8 @@ class User extends Component<null, State> {
|
|||
|
||||
handleAddBtnClick = () => {
|
||||
CreateUser({
|
||||
title: this.props.intl.formatMessage({ id: 'user.create' }),
|
||||
language: this.props.intl.locale,
|
||||
onOk: () => {
|
||||
this.fetchtable.reload();
|
||||
},
|
||||
|
@ -56,6 +59,8 @@ class User extends Component<null, State> {
|
|||
|
||||
handlePutBtnClick = (record: UserProfile) => {
|
||||
PutProfile({
|
||||
title: this.props.intl.formatMessage({ id: 'user.modify' }),
|
||||
language: this.props.intl.locale,
|
||||
data: record,
|
||||
onOk: () => {
|
||||
this.fetchtable.reload();
|
||||
|
@ -65,6 +70,8 @@ class User extends Component<null, State> {
|
|||
|
||||
handlePutPassBtnClick = (id: number) => {
|
||||
PutPassword({
|
||||
title: this.props.intl.formatMessage({ id: 'user.reset.password' }),
|
||||
language: this.props.intl.locale,
|
||||
id,
|
||||
onOk: () => {
|
||||
this.fetchtable.reload();
|
||||
|
@ -77,7 +84,7 @@ class User extends Component<null, State> {
|
|||
method: 'DELETE',
|
||||
}).then(() => {
|
||||
this.fetchtable.reload();
|
||||
message.success('用户删除成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.delete.success' }));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -91,44 +98,47 @@ class User extends Component<null, State> {
|
|||
const { isroot } = auth.getSelftProfile();
|
||||
const columns: ColumnProps<UserProfile>[] = [
|
||||
{
|
||||
title: '登录名',
|
||||
title: <FormattedMessage id="user.username" />,
|
||||
dataIndex: 'username',
|
||||
}, {
|
||||
title: '显示名',
|
||||
title: <FormattedMessage id="user.dispname" />,
|
||||
dataIndex: 'dispname',
|
||||
}, {
|
||||
title: '邮箱',
|
||||
title: <FormattedMessage id="user.email" />,
|
||||
dataIndex: 'email',
|
||||
}, {
|
||||
title: '手机',
|
||||
title: <FormattedMessage id="user.phone" />,
|
||||
dataIndex: 'phone',
|
||||
}, {
|
||||
title: 'im',
|
||||
dataIndex: 'im',
|
||||
}, {
|
||||
title: '是否超管',
|
||||
title: <FormattedMessage id="user.isroot" />,
|
||||
dataIndex: 'is_root',
|
||||
width: 70,
|
||||
className: 'textAlignCenter',
|
||||
render: (text) => {
|
||||
return text === 1 ? '是' : '否';
|
||||
if (this.props.intl.locale === 'zh') {
|
||||
return text === 1 ? '是' : '否';
|
||||
}
|
||||
return text === 1 ? 'Y' : 'N';
|
||||
},
|
||||
},
|
||||
];
|
||||
if (isroot) {
|
||||
columns.push({
|
||||
title: '操作',
|
||||
title: <FormattedMessage id="table.operations" />,
|
||||
className: 'textAlignCenter',
|
||||
width: 200,
|
||||
render: (text, record) => {
|
||||
width: this.props.intl.locale === 'zh' ? 200 : 250,
|
||||
render: (_text, record) => {
|
||||
return (
|
||||
<span>
|
||||
<a onClick={() => { this.handlePutPassBtnClick(record.id); }}>重置密码</a>
|
||||
<a onClick={() => { this.handlePutPassBtnClick(record.id); }}><FormattedMessage id="user.reset.password" /></a>
|
||||
<Divider type="vertical" />
|
||||
<a onClick={() => { this.handlePutBtnClick(record); }}>修改信息</a>
|
||||
<a onClick={() => { this.handlePutBtnClick(record); }}><FormattedMessage id="table.modify" /></a>
|
||||
<Divider type="vertical" />
|
||||
<Popconfirm title="确认要删除这个用户吗?" onConfirm={() => { this.handleDelBtnClick(record.id); }}>
|
||||
<a>删除</a>
|
||||
<Popconfirm title={<FormattedMessage id="table.delete.sure" />} onConfirm={() => { this.handleDelBtnClick(record.id); }}>
|
||||
<a><FormattedMessage id="table.delete" /></a>
|
||||
</Popconfirm>
|
||||
</span>
|
||||
);
|
||||
|
@ -149,7 +159,7 @@ class User extends Component<null, State> {
|
|||
<Col span={16} className="textAlignRight">
|
||||
<ButtonGroup>
|
||||
{
|
||||
isroot ? <Button onClick={this.handleAddBtnClick}>新建用户</Button> : null
|
||||
isroot ? <Button onClick={this.handleAddBtnClick}><FormattedMessage id="user.create" /></Button> : null
|
||||
}
|
||||
<Popover
|
||||
trigger="click"
|
||||
|
@ -162,10 +172,10 @@ class User extends Component<null, State> {
|
|||
}}
|
||||
content={
|
||||
copySucceeded ?
|
||||
<Alert message="邀请用户的链接复制成功" type="success" /> :
|
||||
<Alert message={<FormattedMessage id="invite.user.copy.success" />} type="success" /> :
|
||||
<Alert message={
|
||||
<div>
|
||||
<p>复制失败,请手动复制</p>
|
||||
<p><FormattedMessage id="invite.user.copy.faile" /></p>
|
||||
<span>{inviteLink}</span>
|
||||
</div>
|
||||
} type="warning" />
|
||||
|
@ -175,9 +185,9 @@ class User extends Component<null, State> {
|
|||
placement="topRight"
|
||||
visible={inviteTooltipVisible}
|
||||
onVisibleChange={(visible) => { this.setState({ inviteTooltipVisible: visible }); }}
|
||||
title="点击生成一个邀请用户的链接"
|
||||
title={<FormattedMessage id="user.invite.tips" />}
|
||||
>
|
||||
<Button className="ml10" onClick={this.handleInviteBtnClick}>邀请用户</Button>
|
||||
<Button className="ml10" onClick={this.handleInviteBtnClick}><FormattedMessage id="user.invite" /></Button>
|
||||
</Tooltip>
|
||||
</Popover>
|
||||
</ButtonGroup>
|
||||
|
@ -196,4 +206,4 @@ class User extends Component<null, State> {
|
|||
);
|
||||
}
|
||||
}
|
||||
export default CreateIncludeNsTree(User);
|
||||
export default CreateIncludeNsTree(injectIntl(User));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps } from 'react-intl';
|
||||
import { Modal, message } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import ModalControl from '@cpts/ModalControl';
|
||||
|
@ -14,10 +15,10 @@ interface Props {
|
|||
destroy: () => void,
|
||||
}
|
||||
|
||||
class AddTeam extends Component<Props> {
|
||||
class AddTeam extends Component<Props & WrappedComponentProps> {
|
||||
teamFormRef: any;
|
||||
static defaultProps = {
|
||||
title: '编辑团队',
|
||||
static defaultProps: any = {
|
||||
title: '',
|
||||
visible: true,
|
||||
onOk: _.noop,
|
||||
onCancel: _.noop,
|
||||
|
@ -31,7 +32,7 @@ class AddTeam extends Component<Props> {
|
|||
method: 'POST',
|
||||
body: JSON.stringify(values),
|
||||
}).then(() => {
|
||||
message.success('团队创建成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.create.success' }));
|
||||
this.props.onOk();
|
||||
this.props.destroy();
|
||||
});
|
||||
|
@ -61,4 +62,4 @@ class AddTeam extends Component<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
export default ModalControl(AddTeam);
|
||||
export default ModalControl(injectIntl(AddTeam));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, { Component }from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { injectIntl, WrappedComponentProps } from 'react-intl';
|
||||
import { Modal, message } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import ModalControl from '@cpts/ModalControl';
|
||||
|
@ -17,19 +17,10 @@ interface Props {
|
|||
destroy: () => void,
|
||||
}
|
||||
|
||||
class PutTeam extends Component<Props> {
|
||||
class PutTeam extends Component<Props & WrappedComponentProps> {
|
||||
teamFormRef: any;
|
||||
static propTypes = {
|
||||
data: PropTypes.object.isRequired,
|
||||
title: PropTypes.string,
|
||||
visible: PropTypes.bool,
|
||||
onOk: PropTypes.func,
|
||||
onCancel: PropTypes.func,
|
||||
destroy: PropTypes.func,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
title: '编辑团队',
|
||||
static defaultProps: any = {
|
||||
title: '',
|
||||
visible: true,
|
||||
onOk: _.noop,
|
||||
onCancel: _.noop,
|
||||
|
@ -46,7 +37,7 @@ class PutTeam extends Component<Props> {
|
|||
...values,
|
||||
}),
|
||||
}).then(() => {
|
||||
message.success('团队信息修改成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.modify.success' }));
|
||||
this.props.onOk();
|
||||
this.props.destroy();
|
||||
});
|
||||
|
@ -77,4 +68,4 @@ class PutTeam extends Component<Props> {
|
|||
}
|
||||
}
|
||||
|
||||
export default ModalControl(PutTeam);
|
||||
export default ModalControl(injectIntl(PutTeam));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component }from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Form, Input, Radio, Select, Spin } from 'antd';
|
||||
import { FormProps } from 'antd/lib/form';
|
||||
import _ from 'lodash';
|
||||
|
@ -21,13 +22,13 @@ const RadioGroup = Radio.Group;
|
|||
const { Option } = Select;
|
||||
|
||||
class TeamForm extends Component<Props & FormProps, State> {
|
||||
static defaultProps = {
|
||||
initialValue: {},
|
||||
static defaultProps: any = {
|
||||
initialValue: {} as any,
|
||||
};
|
||||
|
||||
lastFetchId = 0;
|
||||
|
||||
constructor(props: Props) {
|
||||
constructor(props: Props & FormProps) {
|
||||
super(props);
|
||||
this.fetchUser = _.debounce(this.fetchUser, 500);
|
||||
}
|
||||
|
@ -89,48 +90,48 @@ class TeamForm extends Component<Props & FormProps, State> {
|
|||
const { getFieldDecorator, getFieldValue } = this.props.form!;
|
||||
return (
|
||||
<Form layout="vertical">
|
||||
<FormItem label="英文标识" required>
|
||||
<FormItem label={<FormattedMessage id="team.ident" />} required>
|
||||
{getFieldDecorator('ident', {
|
||||
initialValue: initialValue.ident,
|
||||
rules: [{ required: true, message: '请填写英文标识!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<Input />,
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem label="中文名称" required>
|
||||
<FormItem label={<FormattedMessage id="team.name" />} required>
|
||||
{getFieldDecorator('name', {
|
||||
initialValue: initialValue.name,
|
||||
rules: [{ required: true, message: '请填写中文名称!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<Input />,
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem label="管理方式" required>
|
||||
<FormItem label={<FormattedMessage id="team.mgmt" />} required>
|
||||
{getFieldDecorator('mgmt', {
|
||||
initialValue: initialValue.mgmt || 0,
|
||||
rules: [{ required: true, message: '请选择管理方式!' }],
|
||||
rules: [{ required: true }],
|
||||
})(
|
||||
<RadioGroup>
|
||||
<Radio value={0}>成员管理制</Radio>
|
||||
<Radio value={1}>管理员管理制</Radio>
|
||||
<Radio value={0}><FormattedMessage id="team.mgmt.member" /></Radio>
|
||||
<Radio value={1}><FormattedMessage id="team.mgmt.admin" /></Radio>
|
||||
</RadioGroup>,
|
||||
)}
|
||||
</FormItem>
|
||||
{
|
||||
getFieldValue('mgmt') === 1 ?
|
||||
<FormItem label="管理员">
|
||||
<FormItem label={<FormattedMessage id="team.admins" />}>
|
||||
{getFieldDecorator('admins', {
|
||||
initialValue: initialValue.admins,
|
||||
rules: [{
|
||||
required: getFieldValue('mgmt') === 1,
|
||||
message: '管理员管理制必须选择管理员!',
|
||||
// message: '管理员管理制必须选择管理员!',
|
||||
}],
|
||||
})(
|
||||
this.renderUserSelect(),
|
||||
)}
|
||||
</FormItem> : null
|
||||
}
|
||||
<FormItem label="普通组员">
|
||||
<FormItem label={<FormattedMessage id="team.members" />}>
|
||||
{getFieldDecorator('members', {
|
||||
initialValue: initialValue.members,
|
||||
})(
|
||||
|
@ -142,4 +143,4 @@ class TeamForm extends Component<Props & FormProps, State> {
|
|||
}
|
||||
}
|
||||
|
||||
export default Form.create()(TeamForm as any);
|
||||
export default Form.create()(TeamForm);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import React, { Component } from 'react';
|
||||
import { injectIntl, WrappedComponentProps, FormattedMessage } from 'react-intl';
|
||||
import { Row, Col, Input, Divider, Popconfirm, Button, message } from 'antd';
|
||||
import _ from 'lodash';
|
||||
import CreateIncludeNsTree from '@cpts/Layout/CreateIncludeNsTree';
|
||||
|
@ -13,13 +14,15 @@ interface State {
|
|||
searchValue: string,
|
||||
}
|
||||
|
||||
class UserTeam extends Component<null, State> {
|
||||
class UserTeam extends Component<WrappedComponentProps, State> {
|
||||
fetchtable: any;
|
||||
|
||||
state = {} as State;
|
||||
|
||||
handleAddBtnClick = () => {
|
||||
AddTeam({
|
||||
title: <FormattedMessage id="table.create" />,
|
||||
language: this.props.intl.locale,
|
||||
onOk: () => {
|
||||
this.fetchtable.reload();
|
||||
},
|
||||
|
@ -28,6 +31,8 @@ class UserTeam extends Component<null, State> {
|
|||
|
||||
handlePutBtnClick = (record: Team) => {
|
||||
PutTeam({
|
||||
title: <FormattedMessage id="table.modify" />,
|
||||
language: this.props.intl.locale,
|
||||
data: {
|
||||
...record,
|
||||
admins: _.map(record.admin_objs, n => n.id),
|
||||
|
@ -44,7 +49,7 @@ class UserTeam extends Component<null, State> {
|
|||
method: 'DELETE',
|
||||
}).then(() => {
|
||||
this.fetchtable.reload();
|
||||
message.success('团队删除成功!');
|
||||
message.success(this.props.intl.formatMessage({ id: 'msg.delete.success' }));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -61,7 +66,9 @@ class UserTeam extends Component<null, State> {
|
|||
/>
|
||||
</Col>
|
||||
<Col span={16} className="textAlignRight">
|
||||
<Button onClick={this.handleAddBtnClick} icon="plus">新建团队</Button>
|
||||
<Button onClick={this.handleAddBtnClick} icon="plus">
|
||||
<FormattedMessage id="table.create" />
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
<FetchTable
|
||||
|
@ -72,37 +79,37 @@ class UserTeam extends Component<null, State> {
|
|||
tableProps={{
|
||||
columns: [
|
||||
{
|
||||
title: '英文标识',
|
||||
title: <FormattedMessage id="team.ident" />,
|
||||
dataIndex: 'ident',
|
||||
width: 130,
|
||||
}, {
|
||||
title: '中文名称',
|
||||
title: <FormattedMessage id="team.name" />,
|
||||
dataIndex: 'name',
|
||||
width: 130,
|
||||
}, {
|
||||
title: '管理员',
|
||||
title: <FormattedMessage id="team.admins" />,
|
||||
dataIndex: 'admin_objs',
|
||||
render(text) {
|
||||
const users = _.map(text, item => item.username);
|
||||
return _.join(users, ', ');
|
||||
},
|
||||
}, {
|
||||
title: '普通成员',
|
||||
title: <FormattedMessage id="team.members" />,
|
||||
dataIndex: 'member_objs',
|
||||
render(text) {
|
||||
const users = _.map(text, item => item.username);
|
||||
return _.join(users, ', ');
|
||||
},
|
||||
}, {
|
||||
title: '操作',
|
||||
width: 100,
|
||||
render: (text, record) => {
|
||||
title: <FormattedMessage id="table.operations" />,
|
||||
width: this.props.intl.locale === 'zh' ? 100 : 150,
|
||||
render: (_text, record) => {
|
||||
return (
|
||||
<span>
|
||||
<a onClick={() => { this.handlePutBtnClick(record); }}>编辑</a>
|
||||
<a onClick={() => { this.handlePutBtnClick(record); }}><FormattedMessage id="table.modify" /></a>
|
||||
<Divider type="vertical" />
|
||||
<Popconfirm title="确认要删除这个团队吗?" onConfirm={() => { this.handleDelBtnClick(record.id); }}>
|
||||
<a>删除</a>
|
||||
<Popconfirm title={<FormattedMessage id="table.delete.sure" />} onConfirm={() => { this.handleDelBtnClick(record.id); }}>
|
||||
<a><FormattedMessage id="table.delete" /></a>
|
||||
</Popconfirm>
|
||||
</span>
|
||||
);
|
||||
|
@ -115,4 +122,4 @@ class UserTeam extends Component<null, State> {
|
|||
);
|
||||
}
|
||||
}
|
||||
export default CreateIncludeNsTree(UserTeam);
|
||||
export default CreateIncludeNsTree(injectIntl(UserTeam));
|
||||
|
|
Loading…
Reference in New Issue