Merge branch 'v1.0'

This commit is contained in:
liugq 2021-11-22 14:57:43 +08:00
commit b51415a495
25 changed files with 2748 additions and 1939 deletions

View File

@ -18,7 +18,7 @@ export default [
authority: ["admin", "user"], authority: ["admin", "user"],
routes: [ routes: [
// cluster // cluster
{ path: "/", redirect: "/cluster/overview" }, { path: "/", redirect: "/cluster/metrics" },
{ {
path: "/cluster", path: "/cluster",
name: "cluster", name: "cluster",
@ -33,20 +33,20 @@ export default [
// { path: '/', redirect: '/' }, // { path: '/', redirect: '/' },
// ], // ],
// }, // },
{ // {
path: "/cluster/overview", // path: "/cluster/overview",
name: "overview", // name: "overview",
component: "./Cluster/NewOverview", // component: "./Cluster/NewOverview",
// hideInMenu: true, // // hideInMenu: true,
routes: [{ path: "/", redirect: "/" }], // routes: [{ path: "/", redirect: "/" }],
}, // },
{ // {
path: "/cluster/monitoring/:cluster_id", // path: "/cluster/monitoring/:cluster_id",
name: "cluster", // name: "cluster",
component: "./Cluster/ClusterMonitor", // component: "./Cluster/ClusterMonitor",
hideInMenu: true, // hideInMenu: true,
routes: [{ path: "/", redirect: "/" }], // routes: [{ path: "/", redirect: "/" }],
}, // },
{ {
path: "/cluster/metrics/", path: "/cluster/metrics/",
name: "monitoring", name: "monitoring",
@ -101,243 +101,243 @@ export default [
// }, // },
//alerting //alerting
{ // {
path: "/alerting", // path: "/alerting",
name: "alerting", // name: "alerting",
icon: "alert", // icon: "alert",
routes: [ // routes: [
{ // {
routes: [{ path: "/", redirect: "/" }], // routes: [{ path: "/", redirect: "/" }],
path: "/alerting/overview", // path: "/alerting/overview",
component: "./Alerting/pages/Overview/Overview", // component: "./Alerting/pages/Overview/Overview",
name: "overview", // name: "overview",
}, // },
{ // {
routes: [{ path: "/", redirect: "/" }], // routes: [{ path: "/", redirect: "/" }],
path: "/alerting/monitor", // path: "/alerting/monitor",
component: "./Alerting/index", // component: "./Alerting/index",
name: "monitor", // name: "monitor",
}, // },
{ // {
routes: [{ path: "/", redirect: "/" }], // routes: [{ path: "/", redirect: "/" }],
path: "/alerting/destination", // path: "/alerting/destination",
component: "./Alerting/destination", // component: "./Alerting/destination",
name: "destination", // name: "destination",
}, // },
], // ],
}, // },
//data //data
{ // {
path: "/data", // path: "/data",
name: "data", // name: "data",
icon: "database", // icon: "database",
routes: [ // routes: [
// { // // {
// path: '/data/overview', // // path: '/data/overview',
// name: 'overview', // // name: 'overview',
// component: './DataManagement/IndexSummary', // // component: './DataManagement/IndexSummary',
// routes:[ // // routes:[
// { path: '/', redirect: '/' }, // // { path: '/', redirect: '/' },
// ], // // ],
// }, // // },
{ // {
path: "/data/index", // path: "/data/index",
name: "index", // name: "index",
component: "./DataManagement/Index", // component: "./DataManagement/Index",
routes: [{ path: "/", redirect: "/" }], // routes: [{ path: "/", redirect: "/" }],
}, // },
// { // // {
// path: '/data/document', // // path: '/data/document',
// name: 'document', // // name: 'document',
// component: './DataManagement/Document', // // component: './DataManagement/Document',
// routes:[ // // routes:[
// { path: '/', redirect: '/' }, // // { path: '/', redirect: '/' },
// ], // // ],
// }, // // },
// { // // {
// path: '/data/template', // // path: '/data/template',
// name: 'template', // // name: 'template',
// component: './DataManagement/IndexTemplate', // // component: './DataManagement/IndexTemplate',
// routes:[ // // routes:[
// { path: '/', redirect: '/' }, // // { path: '/', redirect: '/' },
// ], // // ],
// }, // // },
// { // // {
// path: '/data/lifecycle', // // path: '/data/lifecycle',
// name: 'lifecycle', // // name: 'lifecycle',
// component: './DataManagement/IndexLifeCycle', // // component: './DataManagement/IndexLifeCycle',
// routes:[ // // routes:[
// { path: '/', redirect: '/' }, // // { path: '/', redirect: '/' },
// ], // // ],
// }, // // },
{ // {
routes: [{ path: "/", redirect: "/" }], // routes: [{ path: "/", redirect: "/" }],
path: "/data/discover", // path: "/data/discover",
name: "discover", // name: "discover",
component: "./DataManagement/Discover", // component: "./DataManagement/Discover",
}, // },
{ // {
routes: [{ path: "/", redirect: "/" }], // routes: [{ path: "/", redirect: "/" }],
path: "/data/views/", // path: "/data/views/",
name: "indexPatterns", // name: "indexPatterns",
component: "./DataManagement/IndexPatterns", // component: "./DataManagement/IndexPatterns",
}, // },
], // ],
}, // },
//search //search
{ // {
path: "/search", // path: "/search",
name: "search", // name: "search",
icon: "search", // icon: "search",
routes: [ // routes: [
// { // // {
// path: '/search/overview', // // path: '/search/overview',
// name: 'overview', // // name: 'overview',
// component: './SearchManage/template/Template', // // component: './SearchManage/template/Template',
// routes:[ // // routes:[
// { path: '/', redirect: '/' }, // // { path: '/', redirect: '/' },
// ], // // ],
// }, // // },
// { // // {
// path: '/search/template', // // path: '/search/template',
// name: 'template', // // name: 'template',
// component: './SearchManage/template/Template', // // component: './SearchManage/template/Template',
// routes: [ // // routes: [
// { // // {
// path: '/search/template', // // path: '/search/template',
// redirect: '/search/template/template', // // redirect: '/search/template/template',
// }, // // },
// { // // {
// path: '/search/template/template', // // path: '/search/template/template',
// component: './SearchManage/template/SearchTemplate', // // component: './SearchManage/template/SearchTemplate',
// routes:[ // // routes:[
// { path: '/', redirect: '/' }, // // { path: '/', redirect: '/' },
// ], // // ],
// }, // // },
// { // // {
// path: '/search/template/:cluster_id', // // path: '/search/template/:cluster_id',
// component: './SearchManage/template/SearchTemplate', // // component: './SearchManage/template/SearchTemplate',
// routes:[ // // routes:[
// { path: '/', redirect: '/' }, // // { path: '/', redirect: '/' },
// ], // // ],
// }, // // },
// { // // {
// path: '/search/template/history', // // path: '/search/template/history',
// component: './SearchManage/template/History', // // component: './SearchManage/template/History',
// routes:[ // // routes:[
// { path: '/', redirect: '/' }, // // { path: '/', redirect: '/' },
// ], // // ],
// }, // // },
// ] // // ]
// }, // // },
{ // {
path: "/search/alias", // path: "/search/alias",
name: "alias", // name: "alias",
component: "./SearchManage/alias/Alias", // component: "./SearchManage/alias/Alias",
routes: [ // routes: [
{ // {
path: "/search/alias", // path: "/search/alias",
redirect: "/search/alias/index", // redirect: "/search/alias/index",
// routes:[ // // routes:[
// { path: '/', redirect: '/' }, // // { path: '/', redirect: '/' },
// ], // // ],
}, // },
{ // {
path: "/search/alias/index", // path: "/search/alias/index",
component: "./SearchManage/alias/AliasManage", // component: "./SearchManage/alias/AliasManage",
routes: [{ path: "/", redirect: "/" }], // routes: [{ path: "/", redirect: "/" }],
}, // },
{ // {
path: "/search/alias/rule", // path: "/search/alias/rule",
component: "./SearchManage/alias/Rule", // component: "./SearchManage/alias/Rule",
routes: [{ path: "/", redirect: "/" }], // routes: [{ path: "/", redirect: "/" }],
}, // },
], // ],
}, // },
// { // // {
// path: '/search/dict', // // path: '/search/dict',
// name: 'dict', // // name: 'dict',
// component: './SearchManage/dict/Dict', // // component: './SearchManage/dict/Dict',
// routes: [ // // routes: [
// { // // {
// path: '/search/dict', // // path: '/search/dict',
// redirect: '/search/dict/professional', // // redirect: '/search/dict/professional',
// // routes:[ // // // routes:[
// // { path: '/', redirect: '/' }, // // // { path: '/', redirect: '/' },
// // ], // // // ],
// }, // // },
// { // // {
// path: '/search/dict/professional', // // path: '/search/dict/professional',
// component: './SearchManage/dict/Pro', // // component: './SearchManage/dict/Pro',
// routes:[ // // routes:[
// { path: '/', redirect: '/' }, // // { path: '/', redirect: '/' },
// ], // // ],
// }, // // },
// { // // {
// path: '/search/dict/common', // // path: '/search/dict/common',
// component: './SearchManage/dict/Common', // // component: './SearchManage/dict/Common',
// routes:[ // // routes:[
// { path: '/', redirect: '/' }, // // { path: '/', redirect: '/' },
// ], // // ],
// } // // }
// ] // // ]
// }, // // },
// { // // {
// path: '/search/analyzer', // // path: '/search/analyzer',
// name: 'analyzer', // // name: 'analyzer',
// component: './SearchManage/analyzer/Analyzer', // // component: './SearchManage/analyzer/Analyzer',
// routes: [ // // routes: [
// { // // {
// path: '/search/analyzer', // // path: '/search/analyzer',
// redirect: '/search/analyzer/manage', // // redirect: '/search/analyzer/manage',
// }, // // },
// { // // {
// path: '/search/analyzer/manage', // // path: '/search/analyzer/manage',
// component: './SearchManage/analyzer/Manage', // // component: './SearchManage/analyzer/Manage',
// routes:[ // // routes:[
// { path: '/', redirect: '/' }, // // { path: '/', redirect: '/' },
// ], // // ],
// }, // // },
// { // // {
// path: '/search/analyzer/test', // // path: '/search/analyzer/test',
// component: './SearchManage/analyzer/AnalyzerTest', // // component: './SearchManage/analyzer/AnalyzerTest',
// routes:[ // // routes:[
// { path: '/', redirect: '/' }, // // { path: '/', redirect: '/' },
// ], // // ],
// } // // }
// ] // // ]
// } // // }
//, { // //, {
// path: '/search/nlp', // // path: '/search/nlp',
// name: 'nlp', // // name: 'nlp',
// component: './SearchManage/nlp/NLP', // // component: './SearchManage/nlp/NLP',
// routes: [ // // routes: [
// { // // {
// path: '/search/nlp', // // path: '/search/nlp',
// redirect: '/search/nlp/query', // // redirect: '/search/nlp/query',
// }, // // },
// { // // {
// path: '/search/nlp/query', // // path: '/search/nlp/query',
// component: './SearchManage/nlp/Query', // // component: './SearchManage/nlp/Query',
// }, // // },
// { // // {
// path: '/search/nlp/intention', // // path: '/search/nlp/intention',
// component: './SearchManage/nlp/Intention', // // component: './SearchManage/nlp/Intention',
// }, // // },
// { // // {
// path: '/search/nlp/knowledge', // // path: '/search/nlp/knowledge',
// component: './SearchManage/nlp/Knowledge', // // component: './SearchManage/nlp/Knowledge',
// }, // // },
// { // // {
// path: '/search/nlp/text', // // path: '/search/nlp/text',
// component: './SearchManage/nlp/Text', // // component: './SearchManage/nlp/Text',
// } // // }
//] // //]
//}, // //},
], // ],
}, // },
// //
// //sync // //sync
// { // {

View File

@ -119,6 +119,14 @@ export default class GlobalHeaderRight extends PureComponent {
{" "} {" "}
<Icon type="code" /> <Icon type="code" />
</a> </a>
<a
className={styles.action}
target="_blank"
href="https://www.infinilabs.com"
>
{" "}
<Icon type="question-circle" />
</a>
{/* <NoticeIcon {/* <NoticeIcon
className={styles.action} className={styles.action}
@ -172,7 +180,10 @@ export default class GlobalHeaderRight extends PureComponent {
) : ( ) : (
<Spin size="small" style={{ marginLeft: 8, marginRight: 8 }} /> <Spin size="small" style={{ marginLeft: 8, marginRight: 8 }} />
)} */} )} */}
<SelectLang className={styles.action} /> <a className={styles.action}>
<SelectLang />
</a>
<div <div
style={{ style={{
display: this.state.consoleVisible ? "block" : "none", display: this.state.consoleVisible ? "block" : "none",

View File

@ -1,8 +1,8 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from "react";
import { formatMessage, setLocale, getLocale } from 'umi/locale'; import { formatMessage, setLocale, getLocale } from "umi/locale";
import { Menu, Icon, Dropdown } from 'antd'; import { Menu, Icon, Dropdown } from "antd";
import classNames from 'classnames'; import classNames from "classnames";
import styles from './index.less'; import styles from "./index.less";
export default class SelectLang extends PureComponent { export default class SelectLang extends PureComponent {
changLang = ({ key }) => { changLang = ({ key }) => {
@ -13,21 +13,24 @@ export default class SelectLang extends PureComponent {
const { className } = this.props; const { className } = this.props;
const selectedLang = getLocale(); const selectedLang = getLocale();
const langMenu = ( const langMenu = (
<Menu className={styles.menu} selectedKeys={[selectedLang]} onClick={this.changLang}> <Menu
className={styles.menu}
selectedKeys={[selectedLang]}
onClick={this.changLang}
>
<Menu.Item key="zh-CN"> <Menu.Item key="zh-CN">
<span role="img" aria-label="简体中文"> <span role="img" aria-label="简体中文">
🇨🇳 🇨🇳
</span>{' '} </span>{" "}
简体中文 简体中文
</Menu.Item> </Menu.Item>
<Menu.Item key="en-US"> <Menu.Item key="en-US">
<span role="img" aria-label="English"> <span role="img" aria-label="English">
🇬🇧 🇬🇧
</span>{' '} </span>{" "}
English English
</Menu.Item> </Menu.Item>
</Menu> </Menu>
); );
return ( return (
@ -35,7 +38,7 @@ export default class SelectLang extends PureComponent {
<Icon <Icon
type="global" type="global"
className={classNames(styles.dropDown, className)} className={classNames(styles.dropDown, className)}
title={formatMessage({ id: 'navBar.lang' })} title={formatMessage({ id: "navBar.lang" })}
/> />
</Dropdown> </Dropdown>
); );

View File

@ -30,9 +30,9 @@
* GitHub history for details. * GitHub history for details.
*/ */
import $ from 'jquery'; import $ from "jquery";
import _ from 'lodash'; import _ from "lodash";
import * as es from '../es'; import * as es from "../es";
// NOTE: If this value ever changes to be a few seconds or less, it might introduce flakiness // NOTE: If this value ever changes to be a few seconds or less, it might introduce flakiness
// due to timing issues in our app.js tests. // due to timing issues in our app.js tests.
@ -45,7 +45,7 @@ let templates = {};
//new add //new add
let commands = []; let commands = [];
const mappingObj = {}; const mappingObj = {};
let clusterID = ''; let clusterID = "";
export function expandAliases(indicesOrAliases, clusterID) { export function expandAliases(indicesOrAliases, clusterID) {
const clusterPerAliasIndexes = perAliasIndexes[clusterID] || {}; const clusterPerAliasIndexes = perAliasIndexes[clusterID] || {};
@ -56,10 +56,10 @@ export function expandAliases(indicesOrAliases, clusterID) {
return indicesOrAliases; return indicesOrAliases;
} }
if (typeof indicesOrAliases === 'string') { if (typeof indicesOrAliases === "string") {
indicesOrAliases = [indicesOrAliases]; indicesOrAliases = [indicesOrAliases];
} }
indicesOrAliases = $.map(indicesOrAliases, function (iOrA) { indicesOrAliases = $.map(indicesOrAliases, function(iOrA) {
if (clusterPerAliasIndexes[iOrA]) { if (clusterPerAliasIndexes[iOrA]) {
return clusterPerAliasIndexes[iOrA]; return clusterPerAliasIndexes[iOrA];
} }
@ -68,7 +68,7 @@ export function expandAliases(indicesOrAliases, clusterID) {
let ret = [].concat.apply([], indicesOrAliases); let ret = [].concat.apply([], indicesOrAliases);
ret.sort(); ret.sort();
let last; let last;
ret = $.map(ret, function (v) { ret = $.map(ret, function(v) {
const r = last === v ? null : v; const r = last === v ? null : v;
last = v; last = v;
return r; return r;
@ -83,24 +83,24 @@ export function getTemplates(key) {
} }
export function getFields(indices, types, key) { export function getFields(indices, types, key) {
key = key || clusterID key = key || clusterID;
const clusterPerIndexTypes = perIndexTypes[key] || {}; const clusterPerIndexTypes = perIndexTypes[key] || {};
// get fields for indices and types. Both can be a list, a string or null (meaning all). // get fields for indices and types. Both can be a list, a string or null (meaning all).
let ret = []; let ret = [];
indices = expandAliases(indices, key); indices = expandAliases(indices, key);
if (typeof indices === 'string') { if (typeof indices === "string") {
const typeDict = clusterPerIndexTypes[indices]; const typeDict = clusterPerIndexTypes[indices];
if (!typeDict) { if (!typeDict) {
return []; return [];
} }
if (typeof types === 'string') { if (typeof types === "string") {
const f = typeDict[types]; const f = typeDict[types];
ret = f ? f : []; ret = f ? f : [];
} else { } else {
// filter what we need // filter what we need
$.each(typeDict, function (type, fields) { $.each(typeDict, function(type, fields) {
if (!types || types.length === 0 || $.inArray(type, types) !== -1) { if (!types || types.length === 0 || $.inArray(type, types) !== -1) {
ret.push(fields); ret.push(fields);
} }
@ -110,16 +110,20 @@ export function getFields(indices, types, key) {
} }
} else { } else {
// multi index mode. // multi index mode.
$.each(clusterPerIndexTypes, function (index) { $.each(clusterPerIndexTypes, function(index) {
if (!indices || indices.length === 0 || $.inArray(index, indices) !== -1) { if (
!indices ||
indices.length === 0 ||
$.inArray(index, indices) !== -1
) {
ret.push(getFields(index, types, key)); ret.push(getFields(index, types, key));
} }
}); });
ret = [].concat.apply([], ret); ret = [].concat.apply([], ret);
} }
return _.uniqBy(ret, function (f) { return _.uniqBy(ret, function(f) {
return f.name + ':' + f.type; return f.name + ":" + f.type;
}); });
} }
@ -127,19 +131,19 @@ export function getTypes(indices, clusterID) {
const clusterPerIndexTypes = perIndexTypes[clusterID] || {}; const clusterPerIndexTypes = perIndexTypes[clusterID] || {};
let ret = []; let ret = [];
indices = expandAliases(indices, clusterID); indices = expandAliases(indices, clusterID);
if (typeof indices === 'string') { if (typeof indices === "string") {
const typeDict = clusterPerIndexTypes[indices]; const typeDict = clusterPerIndexTypes[indices];
if (!typeDict) { if (!typeDict) {
return []; return [];
} }
// filter what we need // filter what we need
$.each(typeDict, function (type) { $.each(typeDict, function(type) {
ret.push(type); ret.push(type);
}); });
} else { } else {
// multi index mode. // multi index mode.
$.each(clusterPerIndexTypes, function (index) { $.each(clusterPerIndexTypes, function(index) {
if (!indices || $.inArray(index, indices) !== -1) { if (!indices || $.inArray(index, indices) !== -1) {
ret.push(getTypes(index, clusterID)); ret.push(getTypes(index, clusterID));
} }
@ -151,17 +155,17 @@ export function getTypes(indices, clusterID) {
} }
export function getIndices(includeAliases, key) { export function getIndices(includeAliases, key) {
if(typeof key != 'string') { if (typeof key != "string") {
key = key?.editor?.clusterID || clusterID key = key?.editor?.clusterID || clusterID;
} }
const clusterPerIndexTypes = perIndexTypes[key] || {}; const clusterPerIndexTypes = perIndexTypes[key] || {};
const clusterPerAliasIndexes = perAliasIndexes[key] || []; const clusterPerAliasIndexes = perAliasIndexes[key] || [];
const ret = []; const ret = [];
$.each(clusterPerIndexTypes, function (index) { $.each(clusterPerIndexTypes, function(index) {
ret.push(index); ret.push(index);
}); });
if (typeof includeAliases === 'undefined' ? true : includeAliases) { if (typeof includeAliases === "undefined" ? true : includeAliases) {
$.each(clusterPerAliasIndexes, function (alias) { $.each(clusterPerAliasIndexes, function(alias) {
ret.push(alias); ret.push(alias);
}); });
} }
@ -175,10 +179,10 @@ function getFieldNamesFromFieldMapping(fieldName, fieldMapping) {
let nestedFields; let nestedFields;
function applyPathSettings(nestedFieldNames) { function applyPathSettings(nestedFieldNames) {
const pathType = fieldMapping.path || 'full'; const pathType = fieldMapping.path || "full";
if (pathType === 'full') { if (pathType === "full") {
return $.map(nestedFieldNames, function (f) { return $.map(nestedFieldNames, function(f) {
f.name = fieldName + '.' + f.name; f.name = fieldName + "." + f.name;
return f; return f;
}); });
} }
@ -200,7 +204,10 @@ function getFieldNamesFromFieldMapping(fieldName, fieldMapping) {
} }
if (fieldMapping.fields) { if (fieldMapping.fields) {
nestedFields = $.map(fieldMapping.fields, function (fieldMapping, fieldName) { nestedFields = $.map(fieldMapping.fields, function(
fieldMapping,
fieldName
) {
return getFieldNamesFromFieldMapping(fieldName, fieldMapping); return getFieldNamesFromFieldMapping(fieldName, fieldMapping);
}); });
nestedFields = applyPathSettings(nestedFields); nestedFields = applyPathSettings(nestedFields);
@ -212,13 +219,13 @@ function getFieldNamesFromFieldMapping(fieldName, fieldMapping) {
} }
function getFieldNamesFromProperties(properties = {}) { function getFieldNamesFromProperties(properties = {}) {
const fieldList = $.map(properties, function (fieldMapping, fieldName) { const fieldList = $.map(properties, function(fieldMapping, fieldName) {
return getFieldNamesFromFieldMapping(fieldName, fieldMapping); return getFieldNamesFromFieldMapping(fieldName, fieldMapping);
}); });
// deduping // deduping
return _.uniqBy(fieldList, function (f) { return _.uniqBy(fieldList, function(f) {
return f.name + ':' + f.type; return f.name + ":" + f.type;
}); });
} }
@ -228,29 +235,31 @@ function loadTemplates(templatesObject = {}, clusterID) {
} }
function getRawBody(body) { function getRawBody(body) {
if(body.response_body){ if (body.response_body) {
return JSON.parse(body.response_body); return JSON.parse(body.response_body);
} }
return body; return body;
} }
export function loadMappings(mappings, clusterID) { export function loadMappings(mappings, clusterID) {
mappings = getRawBody(mappings) mappings = getRawBody(mappings);
let clusterPerIndexTypes = {}; let clusterPerIndexTypes = {};
$.each(mappings, function (index, indexMapping) { $.each(mappings, function(index, indexMapping) {
const normalizedIndexMappings = {}; const normalizedIndexMappings = {};
// Migrate 1.0.0 mappings. This format has changed, so we need to extract the underlying mapping. // Migrate 1.0.0 mappings. This format has changed, so we need to extract the underlying mapping.
if (indexMapping.mappings && _.keys(indexMapping).length === 1) { if (indexMapping.mappings && _.keys(indexMapping).length === 1) {
indexMapping = indexMapping.mappings; indexMapping = indexMapping.mappings;
} }
$.each(indexMapping, function (typeName, typeMapping) { $.each(indexMapping, function(typeName, typeMapping) {
if (typeName === 'properties') { if (typeName === "properties") {
const fieldList = getFieldNamesFromProperties(typeMapping); const fieldList = getFieldNamesFromProperties(typeMapping);
normalizedIndexMappings[typeName] = fieldList; normalizedIndexMappings[typeName] = fieldList;
} else { } else {
normalizedIndexMappings[typeName] = getFieldNamesFromProperties(typeMapping.properties); // for es 2.x, 5.x, 6.x normalizedIndexMappings[typeName] = getFieldNamesFromProperties(
typeMapping.properties
); // for es 2.x, 5.x, 6.x
} }
}); });
clusterPerIndexTypes[index] = normalizedIndexMappings; clusterPerIndexTypes[index] = normalizedIndexMappings;
@ -259,13 +268,13 @@ export function loadMappings(mappings, clusterID) {
} }
export function loadAliases(aliases, clusterID) { export function loadAliases(aliases, clusterID) {
aliases = getRawBody(aliases) aliases = getRawBody(aliases);
let clusterPerAliasIndexes = {}; let clusterPerAliasIndexes = {};
$.each(aliases || {}, function (index, omdexAliases) { $.each(aliases || {}, function(index, omdexAliases) {
// verify we have an index defined. useful when mapping loading is disabled // verify we have an index defined. useful when mapping loading is disabled
// clusterPerAliasIndexes[index] = clusterPerAliasIndexes[index] || {}; // clusterPerAliasIndexes[index] = clusterPerAliasIndexes[index] || {};
$.each(omdexAliases.aliases || {}, function (alias) { $.each(omdexAliases.aliases || {}, function(alias) {
if (alias === index) { if (alias === index) {
return; return;
} // alias which is identical to index means no index. } // alias which is identical to index means no index.
@ -290,18 +299,21 @@ export function clear() {
function retrieveSettings(settingsKey, settingsToRetrieve, clusterID) { function retrieveSettings(settingsKey, settingsToRetrieve, clusterID) {
const settingKeyToPathMap = { const settingKeyToPathMap = {
fields: '_mapping', fields: "_mapping",
indices: '_aliases', indices: "_aliases",
templates: '_template', templates: "_template",
commands: 'commands/_search', commands: "commands/_search",
}; };
// Fetch autocomplete info if setting is set to true, and if user has made changes. // Fetch autocomplete info if setting is set to true, and if user has made changes.
if (settingsToRetrieve[settingsKey] === true) { if (settingsToRetrieve[settingsKey] === true) {
if(settingsKey === 'commands'){ if (settingsKey === "commands") {
return es.queryCommonCommands(); return es.queryCommonCommands();
} }
return es.send('GET', settingKeyToPathMap[settingsKey], null, {clusterID, asSystemRequest: true}); return es.send("GET", settingKeyToPathMap[settingsKey], null, {
clusterID,
asSystemRequest: true,
});
} else { } else {
const settingsPromise = new $.Deferred(); const settingsPromise = new $.Deferred();
if (settingsToRetrieve[settingsKey] === false) { if (settingsToRetrieve[settingsKey] === false) {
@ -331,8 +343,8 @@ export function clearSubscriptions() {
} }
} }
function getObject(value){ function getObject(value) {
return typeof(value) === 'string' ? JSON.parse(value): value; return typeof value === "string" ? JSON.parse(value) : value;
} }
/** /**
@ -340,17 +352,41 @@ function getObject(value){
* @param settings Settings A way to retrieve the current settings * @param settings Settings A way to retrieve the current settings
* @param settingsToRetrieve any * @param settingsToRetrieve any
*/ */
export function retrieveAutoCompleteInfo(settings, settingsToRetrieve, clusterID) { export function retrieveAutoCompleteInfo(
settings,
settingsToRetrieve,
clusterID
) {
clearSubscriptions(); clearSubscriptions();
const mappingPromise = retrieveSettings('fields', settingsToRetrieve, clusterID); const mappingPromise = retrieveSettings(
const aliasesPromise = retrieveSettings('indices', settingsToRetrieve, clusterID); "fields",
const templatesPromise = retrieveSettings('templates', settingsToRetrieve, clusterID); settingsToRetrieve,
const commandsPromise = retrieveSettings('commands', settingsToRetrieve, clusterID); clusterID
);
const aliasesPromise = retrieveSettings(
"indices",
settingsToRetrieve,
clusterID
);
const templatesPromise = retrieveSettings(
"templates",
settingsToRetrieve,
clusterID
);
const commandsPromise = retrieveSettings(
"commands",
settingsToRetrieve,
clusterID
);
$.when(
$.when(mappingPromise, aliasesPromise, templatesPromise, commandsPromise).done((mappings, aliases, templates, commands) => { mappingPromise,
if(commands){ aliasesPromise,
templatesPromise,
commandsPromise
).done((mappings, aliases, templates, commands) => {
if (commands) {
loadCommands(commands); loadCommands(commands);
} }
let mappingsResponse; let mappingsResponse;
@ -358,9 +394,11 @@ export function retrieveAutoCompleteInfo(settings, settingsToRetrieve, clusterID
const maxMappingSize = mappings[0].length > 10 * 1024 * 1024; const maxMappingSize = mappings[0].length > 10 * 1024 * 1024;
if (maxMappingSize) { if (maxMappingSize) {
console.warn( console.warn(
`Mapping size is larger than 10MB (${mappings[0].length / 1024 / 1024} MB). Ignoring...` `Mapping size is larger than 10MB (${mappings[0].length /
1024 /
1024} MB). Ignoring...`
); );
mappingsResponse = '[{}]'; mappingsResponse = "[{}]";
} else { } else {
mappingsResponse = mappings[0]; mappingsResponse = mappings[0];
} }
@ -377,7 +415,7 @@ export function retrieveAutoCompleteInfo(settings, settingsToRetrieve, clusterID
if (mappings && aliases) { if (mappings && aliases) {
// Trigger an update event with the mappings, aliases // Trigger an update event with the mappings, aliases
$(mappingObj).trigger('update', [mappingsResponse, aliases[0]]); $(mappingObj).trigger("update", [mappingsResponse, aliases[0]]);
} }
// Schedule next request. // Schedule next request.
@ -391,13 +429,13 @@ export function retrieveAutoCompleteInfo(settings, settingsToRetrieve, clusterID
}); });
} }
async function loadCommands(commandsPromise){ async function loadCommands(commandsPromise) {
const commandRes = await commandsPromise.json(); const commandRes = await commandsPromise.json();
const hits = commandRes.hits.hits; const hits = commandRes.hits.hits;
if(hits && hits.length > 0){ if (hits && hits.length > 0) {
hits.forEach((hit)=>{ hits.forEach((hit) => {
commands.push(hit); commands.push(hit);
}) });
} }
} }
@ -405,10 +443,10 @@ export function pushCommand(cmd) {
commands.push(cmd); commands.push(cmd);
} }
export function getCommands({editor}) { export function getCommands({ editor }) {
const ret = []; const ret = [];
commands.forEach(command=>{ commands.forEach((command) => {
ret.push(command._source['title']); ret.push(command._source["title"]);
}); });
return ret; return ret;
// const curPosition = editor.getCurrentPosition(); // const curPosition = editor.getCurrentPosition();
@ -427,12 +465,17 @@ export function getCommands({editor}) {
} }
export function getCommand(title) { export function getCommand(title) {
const command = commands.filter(c=>{ const command = commands.filter((c) => {
return c._source['title'] == title; return c._source["title"] == title;
}) });
return command && command[0]; return command && command[0];
} }
export function deleteCommand(id) {
commands = commands.filter((c) => {
return c._id != id;
});
}
export function setClusterID(id) { export function setClusterID(id) {
clusterID = id; clusterID = id;
} }

View File

@ -8,7 +8,7 @@ export default function useAsync(callback, dependencies = []) {
const callbackMemoized = React.useCallback(() => { const callbackMemoized = React.useCallback(() => {
setLoading(true); setLoading(true);
setError(undefined); setError(undefined);
setValue(undefined); // setValue(undefined);
callback() callback()
.then(setValue) .then(setValue)
.catch(setError) .catch(setError)

View File

@ -1,411 +1,421 @@
import alert from './en-US/alert'; import alert from "./en-US/alert";
import console from './en-US/console'; import console from "./en-US/console";
import cluster from "./en-US/cluster";
export default { export default {
'navBar.lang': 'Languages', "navBar.lang": "Languages",
'layout.user.appname':"INFINI SEARCH CENTER", "layout.user.appname": "INFINI SEARCH CENTER",
'layout.user.appslogon':"INFINI search center is the best search platform in the world", "layout.user.appslogon":
'app.setting.appname':"Search Center", "INFINI search center is the best search platform in the world",
"app.setting.appname": "Search Center",
"layout.user.link.help": "Help",
'layout.user.link.help': 'Help', "layout.user.link.privacy": "Privacy",
'layout.user.link.privacy': 'Privacy', "layout.user.link.terms": "Terms",
'layout.user.link.terms': 'Terms', "validation.email.required": "Please enter your email!",
'validation.email.required': 'Please enter your email!', "validation.email.wrong-format": "The email address is in the wrong format!",
'validation.email.wrong-format': 'The email address is in the wrong format!', "validation.password.required": "Please enter your password!",
'validation.password.required': 'Please enter your password!', "validation.password.twice": "The passwords entered twice do not match!",
'validation.password.twice': 'The passwords entered twice do not match!', "validation.password.strength.msg":
'validation.password.strength.msg':
"Please enter at least 6 characters and don't use passwords that are easy to guess.", "Please enter at least 6 characters and don't use passwords that are easy to guess.",
'validation.password.strength.strong': 'Strength: strong', "validation.password.strength.strong": "Strength: strong",
'validation.password.strength.medium': 'Strength: medium', "validation.password.strength.medium": "Strength: medium",
'validation.password.strength.short': 'Strength: too short', "validation.password.strength.short": "Strength: too short",
'validation.confirm-password.required': 'Please confirm your password!', "validation.confirm-password.required": "Please confirm your password!",
'validation.phone-number.required': 'Please enter your phone number!', "validation.phone-number.required": "Please enter your phone number!",
'validation.phone-number.wrong-format': 'Malformed phone number!', "validation.phone-number.wrong-format": "Malformed phone number!",
'validation.verification-code.required': 'Please enter the verification code!', "validation.verification-code.required":
'validation.title.required': 'Please enter a title', "Please enter the verification code!",
'validation.date.required': 'Please select the start and end date', "validation.title.required": "Please enter a title",
'validation.goal.required': 'Please enter a description of the goal', "validation.date.required": "Please select the start and end date",
'validation.standard.required': 'Please enter a metric', "validation.goal.required": "Please enter a description of the goal",
'form.optional': ' (optional) ', "validation.standard.required": "Please enter a metric",
'form.submit': 'Submit', "form.optional": " (optional) ",
'form.save': 'Save', "form.submit": "Submit",
'form.email.placeholder': 'Email', "form.save": "Save",
'form.password.placeholder': 'Password', "form.email.placeholder": "Email",
'form.confirm-password.placeholder': 'Confirm password', "form.password.placeholder": "Password",
'form.phone-number.placeholder': 'Phone number', "form.confirm-password.placeholder": "Confirm password",
'form.verification-code.placeholder': 'Verification code', "form.phone-number.placeholder": "Phone number",
'form.title.label': 'Title', "form.verification-code.placeholder": "Verification code",
'form.title.placeholder': 'Give the target a name', "form.title.label": "Title",
'form.date.label': 'Start and end date', "form.title.placeholder": "Give the target a name",
'form.date.placeholder.start': 'Start date', "form.date.label": "Start and end date",
'form.date.placeholder.end': 'End date', "form.date.placeholder.start": "Start date",
'form.goal.label': 'Goal description', "form.date.placeholder.end": "End date",
'form.goal.placeholder': 'Please enter your work goals', "form.goal.label": "Goal description",
'form.standard.label': 'Metrics', "form.goal.placeholder": "Please enter your work goals",
'form.standard.placeholder': 'Please enter a metric', "form.standard.label": "Metrics",
'form.client.label': 'Client', "form.standard.placeholder": "Please enter a metric",
'form.client.label.tooltip': 'Target service object', "form.client.label": "Client",
'form.client.placeholder': "form.client.label.tooltip": "Target service object",
'Please describe your customer service, internal customers directly @ Name / job number', "form.client.placeholder":
'form.invites.label': 'Inviting critics', "Please describe your customer service, internal customers directly @ Name / job number",
'form.invites.placeholder': 'Please direct @ Name / job number, you can invite up to 5 people', "form.invites.label": "Inviting critics",
'form.weight.label': 'Weight', "form.invites.placeholder":
'form.weight.placeholder': 'Please enter weight', "Please direct @ Name / job number, you can invite up to 5 people",
'form.public.label': 'Target disclosure', "form.weight.label": "Weight",
'form.public.label.help': 'Customers and invitees are shared by default', "form.weight.placeholder": "Please enter weight",
'form.public.radio.public': 'Public', "form.public.label": "Target disclosure",
'form.public.radio.partially-public': 'Partially public', "form.public.label.help": "Customers and invitees are shared by default",
'form.public.radio.private': 'Private', "form.public.radio.public": "Public",
'form.publicUsers.placeholder': 'Open to', "form.public.radio.partially-public": "Partially public",
'form.publicUsers.option.A': 'Colleague A', "form.public.radio.private": "Private",
'form.publicUsers.option.B': 'Colleague B', "form.publicUsers.placeholder": "Open to",
'form.publicUsers.option.C': 'Colleague C', "form.publicUsers.option.A": "Colleague A",
'form.button.search': 'Search', "form.publicUsers.option.B": "Colleague B",
'form.button.new': 'New', "form.publicUsers.option.C": "Colleague C",
'form.button.create': 'Create', "form.button.search": "Search",
'form.button.add': 'Add', "form.button.new": "New",
'form.button.edit': 'Edit', "form.button.create": "Create",
'form.button.update': 'Update', "form.button.add": "Add",
'form.button.save': 'Save', "form.button.edit": "Edit",
'form.button.delete': 'Delete', "form.button.update": "Update",
'form.button.cancel': 'Cancel', "form.button.save": "Save",
'form.button.collapse': 'Collapse', "form.button.delete": "Delete",
'form.button.advanced': 'Advanced', "form.button.cancel": "Cancel",
'table.field.operation': 'Operation', "form.button.collapse": "Collapse",
"form.button.advanced": "Advanced",
"table.field.operation": "Operation",
"form.button.next": "Next",
"form.button.pre": "Previous",
'component.globalHeader.search': 'Search', "component.globalHeader.search": "Search",
'component.globalHeader.search.example1': 'Search example 1', "component.globalHeader.search.example1": "Search example 1",
'component.globalHeader.search.example2': 'Search example 2', "component.globalHeader.search.example2": "Search example 2",
'component.globalHeader.search.example3': 'Search example 3', "component.globalHeader.search.example3": "Search example 3",
'component.globalHeader.help': 'Help', "component.globalHeader.help": "Help",
'component.globalHeader.notification': 'Notification', "component.globalHeader.notification": "Notification",
'component.globalHeader.notification.empty': 'You have viewed all notifications.', "component.globalHeader.notification.empty":
'component.globalHeader.message': 'Message', "You have viewed all notifications.",
'component.globalHeader.message.empty': 'You have viewed all messsages.', "component.globalHeader.message": "Message",
'component.globalHeader.event': 'Event', "component.globalHeader.message.empty": "You have viewed all messsages.",
'component.globalHeader.event.empty': 'You have viewed all events.', "component.globalHeader.event": "Event",
'component.noticeIcon.clear': 'Clear', "component.globalHeader.event.empty": "You have viewed all events.",
'component.noticeIcon.cleared': 'Cleared', "component.noticeIcon.clear": "Clear",
'component.noticeIcon.empty': 'No notifications', "component.noticeIcon.cleared": "Cleared",
'menu.home': 'Home', "component.noticeIcon.empty": "No notifications",
'menu.devtool': 'CONSOLE', "menu.home": "Home",
'menu.alerting': 'AERTING', "menu.devtool": "CONSOLE",
'menu.alerting.overview': 'OVERVIEW', "menu.alerting": "AERTING",
'menu.alerting.monitor': 'MONITORS', "menu.alerting.overview": "OVERVIEW",
'menu.alerting.destination': 'DESTINATIONS', "menu.alerting.monitor": "MONITORS",
"menu.alerting.destination": "DESTINATIONS",
'menu.cluster': 'CLUSTER', "menu.cluster": "CLUSTER",
'menu.cluster.overview': 'OVERVIEW', "menu.cluster.overview": "OVERVIEW",
'menu.cluster.monitoring': 'METRICS', "menu.cluster.monitoring": "METRICS",
'menu.cluster.settings': 'SETTINGS', "menu.cluster.settings": "SETTINGS",
'menu.cluster.logging': 'LOGS', "menu.cluster.logging": "LOGS",
"menu.data": "DATA",
"menu.data.overview": "OVERVIEW",
"menu.data.index": "INDICES",
"menu.data.document": "DOCUMENTS",
"menu.data.template": "TEMPLATES",
"menu.data.lifecycle": "LIFECYCLES",
"menu.data.discover": "EXPLORE",
"menu.data.indexPatterns": "VIEWS",
'menu.data': 'DATA', "menu.search": "SEARCH",
'menu.data.overview': 'OVERVIEW', "menu.search.overview": "OVERVIEW",
'menu.data.index': 'INDICES', "menu.search.template": "TEMPLATES",
'menu.data.document': 'DOCUMENTS', "menu.search.alias": "ALIAS",
'menu.data.template': 'TEMPLATES', "menu.search.dict": "DICTIONARY",
'menu.data.lifecycle': 'LIFECYCLES', "menu.search.analyzer": "ANALYZER",
'menu.data.discover': 'EXPLORE', "menu.search.nlp": "NLP",
'menu.data.indexPatterns': 'VIEWS',
'menu.search': 'SEARCH', "menu.synchronize": "SYNCHRONIZE",
'menu.search.overview': 'OVERVIEW', "menu.synchronize.overview": "OVERVIEW",
'menu.search.template': 'TEMPLATES', "menu.synchronize.pipeline": "PIPELINES",
'menu.search.alias': 'ALIAS', "menu.synchronize.rebuild": "REBUILD",
'menu.search.dict': 'DICTIONARY', "menu.synchronize.inout": "CONNECT",
'menu.search.analyzer': 'ANALYZER',
'menu.search.nlp': 'NLP',
'menu.synchronize': 'SYNCHRONIZE', "menu.backup": "BACKUP",
'menu.synchronize.overview': 'OVERVIEW', "menu.backup.overview": "OVERVIEW",
'menu.synchronize.pipeline': 'PIPELINES', "menu.backup.index": "BACKUPS",
'menu.synchronize.rebuild': 'REBUILD', "menu.backup.lifecycle": "POLICIES",
'menu.synchronize.inout': 'CONNECT',
'menu.backup': 'BACKUP', "menu.system": "SYSTEM",
'menu.backup.overview': 'OVERVIEW', "menu.system.cluster": "CLUSTERS",
'menu.backup.index': 'BACKUPS', "menu.system.registCluster": "REGIST CLUSTER",
'menu.backup.lifecycle': 'POLICIES', "menu.system.editCluster": "EDIT CLUSTER",
"menu.system.settings": "SETTINGS",
"menu.system.settings.global": "GLOBAL",
"menu.system.settings.gateway": "GATEWAY",
'menu.system': 'SYSTEM', "menu.system.security": "SECURITY",
'menu.system.cluster': 'CLUSTERS', "menu.system.security.general": "GENERAL",
'menu.system.registCluster': 'REGIST CLUSTER', "menu.system.security.sso": "SSO",
'menu.system.editCluster': 'EDIT CLUSTER', "menu.system.security.roles": "ROLES",
'menu.system.settings': 'SETTINGS', "menu.system.security.users": "USERS",
'menu.system.settings.global': 'GLOBAL', "menu.system.security.certs": "CERTS",
'menu.system.settings.gateway': 'GATEWAY',
'menu.system.security': 'SECURITY', "menu.system.logs": "LOGS",
'menu.system.security.general': 'GENERAL', "menu.system.logs.overview": "OVERVIEW",
'menu.system.security.sso': 'SSO', "menu.system.logs.audit": "AUDIT",
'menu.system.security.roles': 'ROLES', "menu.system.logs.query": "QUERY",
'menu.system.security.users': 'USERS', "menu.system.logs.slow": "SLOW",
'menu.system.security.certs': 'CERTS', "menu.system.commonCommand": "COMMON COMMAND",
"menu.form": "Form",
"menu.form.basicform": "Basic Form",
"menu.form.stepform": "Step Form",
"menu.form.stepform.info": "Step Form(write transfer information)",
"menu.form.stepform.confirm": "Step Form(confirm transfer information)",
"menu.form.stepform.result": "Step Form(finished)",
"menu.form.advancedform": "Advanced Form",
"menu.list": "List",
"menu.list.searchtable": "Search Table",
"menu.list.basiclist": "Basic List",
"menu.list.cardlist": "Card List",
"menu.list.searchlist": "Search List",
"menu.list.searchlist.articles": "Search List(articles)",
"menu.list.searchlist.projects": "Search List(projects)",
"menu.list.searchlist.applications": "Search List(applications)",
"menu.profile": "Profile",
"menu.profile.basic": "Basic Profile",
"menu.profile.advanced": "Advanced Profile",
"menu.result": "Result",
"menu.result.success": "Success",
"menu.result.fail": "Fail",
"menu.exception": "Exception",
"menu.exception.not-permission": "403",
"menu.exception.not-find": "404",
"menu.exception.server-error": "500",
"menu.exception.trigger": "Trigger",
"menu.account": "Account",
"menu.account.center": "Account Center",
"menu.account.settings": "Account Settings",
"menu.account.trigger": "Trigger Error",
"menu.account.logout": "Logout",
'menu.system.logs': 'LOGS', "dashboard.charts.title.cluster_throughput.axis.indexing":
'menu.system.logs.overview': 'OVERVIEW', "Indexing Throughput",
'menu.system.logs.audit': 'AUDIT', "dashboard.charts.title.cluster_throughput.axis.searching":
'menu.system.logs.query': 'QUERY', "Searching Throughput",
'menu.system.logs.slow': 'SLOW', "dashboard.charts.title.cluster_latency.axis.indexing": "Indexing Latency",
'menu.system.commonCommand': 'COMMON COMMAND', "dashboard.charts.title.cluster_latency.axis.searching": "Searching Latency",
"dashboard.charts.title.system_load.axis.load": "System Load",
"dashboard.charts.title.system_network.axis.traffic": "Network Throughput",
"dashboard.charts.title.system_disk.axis.throughput": "Disk Throughput",
"dashboard.charts.title.system_disk.axis.iops": "Disk IOPS",
"dashboard.charts.title.system_memory.axis.memory": "Memory Usage",
"dashboard.charts.title.system_memory.axis.gc": "GC Activity",
"dashboard.charts.title.cluster_storage.axis.indices_storage":
"Storage Usage",
"dashboard.charts.title.cluster_storage.axis.available_storage":
"Storage Available",
"dashboard.charts.title.cluster_documents.axis.documents": "Documents Count",
"dashboard.charts.title.cluster_documents.axis.counts": "Shards Count",
"app.login.message-invalid-credentials":
"Invalid username or passwordadmin/888888",
"app.login.message-invalid-verification-code": "Invalid verification code",
"app.login.tab-login-credentials": "Credentials",
"app.login.tab-login-mobile": "Mobile number",
"app.login.remember-me": "Remember me",
"app.login.forgot-password": "Forgot your password?",
"app.login.sign-in-with": "Sign in with",
"app.login.signup": "Sign up",
"app.login.login": "Login",
"app.register.register": "Register",
"app.register.get-verification-code": "Get code",
"app.register.sing-in": "Already have an account?",
"app.register-result.msg": "Accountregistered at {email}",
"app.register-result.activation-email":
"The activation email has been sent to your email address and is valid for 24 hours. Please log in to the email in time and click on the link in the email to activate the account.",
"app.register-result.back-home": "Back to home",
"app.register-result.view-mailbox": "View mailbox",
"app.home.introduce": "introduce",
"app.analysis.test": "Gongzhuan No.{no} shop",
"app.analysis.introduce": "Introduce",
"app.analysis.total-sales": "Total Sales",
"app.analysis.day-sales": "Day Sales",
"app.analysis.visits": "Visits",
"app.analysis.visits-trend": "Visits Trend",
"app.analysis.visits-ranking": "Visits Ranking",
"app.analysis.day-visits": "Day Visits",
"app.analysis.week": "Week Ratio",
"app.analysis.day": "Day Ratio",
"app.analysis.payments": "Payments",
"app.analysis.conversion-rate": "Conversion Rate",
"app.analysis.operational-effect": "Operational Effect",
"app.analysis.sales-trend": "Stores Sales Trend",
"app.analysis.sales-ranking": "Sales Ranking",
"app.analysis.all-year": "All Year",
"app.analysis.all-month": "All Month",
"app.analysis.all-week": "All Week",
"app.analysis.all-day": "All day",
"app.analysis.search-users": "Search Users",
"app.analysis.per-capita-search": "Per Capita Search",
"app.analysis.online-top-search": "Online Top Search",
"app.analysis.the-proportion-of-sales": "The Proportion Of Sales",
"app.analysis.channel.all": "ALL",
"app.analysis.channel.online": "Online",
"app.analysis.channel.stores": "Stores",
"app.analysis.sales": "Sales",
"app.analysis.traffic": "Traffic",
"app.analysis.table.rank": "Rank",
"app.analysis.table.search-keyword": "Keyword",
"app.analysis.table.users": "Users",
"app.analysis.table.weekly-range": "Weekly Range",
"app.forms.basic.title": "Basic form",
"app.forms.basic.description":
"Form pages are used to collect or verify information to users, and basic forms are common in scenarios where there are fewer data items.",
"app.monitor.trading-activity": "Real-Time Trading Activity",
"app.monitor.total-transactions": "Total transactions today",
"app.monitor.sales-target": "Sales target completion rate",
"app.monitor.remaining-time": "Remaining time of activity",
"app.monitor.total-transactions-per-second": "Total transactions per second",
"app.monitor.activity-forecast": "Activity forecast",
"app.monitor.efficiency": "Efficiency",
"app.monitor.ratio": "Ratio",
"app.monitor.proportion-per-category": "Proportion Per Category",
"app.monitor.fast-food": "Fast food",
"app.monitor.western-food": "Western food",
"app.monitor.hot-pot": "Hot pot",
"app.monitor.waiting-for-implementation": "Waiting for implementation",
"app.monitor.popular-searches": "Popular Searches",
"app.monitor.resource-surplus": "Resource Surplus",
"app.monitor.fund-surplus": "Fund Surplus",
'menu.form': 'Form', "app.settings.security.update": "Update Setting",
'menu.form.basicform': 'Basic Form', "app.settings.global.update": "Update Setting",
'menu.form.stepform': 'Step Form', "app.settings.global.site_name": "Site Name",
'menu.form.stepform.info': 'Step Form(write transfer information)', "app.settings.global.domain": "Site Domain",
'menu.form.stepform.confirm': 'Step Form(confirm transfer information)', "app.settings.global.listen_addr": "Listen Address",
'menu.form.stepform.result': 'Step Form(finished)', "app.settings.global.is_tls": "Enable TLS",
'menu.form.advancedform': 'Advanced Form', "app.settings.global.data_path": "Data Path",
'menu.list': 'List', "app.settings.global.log_path": "Log Path",
'menu.list.searchtable': 'Search Table',
'menu.list.basiclist': 'Basic List',
'menu.list.cardlist': 'Card List',
'menu.list.searchlist': 'Search List',
'menu.list.searchlist.articles': 'Search List(articles)',
'menu.list.searchlist.projects': 'Search List(projects)',
'menu.list.searchlist.applications': 'Search List(applications)',
'menu.profile': 'Profile',
'menu.profile.basic': 'Basic Profile',
'menu.profile.advanced': 'Advanced Profile',
'menu.result': 'Result',
'menu.result.success': 'Success',
'menu.result.fail': 'Fail',
'menu.exception': 'Exception',
'menu.exception.not-permission': '403',
'menu.exception.not-find': '404',
'menu.exception.server-error': '500',
'menu.exception.trigger': 'Trigger',
'menu.account': 'Account',
'menu.account.center': 'Account Center',
'menu.account.settings': 'Account Settings',
'menu.account.trigger': 'Trigger Error',
'menu.account.logout': 'Logout',
"app.settings.security.auth2factor_enabled":
"Enable 2FA(two-factor) Authentication",
"app.settings.security.audit_enabled": "Enable Audit Logging",
'dashboard.charts.title.cluster_throughput.axis.indexing':"Indexing Throughput", "app.settings.menuMap.basic": "Basic Settings",
'dashboard.charts.title.cluster_throughput.axis.searching':"Searching Throughput", "app.settings.menuMap.security": "Security Settings",
'dashboard.charts.title.cluster_latency.axis.indexing':"Indexing Latency", "app.settings.menuMap.binding": "Account Binding",
'dashboard.charts.title.cluster_latency.axis.searching':"Searching Latency", "app.settings.menuMap.notification": "New Message Notification",
'dashboard.charts.title.system_load.axis.load':"System Load", "app.settings.basic.avatar": "Avatar",
'dashboard.charts.title.system_network.axis.traffic':"Network Throughput", "app.settings.basic.change-avatar": "Change avatar",
'dashboard.charts.title.system_disk.axis.throughput':"Disk Throughput", "app.settings.basic.email": "Email",
'dashboard.charts.title.system_disk.axis.iops':"Disk IOPS", "app.settings.basic.email-message": "Please input your email!",
'dashboard.charts.title.system_memory.axis.memory':"Memory Usage", "app.settings.basic.nickname": "Nickname",
'dashboard.charts.title.system_memory.axis.gc':"GC Activity", "app.settings.basic.nickname-message": "Please input your Nickname!",
'dashboard.charts.title.cluster_storage.axis.indices_storage':"Storage Usage", "app.settings.basic.profile": "Personal profile",
'dashboard.charts.title.cluster_storage.axis.available_storage':"Storage Available", "app.settings.basic.profile-message": "Please input your personal profile!",
'dashboard.charts.title.cluster_documents.axis.documents':"Documents Count", "app.settings.basic.profile-placeholder": "Brief introduction to yourself",
'dashboard.charts.title.cluster_documents.axis.counts':"Shards Count", "app.settings.basic.country": "Country/Region",
"app.settings.basic.country-message": "Please input your country!",
"app.settings.basic.geographic": "Province or city",
'app.login.message-invalid-credentials': 'Invalid username or passwordadmin/888888', "app.settings.basic.geographic-message": "Please input your geographic info!",
'app.login.message-invalid-verification-code': 'Invalid verification code', "app.settings.basic.address": "Street Address",
'app.login.tab-login-credentials': 'Credentials', "app.settings.basic.address-message": "Please input your address!",
'app.login.tab-login-mobile': 'Mobile number', "app.settings.basic.phone": "Phone Number",
'app.login.remember-me': 'Remember me', "app.settings.basic.phone-message": "Please input your phone!",
'app.login.forgot-password': 'Forgot your password?', "app.settings.basic.update": "Update Information",
'app.login.sign-in-with': 'Sign in with', "app.settings.security.strong": "Strong",
'app.login.signup': 'Sign up', "app.settings.security.medium": "Medium",
'app.login.login': 'Login', "app.settings.security.weak": "Weak",
'app.register.register': 'Register', "app.settings.security.password": "Account Password",
'app.register.get-verification-code': 'Get code', "app.settings.security.password-description": "Current password strength",
'app.register.sing-in': 'Already have an account?', "app.settings.security.phone": "Security Phone",
'app.register-result.msg': 'Accountregistered at {email}', "app.settings.security.phone-description": "Bound phone",
'app.register-result.activation-email': "app.settings.security.question": "Security Question",
'The activation email has been sent to your email address and is valid for 24 hours. Please log in to the email in time and click on the link in the email to activate the account.', "app.settings.security.question-description":
'app.register-result.back-home': 'Back to home', "The security question is not set, and the security policy can effectively protect the account security",
'app.register-result.view-mailbox': 'View mailbox', "app.settings.security.email": "Backup Email",
'app.home.introduce': 'introduce', "app.settings.security.email-description": "Bound Email",
'app.analysis.test': 'Gongzhuan No.{no} shop', "app.settings.security.mfa": "MFA Device",
'app.analysis.introduce': 'Introduce', "app.settings.security.mfa-description":
'app.analysis.total-sales': 'Total Sales', "Unbound MFA device, after binding, can be confirmed twice",
'app.analysis.day-sales': 'Day Sales', "app.settings.security.modify": "Modify",
'app.analysis.visits': 'Visits', "app.settings.security.set": "Set",
'app.analysis.visits-trend': 'Visits Trend', "app.settings.security.bind": "Bind",
'app.analysis.visits-ranking': 'Visits Ranking', "app.settings.binding.taobao": "Binding Taobao",
'app.analysis.day-visits': 'Day Visits', "app.settings.binding.taobao-description": "Currently unbound Taobao account",
'app.analysis.week': 'Week Ratio', "app.settings.binding.alipay": "Binding Alipay",
'app.analysis.day': 'Day Ratio', "app.settings.binding.alipay-description": "Currently unbound Alipay account",
'app.analysis.payments': 'Payments', "app.settings.binding.dingding": "Binding DingTalk",
'app.analysis.conversion-rate': 'Conversion Rate', "app.settings.binding.dingding-description":
'app.analysis.operational-effect': 'Operational Effect', "Currently unbound DingTalk account",
'app.analysis.sales-trend': 'Stores Sales Trend', "app.settings.binding.bind": "Bind",
'app.analysis.sales-ranking': 'Sales Ranking', "app.settings.notification.password": "Account Password",
'app.analysis.all-year': 'All Year', "app.settings.notification.password-description":
'app.analysis.all-month': 'All Month', "Messages from other users will be notified in the form of a station letter",
'app.analysis.all-week': 'All Week', "app.settings.notification.messages": "System Messages",
'app.analysis.all-day': 'All day', "app.settings.notification.messages-description":
'app.analysis.search-users': 'Search Users', "System messages will be notified in the form of a station letter",
'app.analysis.per-capita-search': 'Per Capita Search', "app.settings.notification.todo": "To-do Notification",
'app.analysis.online-top-search': 'Online Top Search', "app.settings.notification.todo-description":
'app.analysis.the-proportion-of-sales': 'The Proportion Of Sales', "The to-do list will be notified in the form of a letter from the station",
'app.analysis.channel.all': 'ALL', "app.settings.open": "Open",
'app.analysis.channel.online': 'Online', "app.settings.close": "Close",
'app.analysis.channel.stores': 'Stores', "app.exception.back": "Back to home",
'app.analysis.sales': 'Sales', "app.exception.description.403": "Sorry, you don't have access to this page",
'app.analysis.traffic': 'Traffic', "app.exception.description.404": "Sorry, the page you visited does not exist",
'app.analysis.table.rank': 'Rank', "app.exception.description.500": "Sorry, the server is reporting an error",
'app.analysis.table.search-keyword': 'Keyword', "app.result.error.title": "Submission Failed",
'app.analysis.table.users': 'Users', "app.result.error.description":
'app.analysis.table.weekly-range': 'Weekly Range', "Please check and modify the following information before resubmitting.",
'app.forms.basic.title': 'Basic form', "app.result.error.hint-title":
'app.forms.basic.description': "The content you submitted has the following error:",
'Form pages are used to collect or verify information to users, and basic forms are common in scenarios where there are fewer data items.', "app.result.error.hint-text1": "Your account has been frozen",
'app.monitor.trading-activity': 'Real-Time Trading Activity', "app.result.error.hint-btn1": "Thaw immediately",
'app.monitor.total-transactions': 'Total transactions today', "app.result.error.hint-text2": "Your account is not yet eligible to apply",
'app.monitor.sales-target': 'Sales target completion rate', "app.result.error.hint-btn2": "Upgrade immediately",
'app.monitor.remaining-time': 'Remaining time of activity', "app.result.error.btn-text": "Return to modify",
'app.monitor.total-transactions-per-second': 'Total transactions per second', "app.result.success.title": "Submission Success",
'app.monitor.activity-forecast': 'Activity forecast', "app.result.success.description":
'app.monitor.efficiency': 'Efficiency', "The submission results page is used to feed back the results of a series of operational tasks. If it is a simple operation, use the Message global prompt feedback. This text area can show a simple supplementary explanation. If there is a similar requirement for displaying “documents”, the following gray area can present more complicated content.",
'app.monitor.ratio': 'Ratio', "app.result.success.operate-title": "Project Name",
'app.monitor.proportion-per-category': 'Proportion Per Category', "app.result.success.operate-id": "Project ID",
'app.monitor.fast-food': 'Fast food', "app.result.success.principal": "Principal",
'app.monitor.western-food': 'Western food', "app.result.success.operate-time": "Effective time",
'app.monitor.hot-pot': 'Hot pot', "app.result.success.step1-title": "Create project",
'app.monitor.waiting-for-implementation': 'Waiting for implementation', "app.result.success.step1-operator": "Qu Lili",
'app.monitor.popular-searches': 'Popular Searches', "app.result.success.step2-title": "Departmental preliminary review",
'app.monitor.resource-surplus': 'Resource Surplus', "app.result.success.step2-operator": "Zhou Maomao",
'app.monitor.fund-surplus': 'Fund Surplus', "app.result.success.step2-extra": "Urge",
"app.result.success.step3-title": "Financial review",
'app.settings.security.update':"Update Setting", "app.result.success.step4-title": "Finish",
'app.settings.global.update':"Update Setting", "app.result.success.btn-return": "Back to list",
'app.settings.global.site_name':"Site Name", "app.result.success.btn-project": "View project",
'app.settings.global.domain':"Site Domain", "app.result.success.btn-print": "Print",
'app.settings.global.listen_addr':"Listen Address", "app.setting.pagestyle": "Page style setting",
'app.settings.global.is_tls':"Enable TLS", "app.setting.pagestyle.dark": "Dark style",
'app.settings.global.data_path':"Data Path", "app.setting.pagestyle.light": "Light style",
'app.settings.global.log_path':"Log Path", "app.setting.content-width": "Content Width",
"app.setting.content-width.fixed": "Fixed",
'app.settings.security.auth2factor_enabled':"Enable 2FA(two-factor) Authentication", "app.setting.content-width.fluid": "Fluid",
'app.settings.security.audit_enabled':"Enable Audit Logging", "app.setting.themecolor": "Theme Color",
"app.setting.themecolor.dust": "Dust Red",
"app.setting.themecolor.volcano": "Volcano",
'app.settings.menuMap.basic': 'Basic Settings', "app.setting.themecolor.sunset": "Sunset Orange",
'app.settings.menuMap.security': 'Security Settings', "app.setting.themecolor.cyan": "Cyan",
'app.settings.menuMap.binding': 'Account Binding', "app.setting.themecolor.green": "Polar Green",
'app.settings.menuMap.notification': 'New Message Notification', "app.setting.themecolor.daybreak": "Daybreak Blue (default)",
'app.settings.basic.avatar': 'Avatar', "app.setting.themecolor.geekblue": "Geek Glue",
'app.settings.basic.change-avatar': 'Change avatar', "app.setting.themecolor.purple": "Golden Purple",
'app.settings.basic.email': 'Email', "app.setting.navigationmode": "Navigation Mode",
'app.settings.basic.email-message': 'Please input your email!', "app.setting.sidemenu": "Side Menu Layout",
'app.settings.basic.nickname': 'Nickname', "app.setting.topmenu": "Top Menu Layout",
'app.settings.basic.nickname-message': 'Please input your Nickname!', "app.setting.fixedheader": "Fixed Header",
'app.settings.basic.profile': 'Personal profile', "app.setting.fixedsidebar": "Fixed Sidebar",
'app.settings.basic.profile-message': 'Please input your personal profile!', "app.setting.fixedsidebar.hint": "Works on Side Menu Layout",
'app.settings.basic.profile-placeholder': 'Brief introduction to yourself', "app.setting.hideheader": "Hidden Header when scrolling",
'app.settings.basic.country': 'Country/Region', "app.setting.hideheader.hint": "Works when Hidden Header is enabled",
'app.settings.basic.country-message': 'Please input your country!', "app.setting.othersettings": "Other Settings",
'app.settings.basic.geographic': 'Province or city', "app.setting.weakmode": "Weak Mode",
'app.settings.basic.geographic-message': 'Please input your geographic info!', "app.setting.copy": "Copy Setting",
'app.settings.basic.address': 'Street Address', "app.setting.copyinfo":
'app.settings.basic.address-message': 'Please input your address!', "copy successplease replace defaultSettings in src/models/setting.js",
'app.settings.basic.phone': 'Phone Number', "app.setting.production.hint":
'app.settings.basic.phone-message': 'Please input your phone!', "Setting panel shows in development environment only, please manually modify",
'app.settings.basic.update': 'Update Information',
'app.settings.security.strong': 'Strong',
'app.settings.security.medium': 'Medium',
'app.settings.security.weak': 'Weak',
'app.settings.security.password': 'Account Password',
'app.settings.security.password-description': 'Current password strength',
'app.settings.security.phone': 'Security Phone',
'app.settings.security.phone-description': 'Bound phone',
'app.settings.security.question': 'Security Question',
'app.settings.security.question-description':
'The security question is not set, and the security policy can effectively protect the account security',
'app.settings.security.email': 'Backup Email',
'app.settings.security.email-description': 'Bound Email',
'app.settings.security.mfa': 'MFA Device',
'app.settings.security.mfa-description':
'Unbound MFA device, after binding, can be confirmed twice',
'app.settings.security.modify': 'Modify',
'app.settings.security.set': 'Set',
'app.settings.security.bind': 'Bind',
'app.settings.binding.taobao': 'Binding Taobao',
'app.settings.binding.taobao-description': 'Currently unbound Taobao account',
'app.settings.binding.alipay': 'Binding Alipay',
'app.settings.binding.alipay-description': 'Currently unbound Alipay account',
'app.settings.binding.dingding': 'Binding DingTalk',
'app.settings.binding.dingding-description': 'Currently unbound DingTalk account',
'app.settings.binding.bind': 'Bind',
'app.settings.notification.password': 'Account Password',
'app.settings.notification.password-description':
'Messages from other users will be notified in the form of a station letter',
'app.settings.notification.messages': 'System Messages',
'app.settings.notification.messages-description':
'System messages will be notified in the form of a station letter',
'app.settings.notification.todo': 'To-do Notification',
'app.settings.notification.todo-description':
'The to-do list will be notified in the form of a letter from the station',
'app.settings.open': 'Open',
'app.settings.close': 'Close',
'app.exception.back': 'Back to home',
'app.exception.description.403': "Sorry, you don't have access to this page",
'app.exception.description.404': 'Sorry, the page you visited does not exist',
'app.exception.description.500': 'Sorry, the server is reporting an error',
'app.result.error.title': 'Submission Failed',
'app.result.error.description':
'Please check and modify the following information before resubmitting.',
'app.result.error.hint-title': 'The content you submitted has the following error:',
'app.result.error.hint-text1': 'Your account has been frozen',
'app.result.error.hint-btn1': 'Thaw immediately',
'app.result.error.hint-text2': 'Your account is not yet eligible to apply',
'app.result.error.hint-btn2': 'Upgrade immediately',
'app.result.error.btn-text': 'Return to modify',
'app.result.success.title': 'Submission Success',
'app.result.success.description':
'The submission results page is used to feed back the results of a series of operational tasks. If it is a simple operation, use the Message global prompt feedback. This text area can show a simple supplementary explanation. If there is a similar requirement for displaying “documents”, the following gray area can present more complicated content.',
'app.result.success.operate-title': 'Project Name',
'app.result.success.operate-id': 'Project ID',
'app.result.success.principal': 'Principal',
'app.result.success.operate-time': 'Effective time',
'app.result.success.step1-title': 'Create project',
'app.result.success.step1-operator': 'Qu Lili',
'app.result.success.step2-title': 'Departmental preliminary review',
'app.result.success.step2-operator': 'Zhou Maomao',
'app.result.success.step2-extra': 'Urge',
'app.result.success.step3-title': 'Financial review',
'app.result.success.step4-title': 'Finish',
'app.result.success.btn-return': 'Back to list',
'app.result.success.btn-project': 'View project',
'app.result.success.btn-print': 'Print',
'app.setting.pagestyle': 'Page style setting',
'app.setting.pagestyle.dark': 'Dark style',
'app.setting.pagestyle.light': 'Light style',
'app.setting.content-width': 'Content Width',
'app.setting.content-width.fixed': 'Fixed',
'app.setting.content-width.fluid': 'Fluid',
'app.setting.themecolor': 'Theme Color',
'app.setting.themecolor.dust': 'Dust Red',
'app.setting.themecolor.volcano': 'Volcano',
'app.setting.themecolor.sunset': 'Sunset Orange',
'app.setting.themecolor.cyan': 'Cyan',
'app.setting.themecolor.green': 'Polar Green',
'app.setting.themecolor.daybreak': 'Daybreak Blue (default)',
'app.setting.themecolor.geekblue': 'Geek Glue',
'app.setting.themecolor.purple': 'Golden Purple',
'app.setting.navigationmode': 'Navigation Mode',
'app.setting.sidemenu': 'Side Menu Layout',
'app.setting.topmenu': 'Top Menu Layout',
'app.setting.fixedheader': 'Fixed Header',
'app.setting.fixedsidebar': 'Fixed Sidebar',
'app.setting.fixedsidebar.hint': 'Works on Side Menu Layout',
'app.setting.hideheader': 'Hidden Header when scrolling',
'app.setting.hideheader.hint': 'Works when Hidden Header is enabled',
'app.setting.othersettings': 'Other Settings',
'app.setting.weakmode': 'Weak Mode',
'app.setting.copy': 'Copy Setting',
'app.setting.copyinfo': 'copy successplease replace defaultSettings in src/models/setting.js',
'app.setting.production.hint':
'Setting panel shows in development environment only, please manually modify',
...alert, ...alert,
...console, ...console,
...cluster,
}; };

View File

@ -0,0 +1,108 @@
export default {
"cluster.manage.title": "CLUSTERS",
"cluster.manage.description":
"集群管理可以帮助您快速接入不同版本的 Elasticsearch 集群,以及删除和修改集群配置。",
"cluster.manage.label.cluster_name": "Cluster Name",
"cluster.manage.btn.regist": "Regist Cluster",
"cluster.manage.table.column.name": "Name",
"cluster.manage.table.column.health": "Health",
"cluster.manage.table.column.version": "Version",
"cluster.manage.table.column.node_count": "Node Count",
"cluster.manage.table.column.endpoint": "Endpoint",
"cluster.manage.table.column.monitored": "Monitored",
"cluster.manage.table.column.operation": "Operation",
"cluster.manage.table.column.description": "Description",
"cluster.manage.monitored.on": "ON",
"cluster.manage.monitored.off": "OFF",
"cluster.regist.title": "REGIST CLUSTER",
"cluster.regist.description": "输入集群地址和身份验证信息分步创建集群。",
"cluster.regist.step.connect.title": "Connect",
"cluster.regist.step.confirm.title": "Confirm",
"cluster.regist.step.complete.title": "Complete",
"cluster.regist.step.connect.label.auth": "Auth",
"cluster.regist.step.connect.label.username": "Username",
"cluster.regist.step.connect.label.password": "Password",
"cluster.regist.step.connect.label.data_nodes": "Data Nodes",
"cluster.regist.step.connect.label.shards": "Active Shards",
"cluster.regist.step.complete.success": "Succeed",
"cluster.regist.step.complete.btn.create": "Regist Again",
"cluster.regist.step.complete.btn.goto": "Go To Cluster List",
"cluster.regist.step.complete.tls.yes": "Yes",
"cluster.regist.step.complete.tls.no": "No",
"cluster.monitor.cluster.title": "Cluster",
"cluster.monitor.node.title": "Node",
"cluster.monitor.index.title": "Index",
"cluster.monitor.summary.name": "Cluster Name",
"cluster.monitor.summary.online_time": "Uptime",
"cluster.monitor.summary.version": "Version",
"cluster.monitor.summary.health": "Health",
"cluster.monitor.summary.node_count": "Node Count",
"cluster.monitor.summary.total_index": "Total Index",
"cluster.monitor.summary.shard": "Pri/Total Shard",
"cluster.monitor.summary.unassign_shard": "Unassigned Shard",
"cluster.monitor.summary.total_docs": "Total Docs",
"cluster.monitor.summary.storage": "Storage",
"cluster.monitor.summary.jvm": "JVM Memory",
"cluster.monitor.timepicker.last15minutes": "Last 15 minutes",
"cluster.monitor.timepicker.thisweek": "This week",
"cluster.monitor.timepicker.last30minutes": "Last 30 minutes",
"cluster.monitor.timepicker.lasthour": "Last hour",
"cluster.monitor.timepicker.lastday": "Last day",
"cluster.monitor.timepicker.lastweek": "Last week",
"cluster.monitor.timepicker.lastmonth": "Last month",
"cluster.monitor.timepicker.last3month": "Last 3 month",
"cluster.monitor.timepicker.lastyear": "Last year",
"cluster.monitor.timepicker.today": "Today",
"cluster.metrics.node.axis.cpu.title": "CPU Usage",
"cluster.metrics.node.axis.disk.title": "Disk Available",
"cluster.metrics.node.axis.indexing_rate.title": "Indexing Rate",
"cluster.metrics.node.axis.query_rate.title": "Query Rate",
"cluster.metrics.node.axis.fetch_rate.title": "Fetch Rate",
"cluster.metrics.node.axis.flush_latency.title": "Flush Latency",
"cluster.metrics.node.axis.indexing_latency.title": "Indexing Latency",
"cluster.metrics.node.axis.query_latency.title": "Query Latency",
"cluster.metrics.node.axis.fetch_latency.title": "Fetch Latency",
"cluster.metrics.node.axis.merge_latency.title": "Merge Latency",
"cluster.metrics.node.axis.refresh_latency.title": "Refresh Latency",
"cluster.metrics.node.axis.flush_latency.title": "Flush Latency",
"cluster.metrics.node.axis.query_cache.title": "Query Cache",
"cluster.metrics.node.axis.request_cache.title": "Request Cache",
"cluster.metrics.node.axis.http_connect_num.title": "Http Connections",
"cluster.metrics.node.axis.http_rate.title": "Rate Of Opened Connections",
"cluster.metrics.node.axis.segment_memory.title": "Segment Memory",
"cluster.metrics.node.axis.segment_count.title": "Segment Count",
"cluster.metrics.node.axis.docs_count.title": "Document Count",
"cluster.metrics.node.axis.index_storage.title": "Indices Storage",
"cluster.metrics.node.axis.jvm_heap_used_percent.title": "JVM Heap Usage",
"cluster.metrics.index.axis.index_storage.title": "Index Storage",
"cluster.metrics.index.axis.doc_count.title": "Document count",
"cluster.metrics.index.axis.query_times.title": "Query Requests",
"cluster.metrics.index.axis.fetch_times.title": "Fetch Requests",
"cluster.metrics.index.axis.merge_times.title": "Merge Requests",
"cluster.metrics.index.axis.refresh_times.title": "Refresh Requests",
"cluster.metrics.index.axis.indexing_rate.title": "Indexing Rate",
"cluster.metrics.index.axis.indexing_latency.title": "Indexing Latency",
"cluster.metrics.index.axis.query_latency.title": "Query Latency",
"cluster.metrics.index.axis.fetch_latency.title": "Fetch Latency",
"cluster.metrics.index.axis.merge_latency.title": "Merge Latency",
"cluster.metrics.index.axis.refresh_latency.title": "Refresh Latency",
"cluster.metrics.index.axis.query_cache.title": "Query Cache",
"cluster.metrics.index.axis.request_cache.title": "Request Cache",
"cluster.metrics.index.axis.segment_memory.title": "Segment Memory",
"cluster.metrics.index.axis.segment_fields_memory.title":
"Segment Stored Fields Memory",
"cluster.metrics.index.axis.segment_doc_values_memory.title":
"Segment Doc Values Memory",
"cluster.metrics.index.axis.segment_terms_memory.title":
"Segment Terms Memory",
"cluster.metrics.group.system": "System",
"cluster.metrics.group.storage": "Storage",
"cluster.metrics.group.latency": "Latency",
"cluster.metrics.group.operations": "Operations",
"cluster.metrics.group.http": "Http Traffic",
"cluster.metrics.group.memory": "Memory",
"cluster.metrics.group.cache": "Cache",
};

View File

@ -1,412 +1,418 @@
import alert from './zh-CN/alert'; import alert from "./zh-CN/alert";
import console from './zh-CN/console'; import console from "./zh-CN/console";
import cluster from "./zh-CN/cluster";
export default { export default {
'navBar.lang': '语言', "navBar.lang": "语言",
'layout.user.appname':"极限搜索管理后台", "layout.user.appname": "极限搜索管理后台",
'layout.user.appslogon':"极限科技的搜索平台是东半球最好用的搜索服务平台", "layout.user.appslogon": "极限科技的搜索平台是东半球最好用的搜索服务平台",
'app.setting.appname':"极限搜索中心", "app.setting.appname": "极限搜索中心",
'layout.user.link.help': '帮助', "layout.user.link.help": "帮助",
'layout.user.link.privacy': '隐私', "layout.user.link.privacy": "隐私",
'layout.user.link.terms': '条款', "layout.user.link.terms": "条款",
'validation.email.required': '请输入邮箱地址!', "validation.email.required": "请输入邮箱地址!",
'validation.email.wrong-format': '邮箱地址格式错误!', "validation.email.wrong-format": "邮箱地址格式错误!",
'validation.password.required': '请输入密码!', "validation.password.required": "请输入密码!",
'validation.password.twice': '两次输入的密码不匹配!', "validation.password.twice": "两次输入的密码不匹配!",
'validation.password.strength.msg': '请至少输入 6 个字符。请不要使用容易被猜到的密码。', "validation.password.strength.msg":
'validation.password.strength.strong': '强度:强', "请至少输入 6 个字符。请不要使用容易被猜到的密码。",
'validation.password.strength.medium': '强度:中', "validation.password.strength.strong": "强度:强",
'validation.password.strength.short': '强度:太短', "validation.password.strength.medium": "强度:中",
'validation.confirm-password.required': '请确认密码!', "validation.password.strength.short": "强度:太短",
'validation.phone-number.required': '请输入手机号!', "validation.confirm-password.required": "请确认密码!",
'validation.phone-number.wrong-format': '手机号格式错误!', "validation.phone-number.required": "请输入手机号!",
'validation.verification-code.required': '请输入验证码!', "validation.phone-number.wrong-format": "手机号格式错误!",
'validation.title.required': '请输入标题', "validation.verification-code.required": "请输入验证码!",
'validation.date.required': '请选择起止日期', "validation.title.required": "请输入标题",
'validation.goal.required': '请输入目标描述', "validation.date.required": "请选择起止日期",
'validation.standard.required': '请输入衡量标准', "validation.goal.required": "请输入目标描述",
'validation.dbtype.required':"请选择数据库类型", "validation.standard.required": "请输入衡量标准",
'validation.logstashconf.required':"请输入Logstash jdbc配置", "validation.dbtype.required": "请选择数据库类型",
'validation.kafkaconf.required':"请输入Logstash Kafka配置", "validation.logstashconf.required": "请输入Logstash jdbc配置",
'form.optional': '(选填)', "validation.kafkaconf.required": "请输入Logstash Kafka配置",
'form.submit': '提交', "form.optional": "(选填)",
'form.save': '保存', "form.submit": "提交",
'form.email.placeholder': '邮箱', "form.save": "保存",
'form.password.placeholder': '至少6位密码区分大小写', "form.email.placeholder": "邮箱",
'form.confirm-password.placeholder': '确认密码', "form.password.placeholder": "至少6位密码区分大小写",
'form.phone-number.placeholder': '位手机号', "form.confirm-password.placeholder": "确认密码",
'form.verification-code.placeholder': '验证码', "form.phone-number.placeholder": "位手机号",
'form.title.label': '标题', "form.verification-code.placeholder": "验证码",
'form.title.placeholder': '给目标起个名字', "form.title.label": "标题",
'form.date.label': '起止日期', "form.title.placeholder": "给目标起个名字",
'form.date.placeholder.start': '开始日期', "form.date.label": "起止日期",
'form.date.placeholder.end': '结束日期', "form.date.placeholder.start": "开始日期",
'form.goal.label': '目标描述', "form.date.placeholder.end": "结束日期",
'form.goal.placeholder': '请输入你的阶段性工作目标', "form.goal.label": "目标描述",
'form.standard.label': '衡量标准', "form.goal.placeholder": "请输入你的阶段性工作目标",
'form.standard.placeholder': '请输入衡量标准', "form.standard.label": "衡量标准",
'form.client.label': '客户', "form.standard.placeholder": "请输入衡量标准",
'form.client.label.tooltip': '目标的服务对象', "form.client.label": "客户",
'form.client.placeholder': '请描述你服务的客户,内部客户直接 @姓名/工号', "form.client.label.tooltip": "目标的服务对象",
'form.invites.label': '邀评人', "form.client.placeholder": "请描述你服务的客户,内部客户直接 @姓名/工号",
'form.invites.placeholder': '请直接 @姓名/工号,最多可邀请 5 人', "form.invites.label": "邀评人",
'form.weight.label': '权重', "form.invites.placeholder": "请直接 @姓名/工号,最多可邀请 5 人",
'form.weight.placeholder': '请输入', "form.weight.label": "权重",
'form.public.label': '目标公开', "form.weight.placeholder": "请输入",
'form.public.label.help': '客户、邀评人默认被分享', "form.public.label": "目标公开",
'form.public.radio.public': '公开', "form.public.label.help": "客户、邀评人默认被分享",
'form.public.radio.partially-public': '部分公开', "form.public.radio.public": "公开",
'form.public.radio.private': '不公开', "form.public.radio.partially-public": "部分公开",
'form.publicUsers.placeholder': '公开给', "form.public.radio.private": "不公开",
'form.publicUsers.option.A': '同事甲', "form.publicUsers.placeholder": "公开给",
'form.publicUsers.option.B': '同事乙', "form.publicUsers.option.A": "同事甲",
'form.publicUsers.option.C': '同事丙', "form.publicUsers.option.B": "同事乙",
'form.dbtype.label':'数据库类型', "form.publicUsers.option.C": "同事丙",
'form.logstash.jdbcconf.label':"Logstash JDBC 配置", "form.dbtype.label": "数据库类型",
'form.logstash.jdbcconf.placeholder':"请输入JDBC配置", "form.logstash.jdbcconf.label": "Logstash JDBC 配置",
'form.logstash.kafkaconf.label':"Logstash Kafka 配置", "form.logstash.jdbcconf.placeholder": "请输入JDBC配置",
'form.logstash.kafkaconf.placeholder':"请输入Kafka配置", "form.logstash.kafkaconf.label": "Logstash Kafka 配置",
'form.button.search': '搜索', "form.logstash.kafkaconf.placeholder": "请输入Kafka配置",
'form.button.new': '新建', "form.button.search": "搜索",
'form.button.create': '创建', "form.button.new": "新建",
'form.button.add': '添加', "form.button.create": "创建",
'form.button.edit': '编辑', "form.button.add": "添加",
'form.button.update': '更新', "form.button.edit": "编辑",
'form.button.save': '保存', "form.button.update": "更新",
'form.button.delete': '删除', "form.button.save": "保存",
'form.button.cancel': '取消', "form.button.delete": "删除",
'form.button.collapse': '收起', "form.button.cancel": "取消",
'form.button.advanced': '高级', "form.button.collapse": "收起",
'table.field.operation': '操作', "form.button.advanced": "高级",
"table.field.operation": "操作",
"form.button.next": "下一步",
"form.button.pre": "上一步",
'component.globalHeader.search': '站内搜索', "component.globalHeader.search": "站内搜索",
'component.globalHeader.search.example1': '搜索提示一', "component.globalHeader.search.example1": "搜索提示一",
'component.globalHeader.search.example2': '搜索提示二', "component.globalHeader.search.example2": "搜索提示二",
'component.globalHeader.search.example3': '搜索提示三', "component.globalHeader.search.example3": "搜索提示三",
'component.globalHeader.help': '使用文档', "component.globalHeader.help": "使用文档",
'component.globalHeader.notification': '通知', "component.globalHeader.notification": "通知",
'component.globalHeader.notification.empty': '你已查看所有通知', "component.globalHeader.notification.empty": "你已查看所有通知",
'component.globalHeader.message': '消息', "component.globalHeader.message": "消息",
'component.globalHeader.message.empty': '您已读完所有消息', "component.globalHeader.message.empty": "您已读完所有消息",
'component.globalHeader.event': '待办', "component.globalHeader.event": "待办",
'component.globalHeader.event.empty': '你已完成所有待办', "component.globalHeader.event.empty": "你已完成所有待办",
'component.noticeIcon.clear': '清空', "component.noticeIcon.clear": "清空",
'component.noticeIcon.cleared': '清空了', "component.noticeIcon.cleared": "清空了",
'component.noticeIcon.empty': '暂无数据', "component.noticeIcon.empty": "暂无数据",
'menu.home': '首页', "menu.home": "首页",
'menu.devtool': '开发工具', "menu.devtool": "开发工具",
'menu.alerting': '告警管理', "menu.alerting": "告警管理",
'menu.alerting.overview': '概览', "menu.alerting.overview": "概览",
'menu.alerting.monitor': '监控管理', "menu.alerting.monitor": "监控管理",
'menu.alerting.destination': '渠道管理', "menu.alerting.destination": "渠道管理",
'menu.cluster': '集群管理', "menu.cluster": "集群管理",
'menu.cluster.overview': '概览', "menu.cluster.overview": "概览",
'menu.cluster.monitoring': '集群监控', "menu.cluster.monitoring": "集群监控",
'menu.cluster.settings': '集群设置', "menu.cluster.settings": "集群设置",
'menu.cluster.logging': '集群日志', "menu.cluster.logging": "集群日志",
"menu.data": "数据管理",
"menu.data.overview": "概览",
"menu.data.index": "索引管理",
"menu.data.document": "文档管理",
"menu.data.template": "模版管理",
"menu.data.lifecycle": "周期管理",
"menu.data.discover": "数据探索",
"menu.data.indexPatterns": "数据视图",
'menu.data': '数据管理', "menu.search": "搜索管理",
'menu.data.overview': '概览', "menu.search.overview": "概览",
'menu.data.index': '索引管理', "menu.search.template": "搜索模板",
'menu.data.document': '文档管理', "menu.search.alias": "别名管理",
'menu.data.template': '模版管理', "menu.search.dict": "词库管理",
'menu.data.lifecycle': '周期管理', "menu.search.analyzer": "分词管理",
'menu.data.discover': '数据探索', "menu.search.nlp": "自然语言处理",
'menu.data.indexPatterns': '数据视图',
'menu.search': '搜索管理', "menu.synchronize": "同步管理",
'menu.search.overview': '概览', "menu.synchronize.overview": "概览",
'menu.search.template': '搜索模板', "menu.synchronize.pipeline": "数据加工",
'menu.search.alias': '别名管理', "menu.synchronize.rebuild": "数据重建",
'menu.search.dict': '词库管理', "menu.synchronize.inout": "导入导出",
'menu.search.analyzer': '分词管理',
'menu.search.nlp': '自然语言处理',
'menu.synchronize': '同步管理', "menu.backup": "备份管理",
'menu.synchronize.overview': '概览', "menu.backup.overview": "概览",
'menu.synchronize.pipeline': '数据加工', "menu.backup.index": "备份还原",
'menu.synchronize.rebuild': '数据重建', "menu.backup.lifecycle": "备份策略",
'menu.synchronize.inout': '导入导出',
'menu.backup': '备份管理', "menu.system": "系统管理",
'menu.backup.overview': '概览', "menu.system.cluster": "集群管理",
'menu.backup.index': '备份还原', "menu.system.registCluster": "集群注册",
'menu.backup.lifecycle': '备份策略', "menu.system.editCluster": "集群修改",
"menu.system.settings": "系统设置",
"menu.system.settings.global": "全局设置",
"menu.system.settings.gateway": "网关设置",
'menu.system': '系统管理', "menu.system.security": "安全设置",
'menu.system.cluster': '集群管理', "menu.system.security.general": "基础设置",
'menu.system.registCluster': '集群注册', "menu.system.security.sso": "单点登录",
'menu.system.editCluster': '集群修改', "menu.system.security.roles": "角色管理",
'menu.system.settings': '系统设置', "menu.system.security.users": "用户管理",
'menu.system.settings.global': '全局设置', "menu.system.security.certs": "证书管理",
'menu.system.settings.gateway': '网关设置',
'menu.system.security': '安全设置', "menu.system.logs": "系统日志",
'menu.system.security.general': '基础设置', "menu.system.logs.overview": "日志概要",
'menu.system.security.sso': '单点登录', "menu.system.logs.audit": "审计日志",
'menu.system.security.roles': '角色管理', "menu.system.logs.query": "查询日志",
'menu.system.security.users': '用户管理', "menu.system.logs.slow": "慢日志",
'menu.system.security.certs': '证书管理', "menu.system.commonCommand": "常用命令",
'menu.system.logs': '系统日志', "menu.form": "表单页",
'menu.system.logs.overview': '日志概要', "menu.form.basicform": "基础表单",
'menu.system.logs.audit': '审计日志', "menu.form.stepform": "分步表单",
'menu.system.logs.query': '查询日志', "menu.form.stepform.info": "分步表单(填写转账信息)",
'menu.system.logs.slow': '慢日志', "menu.form.stepform.confirm": "分步表单(确认转账信息)",
'menu.system.commonCommand': '常用命令', "menu.form.stepform.result": "分步表单(完成)",
"menu.form.advancedform": "高级表单",
"menu.list": "列表页",
"menu.list.searchtable": "查询表格",
"menu.list.basiclist": "标准列表",
"menu.list.cardlist": "卡片列表",
"menu.list.searchlist": "搜索列表",
"menu.list.searchlist.articles": "搜索列表(文章)",
"menu.list.searchlist.projects": "搜索列表(项目)",
"menu.list.searchlist.applications": "搜索列表(应用)",
"menu.profile": "详情页",
"menu.profile.basic": "基础详情页",
"menu.profile.advanced": "高级详情页",
"menu.result": "结果页",
"menu.result.success": "成功页",
"menu.result.fail": "失败页",
"menu.exception": "异常页",
"menu.exception.not-permission": "403",
"menu.exception.not-find": "404",
"menu.exception.server-error": "500",
"menu.exception.trigger": "触发错误",
"menu.account": "个人页",
"menu.account.center": "个人中心",
"menu.account.settings": "个人设置",
"menu.account.trigger": "触发报错",
"menu.account.logout": "退出登录",
"dashboard.charts.title.cluster_throughput.axis.indexing": "索引吞吐",
"dashboard.charts.title.cluster_throughput.axis.searching": "查询吞吐",
"dashboard.charts.title.cluster_latency.axis.indexing": "索引延迟",
"dashboard.charts.title.cluster_latency.axis.searching": "查询延迟",
"dashboard.charts.title.system_load.axis.load": "系统负载",
"dashboard.charts.title.system_network.axis.traffic": "网络吞吐",
"dashboard.charts.title.system_disk.axis.throughput": "磁盘吞吐",
"dashboard.charts.title.system_disk.axis.iops": "磁盘 IOPS",
"dashboard.charts.title.system_memory.axis.memory": "内存统计",
"dashboard.charts.title.system_memory.axis.gc": "GC 次数",
'menu.form': '表单页', "dashboard.charts.title.cluster_storage.axis.indices_storage": "索引存储",
'menu.form.basicform': '基础表单', "dashboard.charts.title.cluster_storage.axis.available_storage": "剩余存储",
'menu.form.stepform': '分步表单',
'menu.form.stepform.info': '分步表单(填写转账信息)',
'menu.form.stepform.confirm': '分步表单(确认转账信息)',
'menu.form.stepform.result': '分步表单(完成)',
'menu.form.advancedform': '高级表单',
'menu.list': '列表页',
'menu.list.searchtable': '查询表格',
'menu.list.basiclist': '标准列表',
'menu.list.cardlist': '卡片列表',
'menu.list.searchlist': '搜索列表',
'menu.list.searchlist.articles': '搜索列表(文章)',
'menu.list.searchlist.projects': '搜索列表(项目)',
'menu.list.searchlist.applications': '搜索列表(应用)',
'menu.profile': '详情页',
'menu.profile.basic': '基础详情页',
'menu.profile.advanced': '高级详情页',
'menu.result': '结果页',
'menu.result.success': '成功页',
'menu.result.fail': '失败页',
'menu.exception': '异常页',
'menu.exception.not-permission': '403',
'menu.exception.not-find': '404',
'menu.exception.server-error': '500',
'menu.exception.trigger': '触发错误',
'menu.account': '个人页',
'menu.account.center': '个人中心',
'menu.account.settings': '个人设置',
'menu.account.trigger': '触发报错',
'menu.account.logout': '退出登录',
'dashboard.charts.title.cluster_throughput.axis.indexing':"索引吞吐", "dashboard.charts.title.cluster_documents.axis.documents": "文档总数",
'dashboard.charts.title.cluster_throughput.axis.searching':"查询吞吐", "dashboard.charts.title.cluster_documents.axis.counts": "分片总数",
'dashboard.charts.title.cluster_latency.axis.indexing':"索引延迟",
'dashboard.charts.title.cluster_latency.axis.searching':"查询延迟",
'dashboard.charts.title.system_load.axis.load':"系统负载",
'dashboard.charts.title.system_network.axis.traffic':"网络吞吐",
'dashboard.charts.title.system_disk.axis.throughput':"磁盘吞吐",
'dashboard.charts.title.system_disk.axis.iops':"磁盘 IOPS",
'dashboard.charts.title.system_memory.axis.memory':"内存统计",
'dashboard.charts.title.system_memory.axis.gc':"GC 次数",
'dashboard.charts.title.cluster_storage.axis.indices_storage':"索引存储", "app.login.message-invalid-credentials": "账户或密码错误admin/888888",
'dashboard.charts.title.cluster_storage.axis.available_storage':"剩余存储", "app.login.message-invalid-verification-code": "验证码错误",
"app.login.tab-login-credentials": "账户密码登录",
"app.login.tab-login-mobile": "手机号登录",
"app.login.remember-me": "自动登录",
"app.login.forgot-password": "忘记密码",
"app.login.sign-in-with": "其他登录方式",
"app.login.signup": "注册账户",
"app.login.login": "登录",
"app.register.register": "注册",
"app.register.get-verification-code": "获取验证码",
"app.register.sing-in": "使用已有账户登录",
"app.register-result.msg": "你的账户:{email} 注册成功",
"app.register-result.activation-email":
"激活邮件已发送到你的邮箱中邮件有效期为24小时。请及时登录邮箱点击邮件中的链接激活帐户。",
"app.register-result.back-home": "返回首页",
"app.register-result.view-mailbox": "查看邮箱",
"app.home.introduce": "介绍",
"app.analysis.test": "工专路 {no} 号店",
"app.analysis.introduce": "指标说明",
"app.analysis.total-sales": "总销售额",
"app.analysis.day-sales": "日销售额",
"app.analysis.visits": "访问量",
"app.analysis.visits-trend": "访问量趋势",
"app.analysis.visits-ranking": "门店访问量排名",
"app.analysis.day-visits": "日访问量",
"app.analysis.week": "周同比",
"app.analysis.day": "日同比",
"app.analysis.payments": "支付笔数",
"app.analysis.conversion-rate": "转化率",
"app.analysis.operational-effect": "运营活动效果",
"app.analysis.sales-trend": "销售趋势",
"app.analysis.sales-ranking": "门店销售额排名",
"app.analysis.all-year": "全年",
"app.analysis.all-month": "本月",
"app.analysis.all-week": "本周",
"app.analysis.all-day": "今日",
"app.analysis.search-users": "搜索用户数",
"app.analysis.per-capita-search": "人均搜索次数",
"app.analysis.online-top-search": "线上热门搜索",
"app.analysis.the-proportion-of-sales": "销售额类别占比",
"app.analysis.channel.all": "全部渠道",
"app.analysis.channel.online": "线上",
"app.analysis.channel.stores": "门店",
"app.analysis.sales": "销售额",
"app.analysis.traffic": "客流量",
"app.analysis.table.rank": "排名",
"app.analysis.table.search-keyword": "搜索关键词",
"app.analysis.table.users": "用户数",
"app.analysis.table.weekly-range": "周涨幅",
"app.forms.basic.title": "基础表单",
"app.forms.basic.description":
"表单页用于向用户收集或验证信息,基础表单常见于数据项较少的表单场景。",
"app.monitor.trading-activity": "活动实时交易情况",
"app.monitor.total-transactions": "今日交易总额",
"app.monitor.sales-target": "销售目标完成率",
"app.monitor.remaining-time": "活动剩余时间",
"app.monitor.total-transactions-per-second": "每秒交易总额",
"app.monitor.activity-forecast": "活动情况预测",
"app.monitor.efficiency": "券核效率",
"app.monitor.ratio": "跳出率",
"app.monitor.proportion-per-category": "各品类占比",
"app.monitor.fast-food": "中式快餐",
"app.monitor.western-food": "西餐",
"app.monitor.hot-pot": "火锅",
"app.monitor.waiting-for-implementation": "Waiting for implementation",
"app.monitor.popular-searches": "热门搜索",
"app.monitor.resource-surplus": "资源剩余",
"app.monitor.fund-surplus": "补贴资金剩余",
'dashboard.charts.title.cluster_documents.axis.documents':"文档总数", "app.settings.security.update": "更新设置",
'dashboard.charts.title.cluster_documents.axis.counts':"分片总数", "app.settings.global.update": "更新设置",
"app.settings.global.site_name": "站点名称",
"app.settings.global.domain": "站点域名",
"app.settings.global.listen_addr": "监听地址",
"app.settings.global.is_tls": "开启 TLS",
"app.settings.global.data_path": "数据目录",
"app.settings.global.log_path": "日志目录",
'app.login.message-invalid-credentials': '账户或密码错误admin/888888', "app.settings.security.auth2factor_enabled": "开启双因子身份认证",
'app.login.message-invalid-verification-code': '验证码错误', "app.settings.security.audit_enabled": "开启审计日志",
'app.login.tab-login-credentials': '账户密码登录',
'app.login.tab-login-mobile': '手机号登录',
'app.login.remember-me': '自动登录',
'app.login.forgot-password': '忘记密码',
'app.login.sign-in-with': '其他登录方式',
'app.login.signup': '注册账户',
'app.login.login': '登录',
'app.register.register': '注册',
'app.register.get-verification-code': '获取验证码',
'app.register.sing-in': '使用已有账户登录',
'app.register-result.msg': '你的账户:{email} 注册成功',
'app.register-result.activation-email':
'激活邮件已发送到你的邮箱中邮件有效期为24小时。请及时登录邮箱点击邮件中的链接激活帐户。',
'app.register-result.back-home': '返回首页',
'app.register-result.view-mailbox': '查看邮箱',
'app.home.introduce': '介绍',
'app.analysis.test': '工专路 {no} 号店',
'app.analysis.introduce': '指标说明',
'app.analysis.total-sales': '总销售额',
'app.analysis.day-sales': '日销售额',
'app.analysis.visits': '访问量',
'app.analysis.visits-trend': '访问量趋势',
'app.analysis.visits-ranking': '门店访问量排名',
'app.analysis.day-visits': '日访问量',
'app.analysis.week': '周同比',
'app.analysis.day': '日同比',
'app.analysis.payments': '支付笔数',
'app.analysis.conversion-rate': '转化率',
'app.analysis.operational-effect': '运营活动效果',
'app.analysis.sales-trend': '销售趋势',
'app.analysis.sales-ranking': '门店销售额排名',
'app.analysis.all-year': '全年',
'app.analysis.all-month': '本月',
'app.analysis.all-week': '本周',
'app.analysis.all-day': '今日',
'app.analysis.search-users': '搜索用户数',
'app.analysis.per-capita-search': '人均搜索次数',
'app.analysis.online-top-search': '线上热门搜索',
'app.analysis.the-proportion-of-sales': '销售额类别占比',
'app.analysis.channel.all': '全部渠道',
'app.analysis.channel.online': '线上',
'app.analysis.channel.stores': '门店',
'app.analysis.sales': '销售额',
'app.analysis.traffic': '客流量',
'app.analysis.table.rank': '排名',
'app.analysis.table.search-keyword': '搜索关键词',
'app.analysis.table.users': '用户数',
'app.analysis.table.weekly-range': '周涨幅',
'app.forms.basic.title': '基础表单',
'app.forms.basic.description':
'表单页用于向用户收集或验证信息,基础表单常见于数据项较少的表单场景。',
'app.monitor.trading-activity': '活动实时交易情况',
'app.monitor.total-transactions': '今日交易总额',
'app.monitor.sales-target': '销售目标完成率',
'app.monitor.remaining-time': '活动剩余时间',
'app.monitor.total-transactions-per-second': '每秒交易总额',
'app.monitor.activity-forecast': '活动情况预测',
'app.monitor.efficiency': '券核效率',
'app.monitor.ratio': '跳出率',
'app.monitor.proportion-per-category': '各品类占比',
'app.monitor.fast-food': '中式快餐',
'app.monitor.western-food': '西餐',
'app.monitor.hot-pot': '火锅',
'app.monitor.waiting-for-implementation': 'Waiting for implementation',
'app.monitor.popular-searches': '热门搜索',
'app.monitor.resource-surplus': '资源剩余',
'app.monitor.fund-surplus': '补贴资金剩余',
"app.settings.menuMap.basic": "基本设置",
'app.settings.security.update':"更新设置", "app.settings.menuMap.security": "安全设置",
'app.settings.global.update':"更新设置", "app.settings.menuMap.binding": "账号绑定",
'app.settings.global.site_name':"站点名称", "app.settings.menuMap.notification": "新消息通知",
'app.settings.global.domain':"站点域名", "app.settings.basic.avatar": "头像",
'app.settings.global.listen_addr':"监听地址", "app.settings.basic.change-avatar": "更换头像",
'app.settings.global.is_tls':"开启 TLS", "app.settings.basic.email": "邮箱",
'app.settings.global.data_path':"数据目录", "app.settings.basic.email-message": "请输入您的邮箱!",
'app.settings.global.log_path':"日志目录", "app.settings.basic.nickname": "昵称",
"app.settings.basic.nickname-message": "请输入您的昵称!",
'app.settings.security.auth2factor_enabled':"开启双因子身份认证", "app.settings.basic.profile": "个人简介",
'app.settings.security.audit_enabled':"开启审计日志", "app.settings.basic.profile-message": "请输入个人简介!",
"app.settings.basic.profile-placeholder": "个人简介",
"app.settings.basic.country": "国家/地区",
'app.settings.menuMap.basic': '基本设置', "app.settings.basic.country-message": "请输入您的国家或地区!",
'app.settings.menuMap.security': '安全设置', "app.settings.basic.geographic": "所在省市",
'app.settings.menuMap.binding': '账号绑定', "app.settings.basic.geographic-message": "请输入您的所在省市!",
'app.settings.menuMap.notification': '新消息通知', "app.settings.basic.address": "街道地址",
'app.settings.basic.avatar': '头像', "app.settings.basic.address-message": "请输入您的街道地址!",
'app.settings.basic.change-avatar': '更换头像', "app.settings.basic.phone": "联系电话",
'app.settings.basic.email': '邮箱', "app.settings.basic.phone-message": "请输入您的联系电话!",
'app.settings.basic.email-message': '请输入您的邮箱!', "app.settings.basic.update": "更新基本信息",
'app.settings.basic.nickname': '昵称', "app.settings.security.strong": "强",
'app.settings.basic.nickname-message': '请输入您的昵称!', "app.settings.security.medium": "中",
'app.settings.basic.profile': '个人简介', "app.settings.security.weak": "弱",
'app.settings.basic.profile-message': '请输入个人简介!', "app.settings.security.password": "账户密码",
'app.settings.basic.profile-placeholder': '个人简介', "app.settings.security.password-description": "当前密码强度:",
'app.settings.basic.country': '国家/地区', "app.settings.security.phone": "密保手机",
'app.settings.basic.country-message': '请输入您的国家或地区!', "app.settings.security.phone-description": "已绑定手机:",
'app.settings.basic.geographic': '所在省市', "app.settings.security.question": "密保问题",
'app.settings.basic.geographic-message': '请输入您的所在省市!', "app.settings.security.question-description":
'app.settings.basic.address': '街道地址', "未设置密保问题,密保问题可有效保护账户安全",
'app.settings.basic.address-message': '请输入您的街道地址!', "app.settings.security.email": "备用邮箱",
'app.settings.basic.phone': '联系电话', "app.settings.security.email-description": "已绑定邮箱:",
'app.settings.basic.phone-message': '请输入您的联系电话!', "app.settings.security.mfa": "MFA 设备",
'app.settings.basic.update': '更新基本信息', "app.settings.security.mfa-description":
'app.settings.security.strong': '强', "未绑定 MFA 设备,绑定后,可以进行二次确认",
'app.settings.security.medium': '中', "app.settings.security.modify": "修改",
'app.settings.security.weak': '弱', "app.settings.security.set": "设置",
'app.settings.security.password': '账户密码', "app.settings.security.bind": "绑定",
'app.settings.security.password-description': '当前密码强度:', "app.settings.binding.taobao": "绑定淘宝",
'app.settings.security.phone': '密保手机', "app.settings.binding.taobao-description": "当前未绑定淘宝账号",
'app.settings.security.phone-description': '已绑定手机:', "app.settings.binding.alipay": "绑定支付宝",
'app.settings.security.question': '密保问题', "app.settings.binding.alipay-description": "当前未绑定支付宝账号",
'app.settings.security.question-description': '未设置密保问题,密保问题可有效保护账户安全', "app.settings.binding.dingding": "绑定钉钉",
'app.settings.security.email': '备用邮箱', "app.settings.binding.dingding-description": "当前未绑定钉钉账号",
'app.settings.security.email-description': '已绑定邮箱:', "app.settings.binding.bind": "绑定",
'app.settings.security.mfa': 'MFA 设备', "app.settings.notification.password": "账户密码",
'app.settings.security.mfa-description': '未绑定 MFA 设备,绑定后,可以进行二次确认', "app.settings.notification.password-description":
'app.settings.security.modify': '修改', "其他用户的消息将以站内信的形式通知",
'app.settings.security.set': '设置', "app.settings.notification.messages": "系统消息",
'app.settings.security.bind': '绑定', "app.settings.notification.messages-description":
'app.settings.binding.taobao': '绑定淘宝', "系统消息将以站内信的形式通知",
'app.settings.binding.taobao-description': '当前未绑定淘宝账号', "app.settings.notification.todo": "账户密码",
'app.settings.binding.alipay': '绑定支付宝', "app.settings.notification.todo-description": "账户密码",
'app.settings.binding.alipay-description': '当前未绑定支付宝账号', "app.settings.open": "开",
'app.settings.binding.dingding': '绑定钉钉', "app.settings.close": "关",
'app.settings.binding.dingding-description': '当前未绑定钉钉账号', "app.exception.back": "返回首页",
'app.settings.binding.bind': '绑定', "app.exception.description.403": "抱歉,你无权访问该页面",
'app.settings.notification.password': '账户密码', "app.exception.description.404": "抱歉,你访问的页面不存在",
'app.settings.notification.password-description': '其他用户的消息将以站内信的形式通知', "app.exception.description.500": "抱歉,服务器出错了",
'app.settings.notification.messages': '系统消息', "app.result.error.title": "提交失败",
'app.settings.notification.messages-description': '系统消息将以站内信的形式通知', "app.result.error.description": "请核对并修改以下信息后,再重新提交。",
'app.settings.notification.todo': '账户密码', "app.result.error.hint-title": "您提交的内容有如下错误:",
'app.settings.notification.todo-description': '账户密码', "app.result.error.hint-text1": "您的账户已被冻结",
'app.settings.open': '开', "app.result.error.hint-btn1": "立即解冻",
'app.settings.close': '关', "app.result.error.hint-text2": "您的账户还不具备申请资格",
'app.exception.back': '返回首页', "app.result.error.hint-btn2": "立即升级",
'app.exception.description.403': '抱歉,你无权访问该页面', "app.result.error.btn-text": "返回修改",
'app.exception.description.404': '抱歉,你访问的页面不存在', "app.result.success.title": "提交成功",
'app.exception.description.500': '抱歉,服务器出错了', "app.result.success.description":
'app.result.error.title': '提交失败', "提交结果页用于反馈一系列操作任务的处理结果, 如果仅是简单操作,使用 Message 全局提示反馈即可。 本文字区域可以展示简单的补充说明,如果有类似展示 “单据”的需求,下面这个灰色区域可以呈现比较复杂的内容。",
'app.result.error.description': '请核对并修改以下信息后,再重新提交。', "app.result.success.operate-title": "项目名称",
'app.result.error.hint-title': '您提交的内容有如下错误:', "app.result.success.operate-id": "项目 ID",
'app.result.error.hint-text1': '您的账户已被冻结', "app.result.success.principal": "负责人:",
'app.result.error.hint-btn1': '立即解冻', "app.result.success.operate-time": "生效时间:",
'app.result.error.hint-text2': '您的账户还不具备申请资格', "app.result.success.step1-title": "创建项目",
'app.result.error.hint-btn2': '立即升级', "app.result.success.step1-operator": "曲丽丽",
'app.result.error.btn-text': '返回修改', "app.result.success.step2-title": "部门初审",
'app.result.success.title': '提交成功', "app.result.success.step2-operator": "周毛毛",
'app.result.success.description': "app.result.success.step2-extra": "催一下",
'提交结果页用于反馈一系列操作任务的处理结果, 如果仅是简单操作,使用 Message 全局提示反馈即可。 本文字区域可以展示简单的补充说明,如果有类似展示 “单据”的需求,下面这个灰色区域可以呈现比较复杂的内容。', "app.result.success.step3-title": "财务复核",
'app.result.success.operate-title': '项目名称', "app.result.success.step4-title": "完成",
'app.result.success.operate-id': '项目 ID', "app.result.success.btn-return": "返回列表",
'app.result.success.principal': '负责人:', "app.result.success.btn-project": "查看项目",
'app.result.success.operate-time': '生效时间:', "app.result.success.btn-print": "打印",
'app.result.success.step1-title': '创建项目', "app.setting.pagestyle": "整体风格设置",
'app.result.success.step1-operator': '曲丽丽', "app.setting.pagestyle.dark": "暗色菜单风格",
'app.result.success.step2-title': '部门初审', "app.setting.pagestyle.light": "亮色菜单风格",
'app.result.success.step2-operator': '周毛毛', "app.setting.content-width": "内容区域宽度",
'app.result.success.step2-extra': '催一下', "app.setting.content-width.fixed": "定宽",
'app.result.success.step3-title': '财务复核', "app.setting.content-width.fluid": "流式",
'app.result.success.step4-title': '完成', "app.setting.themecolor": "主题色",
'app.result.success.btn-return': '返回列表', "app.setting.themecolor.dust": "薄暮",
'app.result.success.btn-project': '查看项目', "app.setting.themecolor.volcano": "火山",
'app.result.success.btn-print': '打印', "app.setting.themecolor.sunset": "日暮",
'app.setting.pagestyle': '整体风格设置', "app.setting.themecolor.cyan": "明青",
'app.setting.pagestyle.dark': '暗色菜单风格', "app.setting.themecolor.green": "极光绿",
'app.setting.pagestyle.light': '亮色菜单风格', "app.setting.themecolor.daybreak": "拂晓蓝(默认)",
'app.setting.content-width': '内容区域宽度', "app.setting.themecolor.geekblue": "极客蓝",
'app.setting.content-width.fixed': '定宽', "app.setting.themecolor.purple": "酱紫",
'app.setting.content-width.fluid': '流式', "app.setting.navigationmode": "导航模式",
'app.setting.themecolor': '主题色', "app.setting.sidemenu": "侧边菜单布局",
'app.setting.themecolor.dust': '薄暮', "app.setting.topmenu": "顶部菜单布局",
'app.setting.themecolor.volcano': '火山', "app.setting.fixedheader": "固定 Header",
'app.setting.themecolor.sunset': '日暮', "app.setting.fixedsidebar": "固定侧边菜单",
'app.setting.themecolor.cyan': '明青', "app.setting.fixedsidebar.hint": "侧边菜单布局时可配置",
'app.setting.themecolor.green': '极光绿', "app.setting.hideheader": "下滑时隐藏 Header",
'app.setting.themecolor.daybreak': '拂晓蓝(默认)', "app.setting.hideheader.hint": "固定 Header 时可配置",
'app.setting.themecolor.geekblue': '极客蓝', "app.setting.othersettings": "其他设置",
'app.setting.themecolor.purple': '酱紫', "app.setting.weakmode": "色弱模式",
'app.setting.navigationmode': '导航模式', "app.setting.copy": "拷贝设置",
'app.setting.sidemenu': '侧边菜单布局', "app.setting.copyinfo":
'app.setting.topmenu': '顶部菜单布局', "拷贝成功,请到 src/defaultSettings.js 中替换默认配置",
'app.setting.fixedheader': '固定 Header', "app.setting.production.hint":
'app.setting.fixedsidebar': '固定侧边菜单', "配置栏只在开发环境用于预览,生产环境不会展现,请拷贝后手动修改配置文件",
'app.setting.fixedsidebar.hint': '侧边菜单布局时可配置',
'app.setting.hideheader': '下滑时隐藏 Header',
'app.setting.hideheader.hint': '固定 Header 时可配置',
'app.setting.othersettings': '其他设置',
'app.setting.weakmode': '色弱模式',
'app.setting.copy': '拷贝设置',
'app.setting.copyinfo': '拷贝成功,请到 src/defaultSettings.js 中替换默认配置',
'app.setting.production.hint':
'配置栏只在开发环境用于预览,生产环境不会展现,请拷贝后手动修改配置文件',
...alert, ...alert,
...console, ...console,
...cluster,
}; };

View File

@ -0,0 +1,109 @@
export default {
"cluster.manage.title": "集群管理",
"cluster.manage.description":
"集群管理可以帮助您快速接入不同版本的 Elasticsearch 集群,以及删除和修改集群配置。",
"cluster.manage.label.cluster_name": "集群名称",
"cluster.manage.btn.regist": "注册集群",
"cluster.manage.table.column.name": "集群名称",
"cluster.manage.table.column.health": "集群状态",
"cluster.manage.table.column.version": "程序版本",
"cluster.manage.table.column.node_count": "节点数",
"cluster.manage.table.column.endpoint": "集群地址",
"cluster.manage.table.column.monitored": "监控启用状态",
"cluster.manage.table.column.operation": "操作",
"cluster.manage.table.column.description": "描述",
"cluster.manage.monitored.on": "启用",
"cluster.manage.monitored.off": "关闭",
"cluster.regist.title": "集群注册",
"cluster.regist.description": "输入集群地址和身份验证信息分步创建集群。",
"cluster.regist.step.connect.title": "连接",
"cluster.regist.step.confirm.title": "确认",
"cluster.regist.step.complete.title": "完成",
"cluster.regist.step.connect.label.auth": "身份验证",
"cluster.regist.step.connect.label.username": "用户名",
"cluster.regist.step.connect.label.password": "密码",
"cluster.regist.step.connect.label.data_nodes": "数据节点数",
"cluster.regist.step.connect.label.shards": "分片数",
"cluster.regist.step.complete.success": "注册成功",
"cluster.regist.step.complete.btn.create": "再注册一个集群",
"cluster.regist.step.complete.btn.goto": "查看集群列表",
"cluster.regist.step.complete.tls.yes": "是",
"cluster.regist.step.complete.tls.no": "否",
"cluster.monitor.cluster.title": "集群",
"cluster.monitor.node.title": "节点",
"cluster.monitor.index.title": "索引",
"cluster.monitor.summary.name": "集群名称",
"cluster.monitor.summary.online_time": "在线时长",
"cluster.monitor.summary.version": "集群版本",
"cluster.monitor.summary.health": "健康状态",
"cluster.monitor.summary.node_count": "节点数",
"cluster.monitor.summary.total_index": "索引数",
"cluster.monitor.summary.shard": "主/总分片",
"cluster.monitor.summary.unassign_shard": "未分配分片",
"cluster.monitor.summary.total_docs": "文档数",
"cluster.monitor.summary.storage": "存储空间",
"cluster.monitor.summary.jvm": "JVM 内存",
"cluster.monitor.timepicker.last15minutes": "最近15分钟",
"cluster.monitor.timepicker.thisweek": "这个星期",
"cluster.monitor.timepicker.last30minutes": "最近30分钟",
"cluster.monitor.timepicker.lasthour": "最近1小时",
"cluster.monitor.timepicker.lastday": "最近1天",
"cluster.monitor.timepicker.lastweek": "最近1周",
"cluster.monitor.timepicker.lastmonth": "最近1个月",
"cluster.monitor.timepicker.last3month": "最近3个月",
"cluster.monitor.timepicker.lastyear": "最近1年",
"cluster.monitor.timepicker.today": "今天",
"cluster.metrics.node.axis.cpu.title": "CPU Usage",
"cluster.metrics.node.axis.disk.title": "Disk Available",
"cluster.metrics.node.axis.indexing_rate.title": "Indexing Rate",
"cluster.metrics.node.axis.query_rate.title": "Query Rate",
"cluster.metrics.node.axis.fetch_rate.title": "Fetch Rate",
"cluster.metrics.node.axis.flush_latency.title": "Flush Latency",
"cluster.metrics.node.axis.indexing_latency.title": "Indexing Latency",
"cluster.metrics.node.axis.query_latency.title": "Query Latency",
"cluster.metrics.node.axis.fetch_latency.title": "Fetch Latency",
"cluster.metrics.node.axis.merge_latency.title": "Merge Latency",
"cluster.metrics.node.axis.refresh_latency.title": "Refresh Latency",
"cluster.metrics.node.axis.flush_latency.title": "Flush Latency",
"cluster.metrics.node.axis.query_cache.title": "Query Cache",
"cluster.metrics.node.axis.request_cache.title": "Request Cache",
"cluster.metrics.node.axis.http_connect_num.title": "Http Connections",
"cluster.metrics.node.axis.http_rate.title": "Rate Of Opened Connections",
"cluster.metrics.node.axis.segment_memory.title": "Segment Memory",
"cluster.metrics.node.axis.segment_count.title": "Segment Count",
"cluster.metrics.node.axis.docs_count.title": "Document Count",
"cluster.metrics.node.axis.index_storage.title": "Indices Storage",
"cluster.metrics.node.axis.jvm_heap_used_percent.title": "JVM Heap Usage",
"cluster.metrics.index.axis.index_storage.title": "Index Storage",
"cluster.metrics.index.axis.doc_count.title": "Document count",
"cluster.metrics.index.axis.query_times.title": "Query Requests",
"cluster.metrics.index.axis.fetch_times.title": "Fetch Requests",
"cluster.metrics.index.axis.merge_times.title": "Merge Requests",
"cluster.metrics.index.axis.refresh_times.title": "Refresh Requests",
"cluster.metrics.index.axis.indexing_rate.title": "Indexing Rate",
"cluster.metrics.index.axis.indexing_latency.title": "Indexing Latency",
"cluster.metrics.index.axis.query_latency.title": "Query Latency",
"cluster.metrics.index.axis.fetch_latency.title": "Fetch Latency",
"cluster.metrics.index.axis.merge_latency.title": "Merge Latency",
"cluster.metrics.index.axis.refresh_latency.title": "Refresh Latency",
"cluster.metrics.index.axis.query_cache.title": "Query Cache",
"cluster.metrics.index.axis.request_cache.title": "Request Cache",
"cluster.metrics.index.axis.segment_memory.title": "Segment Memory",
"cluster.metrics.index.axis.segment_fields_memory.title":
"Segment Stored Fields Memory",
"cluster.metrics.index.axis.segment_doc_values_memory.title":
"Segment Doc Values Memory",
"cluster.metrics.index.axis.segment_terms_memory.title":
"Segment Terms Memory",
"cluster.metrics.group.system": "System",
"cluster.metrics.group.storage": "Storage",
"cluster.metrics.group.latency": "Latency",
"cluster.metrics.group.operations": "Operations",
"cluster.metrics.group.http": "Http Traffic",
"cluster.metrics.group.memory": "Memory",
"cluster.metrics.group.cache": "Cache",
};

View File

@ -162,6 +162,7 @@ const MonitorDatePicker = ({
clusterMonitor, clusterMonitor,
selectedCluster: global.selectedCluster, selectedCluster: global.selectedCluster,
clusterList: global.clusterList, clusterList: global.clusterList,
clusterStatus: global.clusterStatus,
})) }))
class ClusterMonitor extends PureComponent { class ClusterMonitor extends PureComponent {
constructor(props) { constructor(props) {
@ -376,52 +377,72 @@ class ClusterMonitor extends PureComponent {
{ {
from: "now-15m", from: "now-15m",
to: "now", to: "now",
display: "最近15分钟", display: formatMessage({
id: "cluster.monitor.timepicker.last15minutes",
}),
}, },
{ {
from: "now-30m", from: "now-30m",
to: "now", to: "now",
display: "最近30分钟", display: formatMessage({
id: "cluster.monitor.timepicker.last30minutes",
}),
}, },
{ {
from: "now-1h", from: "now-1h",
to: "now", to: "now",
display: "最近一小时", display: formatMessage({
id: "cluster.monitor.timepicker.lasthour",
}),
}, },
{ {
from: "now-24h", from: "now-24h",
to: "now", to: "now",
display: "最近一天", display: formatMessage({
id: "cluster.monitor.timepicker.lastday",
}),
}, },
{ {
from: "now/d", from: "now/d",
to: "now/d", to: "now/d",
display: "今天", display: formatMessage({
id: "cluster.monitor.timepicker.today",
}),
}, },
{ {
from: "now/w", from: "now/w",
to: "now/w", to: "now/w",
display: "这个星期", display: formatMessage({
id: "cluster.monitor.timepicker.thisweek",
}),
}, },
{ {
from: "now-7d", from: "now-7d",
to: "now", to: "now",
display: "最近一周", display: formatMessage({
id: "cluster.monitor.timepicker.lastweek",
}),
}, },
{ {
from: "now-30d", from: "now-30d",
to: "now", to: "now",
display: "最近一个月", display: formatMessage({
id: "cluster.monitor.timepicker.lastmonth",
}),
}, },
{ {
from: "now-90d", from: "now-90d",
to: "now", to: "now",
display: "最近三个月", display: formatMessage({
id: "cluster.monitor.timepicker.last3month",
}),
}, },
{ {
from: "now-1y", from: "now-1y",
to: "now", to: "now",
display: "最近一年", display: formatMessage({
id: "cluster.monitor.timepicker.lastyear",
}),
}, },
].map(({ from, to, display }) => { ].map(({ from, to, display }) => {
return { return {
@ -430,240 +451,278 @@ class ClusterMonitor extends PureComponent {
label: display, label: display,
}; };
}); });
let clusterAvailable = true;
const { clusterStatus: cstatus, selectedCluster } = this.props;
if (cstatus && selectedCluster) {
clusterAvailable = cstatus[selectedCluster.id].available;
}
return ( return (
<Spin spinning={this.state.spinning} tip="Loading..."> // <Spin spinning={this.state.spinning} tip="Loading...">
<div style={{ background: "#fff" }}> <div style={{ background: "#fff" }}>
<div style={{ background: "#fff", padding: "5px", marginBottom: 5 }}> <div style={{ background: "#fff", padding: "5px", marginBottom: 5 }}>
<MonitorDatePicker <MonitorDatePicker
timeRange={this.state.timeRange} timeRange={this.state.timeRange}
commonlyUsedRanges={commonlyUsedRanges} commonlyUsedRanges={commonlyUsedRanges}
isLoading={this.state.spinning} isLoading={this.state.spinning}
onChange={this.handleTimeChange} onChange={this.handleTimeChange}
/> />
</div>
<div
style={{
padding: 15,
borderTop: "1px solid rgb(232, 232, 232)",
borderBottom: "1px solid rgb(232, 232, 232)",
}}
>
<Row gutter={[16, { xs: 8, sm: 16, md: 24, lg: 32 }]}>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title="集群名称"
value={clusterStats.cluster_name}
/>
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title="在线时长"
value={clusterStats.uptime}
/>
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title="集群版本"
value={clusterStats.version}
/>
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title="健康情况"
value={clusterStats.status}
prefix={<HealthCircle color={clusterStats.status} />}
/>
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title="节点数"
value={clusterStats.nodes_count}
/>
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title="索引数"
value={clusterStats.indices_count}
/>
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title="主/总分片"
value={
clusterStats.primary_shards +
"/" +
clusterStats.total_shards
}
/>
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title="未分配分片"
value={clusterStats.unassigned_shards}
/>
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title="文档数"
value={clusterStats.document_count}
/>
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title="存储空间"
value={
clusterStats.used_store_bytes +
"/" +
clusterStats.max_store_bytes
}
/>
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title="JVM 内存"
value={
clusterStats.used_jvm_bytes +
"/" +
clusterStats.max_jvm_bytes
}
/>
</Col>
</Row>
</div>
<div>
<Tabs animated={false}>
<Tabs.TabPane key="cluster" tab="Cluster">
{Object.keys(clusterMetrics).map((e, i) => {
let axis = clusterMetrics[e].axis;
let lines = clusterMetrics[e].lines;
let disableHeaderFormat = false;
let headerUnit = "";
return (
<div key={e} className={styles.vizChartContainer}>
<Chart
size={[, 200]}
className={styles.vizChartItem}
ref={this.chartRefs[i]}
>
<Settings
pointerUpdateDebounce={0}
pointerUpdateTrigger="x"
externalPointerEvents={{
tooltip: { visible: true },
}}
onPointerUpdate={this.pointerUpdate}
theme={theme}
showLegend
legendPosition={Position.Top}
onBrushEnd={this.handleChartBrush}
tooltip={{
headerFormatter: disableHeaderFormat
? undefined
: ({ value }) =>
`${formatter.full_dates(value)}${
headerUnit ? ` ${headerUnit}` : ""
}`,
}}
debug={false}
/>
<Axis
id="{e}-bottom"
position={Position.Bottom}
showOverlappingTicks
labelFormat={this.state.timeRange.timeFormatter}
tickFormat={this.state.timeRange.timeFormatter}
/>
{axis.map((item) => {
return (
<Axis
key={e + "-" + item.id}
id={e + "-" + item.id}
showGridLines={item.showGridLines}
groupId={item.group}
title={formatMessage({
id:
"dashboard.charts.title." +
e +
".axis." +
item.title,
})}
position={item.position}
ticks={item.ticks}
labelFormat={getFormatter(
item.formatType,
item.labelFormat
)}
tickFormat={getFormatter(
item.formatType,
item.tickFormat
)}
/>
);
})}
{lines.map((item) => {
return (
<LineSeries
key={item.metric.label}
id={item.metric.label}
groupId={item.metric.group}
timeZone={timezone}
xScaleType={ScaleType.Time}
yScaleType={ScaleType.Linear}
xAccessor={0}
tickFormat={getFormatter(
item.metric.formatType,
item.metric.tickFormat,
item.metric.units
)}
yAccessors={[1]}
data={item.data}
curve={CurveType.CURVE_MONOTONE_X}
/>
);
})}
</Chart>
</div>
);
})}
</Tabs.TabPane>
<Tabs.TabPane key="node" tab="Node">
<NodeMetric
clusterID={this.props.selectedCluster.id}
timezone={timezone}
timeRange={this.state.timeRange}
handleTimeChange={this.handleTimeChange}
/>
</Tabs.TabPane>
<Tabs.TabPane key="index" tab="Index">
<IndexMetric
clusterID={this.props.selectedCluster.id}
timezone={timezone}
timeRange={this.state.timeRange}
handleTimeChange={this.handleTimeChange}
/>
</Tabs.TabPane>
</Tabs>
</div>
</div> </div>
</Spin>
<div className={styles.summary}>
{!clusterAvailable ? (
<div className={styles.mask}>Cluster is not availabe.</div>
) : null}
<Row
gutter={[16, { xs: 8, sm: 16, md: 24, lg: 32 }]}
className={!clusterAvailable ? styles.metricMask : ""}
>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title={formatMessage({
id: "cluster.monitor.summary.name",
})}
value={clusterStats.cluster_name}
/>
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title={formatMessage({
id: "cluster.monitor.summary.online_time",
})}
value={clusterStats.uptime}
/>
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title={formatMessage({
id: "cluster.monitor.summary.version",
})}
value={clusterStats.version}
/>
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title={formatMessage({
id: "cluster.monitor.summary.health",
})}
value={clusterStats.status}
prefix={<HealthCircle color={clusterStats.status} />}
/>
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title={formatMessage({
id: "cluster.monitor.summary.node_count",
})}
value={clusterStats.nodes_count}
/>
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title={formatMessage({
id: "cluster.monitor.summary.total_index",
})}
value={clusterStats.indices_count}
/>
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title={formatMessage({
id: "cluster.monitor.summary.shard",
})}
value={
clusterStats.primary_shards + "/" + clusterStats.total_shards
}
/>
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title={formatMessage({
id: "cluster.monitor.summary.unassign_shard",
})}
value={clusterStats.unassigned_shards}
/>
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title={formatMessage({
id: "cluster.monitor.summary.total_docs",
})}
value={clusterStats.document_count}
/>
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title={formatMessage({
id: "cluster.monitor.summary.storage",
})}
value={
clusterStats.used_store_bytes +
"/" +
clusterStats.max_store_bytes
}
/>
</Col>
<Col md={2} xs={4}>
<Statistic
valueStyle={vstyle}
title={formatMessage({
id: "cluster.monitor.summary.jvm",
})}
value={
clusterStats.used_jvm_bytes + "/" + clusterStats.max_jvm_bytes
}
/>
</Col>
</Row>
</div>
<div>
<Tabs animated={false}>
<Tabs.TabPane
key="cluster"
tab={formatMessage({
id: "cluster.monitor.cluster.title",
})}
>
{Object.keys(clusterMetrics).map((e, i) => {
let axis = clusterMetrics[e].axis;
let lines = clusterMetrics[e].lines;
let disableHeaderFormat = false;
let headerUnit = "";
return (
<div key={e} className={styles.vizChartContainer}>
<Chart
size={[, 200]}
className={styles.vizChartItem}
ref={this.chartRefs[i]}
>
<Settings
pointerUpdateDebounce={0}
pointerUpdateTrigger="x"
// externalPointerEvents={{
// tooltip: { visible: true },
// }}
onPointerUpdate={this.pointerUpdate}
theme={theme}
showLegend
legendPosition={Position.Top}
onBrushEnd={this.handleChartBrush}
tooltip={{
headerFormatter: disableHeaderFormat
? undefined
: ({ value }) =>
`${formatter.full_dates(value)}${
headerUnit ? ` ${headerUnit}` : ""
}`,
}}
debug={false}
/>
<Axis
id="{e}-bottom"
position={Position.Bottom}
showOverlappingTicks
labelFormat={this.state.timeRange.timeFormatter}
tickFormat={this.state.timeRange.timeFormatter}
/>
{axis.map((item) => {
return (
<Axis
key={e + "-" + item.id}
id={e + "-" + item.id}
showGridLines={item.showGridLines}
groupId={item.group}
title={formatMessage({
id:
"dashboard.charts.title." +
e +
".axis." +
item.title,
})}
position={item.position}
ticks={item.ticks}
labelFormat={getFormatter(
item.formatType,
item.labelFormat
)}
tickFormat={getFormatter(
item.formatType,
item.tickFormat
)}
/>
);
})}
{lines.map((item) => {
return (
<LineSeries
key={item.metric.label}
id={item.metric.label}
groupId={item.metric.group}
timeZone={timezone}
xScaleType={ScaleType.Time}
yScaleType={ScaleType.Linear}
xAccessor={0}
tickFormat={getFormatter(
item.metric.formatType,
item.metric.tickFormat,
item.metric.units
)}
yAccessors={[1]}
data={item.data}
curve={CurveType.CURVE_MONOTONE_X}
/>
);
})}
</Chart>
</div>
);
})}
</Tabs.TabPane>
<Tabs.TabPane
key="node"
tab={formatMessage({
id: "cluster.monitor.node.title",
})}
>
<NodeMetric
clusterID={this.props.selectedCluster.id}
timezone={timezone}
timeRange={this.state.timeRange}
handleTimeChange={this.handleTimeChange}
/>
</Tabs.TabPane>
<Tabs.TabPane
key="index"
tab={formatMessage({
id: "cluster.monitor.index.title",
})}
>
<IndexMetric
clusterID={this.props.selectedCluster.id}
timezone={timezone}
timeRange={this.state.timeRange}
handleTimeChange={this.handleTimeChange}
/>
</Tabs.TabPane>
</Tabs>
</div>
</div>
// </Spin>
); );
} }
} }

View File

@ -15,3 +15,27 @@
fill-opacity: 50%; fill-opacity: 50%;
padding-left: 5px; padding-left: 5px;
} }
.summary {
padding: 15px;
border-top: 1px solid rgb(232, 232, 232);
border-bottom: 1px solid rgb(232, 232, 232);
position: relative;
.mask {
position: absolute;
inset: 0;
background: rgba(96, 96, 96, 0.25);
display: flex;
align-items: center;
justify-content: center;
color: red;
font-size: 20px;
}
.metricMask {
filter: blur(4px);
-o-filter: blur(4px);
-ms-filter: blur(4px);
-moz-filter: blur(4px);
-webkit-filter: blur(4px);
}
}

View File

@ -18,6 +18,9 @@ import { formatter, getFormatter, getNumFormatter } from "../format";
import "./node_metric.scss"; import "./node_metric.scss";
import { calculateBounds } from "@/components/kibana/data/common/query/timefilter"; import { calculateBounds } from "@/components/kibana/data/common/query/timefilter";
import moment from "moment"; import moment from "moment";
import { formatMessage } from "umi/locale";
import MetricContainer from "./metric_container";
import _ from "lodash";
export default ({ clusterID, timezone, timeRange, handleTimeChange }) => { export default ({ clusterID, timezone, timeRange, handleTimeChange }) => {
const [filter, setFilter] = React.useState({ const [filter, setFilter] = React.useState({
@ -58,16 +61,21 @@ export default ({ clusterID, timezone, timeRange, handleTimeChange }) => {
); );
const metrics = React.useMemo(() => { const metrics = React.useMemo(() => {
return Object.values(value?.metrics || {}).sort( return _.groupBy(value?.metrics, "group");
(a, b) => a.order - b.order // return Object.values(value?.metrics || {}).sort(
); // (a, b) => a.order - b.order
// );
}, [value]); }, [value]);
const chartRefs = React.useRef(); const chartRefs = React.useRef();
React.useEffect(() => { React.useEffect(() => {
chartRefs.current = metrics.map(() => { let refs = [];
return React.createRef(); Object.values(metrics).map((m) => {
m.forEach(() => {
refs.push(React.createRef());
});
}); });
chartRefs.current = refs;
}, [metrics]); }, [metrics]);
const { value: indices } = useFetch( const { value: indices } = useFetch(
@ -99,9 +107,10 @@ export default ({ clusterID, timezone, timeRange, handleTimeChange }) => {
}); });
} }
}; };
let refIdx = 0;
return ( return (
<div> <div id="node-metric">
<div className="px"> <div className="px">
<div className="metric-control"> <div className="metric-control">
<div className="selector"> <div className="selector">
@ -117,7 +126,7 @@ export default ({ clusterID, timezone, timeRange, handleTimeChange }) => {
<Select <Select
style={{ width: 200 }} style={{ width: 200 }}
onChange={indexValueChange} onChange={indexValueChange}
placeholder="请选择索引" placeholder="Select index"
value={filter.index_name} value={filter.index_name}
showSearch={true} showSearch={true}
> >
@ -130,91 +139,110 @@ export default ({ clusterID, timezone, timeRange, handleTimeChange }) => {
</div> </div>
</div> </div>
<div className="px"> <div className="px">
<Skeleton active loading={loading} paragraph={{ rows: 20 }}> <Skeleton active loading={!value} paragraph={{ rows: 20 }}>
{Object.keys(metrics).map((e, i) => { {Object.keys(metrics).map((e, i) => {
let axis = metrics[e].axis;
let lines = metrics[e].lines;
let disableHeaderFormat = false;
let headerUnit = "";
return ( return (
<div key={e} className={styles.vizChartContainer}> <div style={{ margin: "8px 0" }}>
<Chart <MetricContainer
size={[, 200]} title={formatMessage({ id: `cluster.metrics.group.${e}` })}
className={styles.vizChartItem} collapsed={false}
ref={chartRefs.current[i]}
> >
<Settings <div className="metric-inner-cnt">
// theme={theme} {metrics[e].map((metric) => {
pointerUpdateDebounce={0} let axis = metric.axis;
pointerUpdateTrigger="x" let lines = metric.lines;
externalPointerEvents={{ let disableHeaderFormat = false;
tooltip: { visible: true }, let headerUnit = "";
}} return (
onPointerUpdate={pointerUpdate} <div key={metric.key} className="metric-item">
showLegend <Chart
legendPosition={Position.Top} size={[, 200]}
onBrushEnd={handleChartBrush} className={styles.vizChartItem}
tooltip={{ ref={chartRefs.current[refIdx++]}
headerFormatter: disableHeaderFormat >
? undefined <Settings
: ({ value }) => // theme={theme}
`${formatter.full_dates(value)}${ pointerUpdateDebounce={0}
headerUnit ? ` ${headerUnit}` : "" pointerUpdateTrigger="x"
}`, // externalPointerEvents={{
}} // tooltip: { visible: true },
debug={false} // }}
/> onPointerUpdate={pointerUpdate}
<Axis showLegend
id="{e}-bottom" legendPosition={Position.Top}
position={Position.Bottom} onBrushEnd={handleChartBrush}
showOverlappingTicks tooltip={{
labelFormat={timeRange.timeFormatter} headerFormatter: disableHeaderFormat
tickFormat={timeRange.timeFormatter} ? undefined
/> : ({ value }) =>
{axis.map((item) => { `${formatter.full_dates(value)}${
return ( headerUnit ? ` ${headerUnit}` : ""
<Axis }`,
key={e + "-" + item.id} }}
id={e + "-" + item.id} debug={false}
showGridLines={item.showGridLines} />
groupId={item.group} <Axis
title={item.title} id="{e}-bottom"
position={item.position} position={Position.Bottom}
ticks={item.ticks} showOverlappingTicks
labelFormat={getFormatter( labelFormat={timeRange.timeFormatter}
item.formatType, tickFormat={timeRange.timeFormatter}
item.labelFormat ticks={8}
)} />
tickFormat={getFormatter( {axis.map((item) => {
item.formatType, return (
item.tickFormat <Axis
)} key={e + "-" + item.id}
/> id={e + "-" + item.id}
); showGridLines={item.showGridLines}
})} groupId={item.group}
title={formatMessage({
id:
"cluster.metrics.index.axis." +
metric.key +
".title",
})}
position={item.position}
ticks={item.ticks}
labelFormat={getFormatter(
item.formatType,
item.labelFormat
)}
tickFormat={getFormatter(
item.formatType,
item.tickFormat
)}
/>
);
})}
{lines.map((item) => { {lines.map((item) => {
return ( return (
<LineSeries <LineSeries
key={item.metric.label} key={item.metric.label}
id={item.metric.label} id={item.metric.label}
groupId={item.metric.group} groupId={item.metric.group}
timeZone={timezone} timeZone={timezone}
xScaleType={ScaleType.Time} xScaleType={ScaleType.Time}
yScaleType={ScaleType.Linear} yScaleType={ScaleType.Linear}
xAccessor={0} xAccessor={0}
tickFormat={getFormatter( tickFormat={getFormatter(
item.metric.formatType, item.metric.formatType,
item.metric.tickFormat, item.metric.tickFormat,
item.metric.units item.metric.units
)} )}
yAccessors={[1]} yAccessors={[1]}
data={item.data} data={item.data}
curve={CurveType.CURVE_MONOTONE_X} curve={CurveType.CURVE_MONOTONE_X}
/> />
); );
})} })}
</Chart> </Chart>
</div>
);
})}
</div>
</MetricContainer>
</div> </div>
); );
})} })}

View File

@ -0,0 +1,31 @@
import React, { useState } from "react";
import "./metric_container.scss";
import { Icon } from "antd";
export default ({ children, title, collapsed = true }) => {
const [isCollapsed, setIsCollapsed] = useState(collapsed);
return (
<div data-metric-container className={isCollapsed ? "collapsed" : ""}>
<div className="header">
<div
className="collapse-icon"
onClick={() => {
setIsCollapsed(!isCollapsed);
}}
>
<Icon
style={{ fontSize: 12 }}
type={isCollapsed ? "right" : "down"}
/>
</div>
<div className="h-item title">{title}</div>
</div>
{!isCollapsed ? (
<div className="body">
<div className="wrapper">{children}</div>
</div>
) : null}
</div>
);
};

View File

@ -0,0 +1,29 @@
div[data-metric-container] {
border: 1px solid #d9d9d9;
box-shadow: rgba(0, 0, 0, 0.15) 0px 2px 8px;
&.collapsed {
border-bottom: none;
}
.header {
background-color: #fafafa;
display: flex;
border-bottom: 1px solid #d9d9d9;
align-items: center;
.h-item {
padding: 6px 10px;
}
.collapse-icon {
display: flex;
flex: none;
align-self: stretch;
align-items: center;
cursor: pointer;
padding-left: 10px;
}
}
.body {
padding: 6px 10px;
.wrapper {
}
}
}

View File

@ -13,11 +13,14 @@ import {
import useFetch from "@/lib/hooks/use_fetch"; import useFetch from "@/lib/hooks/use_fetch";
import { ESPrefix } from "@/services/common"; import { ESPrefix } from "@/services/common";
import styles from "../Metrics.less"; import styles from "../Metrics.less";
import { Spin, Radio, Select, Skeleton } from "antd"; import { Spin, Radio, Select, Skeleton, Row, Col } from "antd";
import { formatter, getFormatter, getNumFormatter } from "../format"; import { formatter, getFormatter, getNumFormatter } from "../format";
import "./node_metric.scss"; import "./node_metric.scss";
import { calculateBounds } from "@/components/kibana/data/common/query/timefilter"; import { calculateBounds } from "@/components/kibana/data/common/query/timefilter";
import moment from "moment"; import moment from "moment";
import { formatMessage } from "umi/locale";
import MetricContainer from "./metric_container";
import _ from "lodash";
export default ({ clusterID, timezone, timeRange, handleTimeChange }) => { export default ({ clusterID, timezone, timeRange, handleTimeChange }) => {
const [filter, setFilter] = React.useState({ const [filter, setFilter] = React.useState({
@ -58,23 +61,28 @@ export default ({ clusterID, timezone, timeRange, handleTimeChange }) => {
); );
const metrics = React.useMemo(() => { const metrics = React.useMemo(() => {
return Object.values(value?.metrics || {}).sort( return _.groupBy(value?.metrics, "group");
(a, b) => a.order - b.order // return Object.values(value?.metrics || {}).sort(
); // (a, b) => a.order - b.order
// );
}, [value]); }, [value]);
const chartRefs = React.useRef(); const chartRefs = React.useRef();
React.useEffect(() => { React.useEffect(() => {
chartRefs.current = metrics.map(() => { let refs = [];
return React.createRef(); Object.values(metrics).map((m) => {
m.forEach(() => {
refs.push(React.createRef());
});
}); });
chartRefs.current = refs;
}, [metrics]); }, [metrics]);
const { value: nodes } = useFetch(`${ESPrefix}/${clusterID}/nodes`, {}, [ const { value: nodes } = useFetch(`${ESPrefix}/${clusterID}/nodes`, {}, [
clusterID, clusterID,
]); ]);
const nodeNames = React.useMemo(() => { const nodeNames = React.useMemo(() => {
return Object.keys(nodes || {}).map((k) => nodes[k].name); return Object.keys(nodes || {}).map((k) => nodes[k].transport_address);
}, [nodes]); }, [nodes]);
const pointerUpdate = (event) => { const pointerUpdate = (event) => {
@ -98,8 +106,9 @@ export default ({ clusterID, timezone, timeRange, handleTimeChange }) => {
} }
}; };
let refIdx = 0;
return ( return (
<div> <div id="node-metric">
<div className="px"> <div className="px">
<div className="metric-control"> <div className="metric-control">
<div className="selector"> <div className="selector">
@ -115,7 +124,7 @@ export default ({ clusterID, timezone, timeRange, handleTimeChange }) => {
<Select <Select
style={{ width: 200 }} style={{ width: 200 }}
onChange={nodeValueChange} onChange={nodeValueChange}
placeholder="请选择节点" placeholder="Select node"
value={filter.node_name} value={filter.node_name}
showSearch={true} showSearch={true}
> >
@ -128,91 +137,110 @@ export default ({ clusterID, timezone, timeRange, handleTimeChange }) => {
</div> </div>
</div> </div>
<div className="px"> <div className="px">
<Skeleton active loading={loading} paragraph={{ rows: 20 }}> <Skeleton active loading={!value} paragraph={{ rows: 20 }}>
{Object.keys(metrics).map((e, i) => { {Object.keys(metrics).map((e, i) => {
let axis = metrics[e].axis;
let lines = metrics[e].lines;
let disableHeaderFormat = false;
let headerUnit = "";
return ( return (
<div key={e} className={styles.vizChartContainer}> <div style={{ margin: "8px 0" }}>
<Chart <MetricContainer
size={[, 200]} title={formatMessage({ id: `cluster.metrics.group.${e}` })}
className={styles.vizChartItem} collapsed={false}
ref={chartRefs.current[i]}
> >
<Settings <div className="metric-inner-cnt">
// theme={theme} {metrics[e].map((metric) => {
pointerUpdateDebounce={0} let axis = metric.axis;
pointerUpdateTrigger="x" let lines = metric.lines;
externalPointerEvents={{ let disableHeaderFormat = false;
tooltip: { visible: true }, let headerUnit = "";
}} return (
onPointerUpdate={pointerUpdate} <div key={metrics.key} className="metric-item">
showLegend <Chart
legendPosition={Position.Top} size={[, 200]}
onBrushEnd={handleChartBrush} className={styles.vizChartItem}
tooltip={{ ref={chartRefs.current[refIdx++]}
headerFormatter: disableHeaderFormat >
? undefined <Settings
: ({ value }) => // theme={theme}
`${formatter.full_dates(value)}${ pointerUpdateDebounce={0}
headerUnit ? ` ${headerUnit}` : "" pointerUpdateTrigger="x"
}`, // externalPointerEvents={{
}} // tooltip: { visible: true },
debug={false} // }}
/> onPointerUpdate={pointerUpdate}
<Axis showLegend
id="{e}-bottom" legendPosition={Position.Top}
position={Position.Bottom} onBrushEnd={handleChartBrush}
showOverlappingTicks tooltip={{
labelFormat={timeRange.timeFormatter} headerFormatter: disableHeaderFormat
tickFormat={timeRange.timeFormatter} ? undefined
/> : ({ value }) =>
{axis.map((item) => { `${formatter.full_dates(value)}${
return ( headerUnit ? ` ${headerUnit}` : ""
<Axis }`,
key={e + "-" + item.id} }}
id={e + "-" + item.id} debug={false}
showGridLines={item.showGridLines} />
groupId={item.group} <Axis
title={item.title} id="{e}-bottom"
position={item.position} position={Position.Bottom}
ticks={item.ticks} showOverlappingTicks
labelFormat={getFormatter( labelFormat={timeRange.timeFormatter}
item.formatType, tickFormat={timeRange.timeFormatter}
item.labelFormat ticks={8}
)} />
tickFormat={getFormatter( {axis.map((item) => {
item.formatType, return (
item.tickFormat <Axis
)} key={e + "-" + item.id}
/> id={e + "-" + item.id}
); showGridLines={item.showGridLines}
})} groupId={item.group}
title={formatMessage({
id:
"cluster.metrics.node.axis." +
metric.key +
".title",
})}
position={item.position}
ticks={item.ticks}
labelFormat={getFormatter(
item.formatType,
item.labelFormat
)}
tickFormat={getFormatter(
item.formatType,
item.tickFormat
)}
/>
);
})}
{lines.map((item) => { {lines.map((item) => {
return ( return (
<LineSeries <LineSeries
key={item.metric.label} key={item.metric.label}
id={item.metric.label} id={item.metric.label}
groupId={item.metric.group} groupId={item.metric.group}
timeZone={timezone} timeZone={timezone}
xScaleType={ScaleType.Time} xScaleType={ScaleType.Time}
yScaleType={ScaleType.Linear} yScaleType={ScaleType.Linear}
xAccessor={0} xAccessor={0}
tickFormat={getFormatter( tickFormat={getFormatter(
item.metric.formatType, item.metric.formatType,
item.metric.tickFormat, item.metric.tickFormat,
item.metric.units item.metric.units
)} )}
yAccessors={[1]} yAccessors={[1]}
data={item.data} data={item.data}
curve={CurveType.CURVE_MONOTONE_X} curve={CurveType.CURVE_MONOTONE_X}
/> />
); );
})} })}
</Chart> </Chart>
</div>
);
})}
</div>
</MetricContainer>
</div> </div>
); );
})} })}

View File

@ -1,5 +1,6 @@
.metric-control { .metric-control {
display: flex; display: flex;
margin-bottom: 15px;
.selector { .selector {
margin-left: auto; margin-left: auto;
display: flex; display: flex;
@ -11,3 +12,28 @@
.px { .px {
padding: 0 15px; padding: 0 15px;
} }
#node-metric,
#index-metric {
.metric-inner-cnt {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.metric-item {
flex: 0 0 calc(50% - 5px);
border: 1px solid #d9d9d9;
margin: 5px 0;
}
}
}
@media (max-width: 940px) {
#node-metric,
#index-metric {
.metric-inner-cnt {
.metric-item {
flex: 0 0 100%;
}
}
}
}

View File

@ -16,7 +16,13 @@ export const formatter = {
size = size.toFixed(1); size = size.toFixed(1);
return size + unitArr[index]; return size + unitArr[index];
}, },
dates: (day) => timeFormatter(niceTimeFormatByDay(day)), dates: (day) => {
let formatStr = niceTimeFormatByDay(day).replace(":ss", "");
if (day == 7) {
formatStr = formatStr.replace(":mm", "");
}
return timeFormatter(formatStr);
},
full_dates: (d) => DateTime.fromMillis(d).toFormat("yyyy-MM-dd HH:mm:ss"), full_dates: (d) => DateTime.fromMillis(d).toFormat("yyyy-MM-dd HH:mm:ss"),
utc_full_dates: (d) => utc_full_dates: (d) =>
DateTime.fromMillis(d) DateTime.fromMillis(d)

View File

@ -319,9 +319,12 @@ export const ConsoleUI = ({
setClusterID(tabState.activeKey?.split(":")[0]); setClusterID(tabState.activeKey?.split(":")[0]);
const panes = tabState.panes.filter((pane: any) => { const panes = tabState.panes.filter((pane: any) => {
pane.closable = true;
return typeof clusterMap[pane.cluster_id] != "undefined"; return typeof clusterMap[pane.cluster_id] != "undefined";
}); });
if (panes.length == 1) {
panes[0].closable = false;
}
const saveTitle = (key: string, title: string) => { const saveTitle = (key: string, title: string) => {
dispatch({ dispatch({
type: "saveTitle", type: "saveTitle",
@ -337,6 +340,18 @@ export const ConsoleUI = ({
setEditorHeight(refToElement.clientHeight); setEditorHeight(refToElement.clientHeight);
}; };
useEffect(() => {
const winResize = () => {
if (isFullscreen) {
setEditorHeight(rootRef.current.offsetHeight);
}
};
window.addEventListener("resize", winResize);
return () => {
window.removeEventListener("resize", winResize);
};
}, [isFullscreen]);
const disableWindowScroll = () => { const disableWindowScroll = () => {
document.body.style.overflow = "hidden"; document.body.style.overflow = "hidden";
}; };

View File

@ -1,5 +1,5 @@
@import '~antd/lib/style/themes/default.less'; @import "~antd/lib/style/themes/default.less";
@import '~@/utils/utils.less'; @import "~@/utils/utils.less";
.tableList { .tableList {
.tableListOperator { .tableListOperator {
@ -48,3 +48,30 @@
margin-right: 8px; margin-right: 8px;
} }
} }
.extraImg {
margin-top: -60px;
text-align: center;
width: 195px;
img {
width: 100%;
}
}
.pageHeaderContent {
position: relative;
}
.contentLink {
margin-top: 16px;
a {
margin-right: 32px;
img {
width: 24px;
}
}
img {
vertical-align: middle;
margin-right: 8px;
}
}

View File

@ -1,256 +1,353 @@
import React from 'react'; import React from "react";
import {Button, Card, Col, Divider, Form, Input, Row, Table, Switch, Icon, Popconfirm, message} from "antd"; import {
Button,
Card,
Col,
Divider,
Form,
Input,
Row,
Table,
Switch,
Icon,
Popconfirm,
message,
} from "antd";
import Link from "umi/link"; import Link from "umi/link";
import {connect} from "dva"; import { connect } from "dva";
import {HealthStatusCircle} from '@/components/infini/health_status_circle'; import { HealthStatusCircle } from "@/components/infini/health_status_circle";
import PageHeaderWrapper from '@/components/PageHeaderWrapper'; import PageHeaderWrapper from "@/components/PageHeaderWrapper";
import styles from './step.less'; import styles from "./step.less";
import clusterBg from '@/assets/cluster_bg.png'; import clusterBg from "@/assets/cluster_bg.png";
import { formatMessage } from "umi/locale";
const content = ( const content = (
<div className={styles.pageHeaderContent}> <div className={styles.pageHeaderContent}>
<p> <p>
集群管理通过注册新集群删除集群让您高效的管理多个 Elasticsearch 集群 {formatMessage({
id: "cluster.manage.description",
})}
</p> </p>
</div> </div>
); );
const extraContent = ( const extraContent = (
<div className={styles.extraImg}> <div className={styles.extraImg}>
<img <img src={clusterBg} />
alt="集群管理"
src={clusterBg}
/>
</div> </div>
); );
@Form.create() @Form.create()
@connect(({clusterConfig, global}) =>({ @connect(({ clusterConfig, global }) => ({
clusterConfig, clusterConfig,
clusterStatus: global.clusterStatus, clusterStatus: global.clusterStatus,
})) }))
class Index extends React.Component { class Index extends React.Component {
columns = [{ columns = [
title: '集群名称', {
dataIndex: 'name', title: formatMessage({
key: 'name', id: "cluster.manage.table.column.name",
},{ }),
title: '健康状态', dataIndex: "name",
dataIndex: 'id', key: "name",
key: 'health_status',
render: (val)=>{
const {clusterStatus} = this.props;
if(!clusterStatus || !clusterStatus[val]){
return
}
const isAvailable = clusterStatus[val].available;
if(!isAvailable){
return <Icon type="close-circle" style={{width:14, height:14, color:'red',borderRadius: 14, boxShadow: '0px 0px 5px #555'}}/>
}
const status = clusterStatus[val].health?.status;
return <HealthStatusCircle status={status}/>
}
},{
title: '所属业务',
dataIndex: 'business',
key: 'business',
render: ()=>{
return 'eu-de-1'
}
},
{
title: '所属部门',
dataIndex: 'business_department',
key: 'business_department',
render: ()=>{
return '部门X'
}
}, {
title: '部署环境',
dataIndex: 'deploy_env',
key: 'deploy_env',
render: ()=>{
return 'PROD'
}
},{
title: '程序版本',
dataIndex: 'version',
key: 'elasticsearch_version',
// render: (data)=>{
// return
// }
},{
title: '节点数',
dataIndex: 'id',
key: 'number_of_nodes',
render: (val)=>{
const {clusterStatus} = this.props;
if(!clusterStatus || !clusterStatus[val]){
return
}
return clusterStatus[val].health?.number_of_nodes;
}
},{
title: '集群地址',
dataIndex: 'host',
key: 'host',
},
{
title: '监控启用状态',
dataIndex: 'monitored',
key: 'monitored',
render: (val) => {
return val? '启用': '关闭';
}
}, },
// { {
// title: '是否需要身份验证', title: formatMessage({
// dataIndex: 'basic_auth', id: "cluster.manage.table.column.health",
// key: 'username', }),
// render: (val) => { dataIndex: "id",
// //console.log(val) key: "health_status",
// return (val && typeof val.username !=='undefined' && val.username !== '')? '是': '否'; render: (val) => {
// } const { clusterStatus } = this.props;
// }, if (!clusterStatus || !clusterStatus[val]) {
// { return;
// title: '描述', }
// dataIndex: 'description', const isAvailable = clusterStatus[val].available;
// key: 'description', if (!isAvailable) {
// },{ return (
// title: '是否启用', <Icon
// dataIndex: 'enabled', type="close-circle"
// key: 'enabled', style={{
// render: (val) =>{ width: 14,
// return val === true ? '是': '否'; height: 14,
// } color: "red",
// }, borderRadius: 14,
{ boxShadow: "0px 0px 5px #555",
title: '操作', }}
render: (text, record) => ( />
<div> );
<Link to='/system/cluster/edit' onClick={()=>{this.handleEditClick(record)}}>编辑</Link> }
<span><Divider type="vertical" /> const status = clusterStatus[val].health?.status;
<Popconfirm title="Sure to delete?" onConfirm={() => this.handleDeleteClick(record)}><a key="delete">删除</a> return <HealthStatusCircle status={status} />;
</Popconfirm> },
},
// {
// title: "所属业务",
// dataIndex: "business",
// key: "business",
// render: () => {
// return "eu-de-1";
// },
// },
// {
// title: "所属部门",
// dataIndex: "business_department",
// key: "business_department",
// render: () => {
// return "部门X";
// },
// },
// {
// title: "部署环境",
// dataIndex: "deploy_env",
// key: "deploy_env",
// render: () => {
// return "PROD";
// },
// },
{
title: formatMessage({
id: "cluster.manage.table.column.version",
}),
dataIndex: "version",
key: "elasticsearch_version",
// render: (data)=>{
// return
// }
},
{
title: formatMessage({
id: "cluster.manage.table.column.node_count",
}),
dataIndex: "id",
key: "number_of_nodes",
render: (val) => {
const { clusterStatus } = this.props;
if (!clusterStatus || !clusterStatus[val]) {
return;
}
return clusterStatus[val].health?.number_of_nodes;
},
},
{
title: formatMessage({
id: "cluster.manage.table.column.endpoint",
}),
dataIndex: "host",
key: "host",
},
{
title: formatMessage({
id: "cluster.manage.table.column.monitored",
}),
dataIndex: "monitored",
key: "monitored",
render: (val) => {
return formatMessage({
id: val
? "cluster.manage.monitored.on"
: "cluster.manage.monitored.off",
});
},
},
// {
// title: '是否需要身份验证',
// dataIndex: 'basic_auth',
// key: 'username',
// render: (val) => {
// //console.log(val)
// return (val && typeof val.username !=='undefined' && val.username !== '')? '是': '否';
// }
// },
// {
// title: '描述',
// dataIndex: 'description',
// key: 'description',
// },{
// title: '是否启用',
// dataIndex: 'enabled',
// key: 'enabled',
// render: (val) =>{
// return val === true ? '是': '否';
// }
// },
{
title: formatMessage({
id: "cluster.manage.table.column.operation",
}),
render: (text, record) => (
<div>
<Link
to="/system/cluster/edit"
onClick={() => {
this.handleEditClick(record);
}}
>
{formatMessage({
id: "form.button.edit",
})}
</Link>
<span>
<Divider type="vertical" />
<Popconfirm
title="Sure to delete?"
onConfirm={() => this.handleDeleteClick(record)}
>
<a key="delete">
{" "}
{formatMessage({
id: "form.button.delete",
})}
</a>
</Popconfirm>
</span> </span>
</div> </div>
), ),
}] },
];
fetchData = (params)=>{ fetchData = (params) => {
const {dispatch} = this.props; const { dispatch } = this.props;
dispatch({ dispatch({
type: 'clusterConfig/fetchClusterList', type: "clusterConfig/fetchClusterList",
payload: params, payload: params,
}) });
} };
componentDidMount() { componentDidMount() {
this.fetchData({}) this.fetchData({});
} }
handleSearchClick = ()=>{ handleSearchClick = () => {
const {form} = this.props; const { form } = this.props;
this.fetchData({ this.fetchData({
name: form.getFieldValue('name'), name: form.getFieldValue("name"),
}) });
} };
handleDeleteClick = (record)=>{ handleDeleteClick = (record) => {
const {dispatch} = this.props; const { dispatch } = this.props;
return dispatch({ return dispatch({
type:'clusterConfig/deleteCluster', type: "clusterConfig/deleteCluster",
payload: { payload: {
id: record.id id: record.id,
} },
}).then((result)=>{ }).then((result) => {
if(result){ if (result) {
message.success("删除成功"); message.success("删除成功");
} }
}); });
} };
saveData = (payload)=>{ saveData = (payload) => {
const {dispatch} = this.props; const { dispatch } = this.props;
return dispatch({ return dispatch({
type:'clusterConfig/saveData', type: "clusterConfig/saveData",
payload: { payload: {
...payload ...payload,
} },
}); });
} };
handleNewClick = () => { handleNewClick = () => {
this.saveData({ this.saveData({
editMode: 'NEW', editMode: "NEW",
editValue: {basic_auth: {}}, editValue: { basic_auth: {} },
}) });
} };
handleEditClick = (record)=>{ handleEditClick = (record) => {
this.saveData({ this.saveData({
editMode : 'UPDATE', editMode: "UPDATE",
editValue: record, editValue: record,
}) });
} };
handleEnabledChange = (enabled) => { handleEnabledChange = (enabled) => {
const {form} = this.props; const { form } = this.props;
this.fetchData({ this.fetchData({
name: form.getFieldValue('name'), name: form.getFieldValue("name"),
enabled: enabled, enabled: enabled,
}) });
} };
render() { render() {
const {getFieldDecorator} = this.props.form; const { getFieldDecorator } = this.props.form;
const formItemLayout = { const formItemLayout = {
labelCol: { span: 10 }, labelCol: { span: 10 },
wrapperCol: { span: 14 }, wrapperCol: { span: 14 },
style: {marginBottom: 0} style: { marginBottom: 0 },
}; };
const {data} = this.props.clusterConfig; const { data } = this.props.clusterConfig;
return ( return (
<PageHeaderWrapper title="集群管理" content={content} extraContent={extraContent}> <PageHeaderWrapper
title={formatMessage({ id: "cluster.manage.title" })}
content={content}
extraContent={extraContent}
>
<Card> <Card>
<div style={{display:'flex', marginBottom:10, flex:"1 1 auto", justifyContent: 'space-between',alignItems:'center',}}> <div
<div> style={{
<Form> display: "flex",
<Row gutter={{md:24, sm:16}}> marginBottom: 10,
<Col md={16} sm={20}> flex: "1 1 auto",
<Form.Item {...formItemLayout} label="集群名称"> justifyContent: "space-between",
{getFieldDecorator('name')(<Input placeholder="please input cluster name" />)} alignItems: "center",
</Form.Item> }}
</Col> >
<Col md={8} sm={16}> <div>
<div style={{paddingTop:4}}> <Form>
<Button type="primary" icon="search" onClick={this.handleSearchClick}> <Row gutter={{ md: 24, sm: 16 }}>
搜索 <Col md={16} sm={20}>
</Button> <Form.Item
</div> {...formItemLayout}
</Col> label={formatMessage({
</Row> id: "cluster.manage.label.cluster_name",
</Form> })}
</div> >
<div> {getFieldDecorator("name")(
{/* <span style={{marginRight:24}}><Switch <Input placeholder="please input cluster name" />
)}
</Form.Item>
</Col>
<Col md={8} sm={16}>
<div style={{ paddingTop: 4 }}>
<Button
type="primary"
icon="search"
onClick={this.handleSearchClick}
>
{formatMessage({ id: "form.button.search" })}
</Button>
</div>
</Col>
</Row>
</Form>
</div>
<div>
{/* <span style={{marginRight:24}}><Switch
checkedChildren={<Icon type="check" />} checkedChildren={<Icon type="check" />}
unCheckedChildren={<Icon type="close" />} unCheckedChildren={<Icon type="close" />}
onChange={this.handleEnabledChange} onChange={this.handleEnabledChange}
defaultChecked defaultChecked
/></span> */} /></span> */}
<Link to='/system/cluster/regist' onClick={this.handleNewClick}> <Button type="primary" icon="plus">注册集群</Button></Link> <Link to="/system/cluster/regist" onClick={this.handleNewClick}>
</div> {" "}
<Button type="primary" icon="plus">
{formatMessage({
id: "cluster.manage.btn.regist",
})}
</Button>
</Link>
</div> </div>
<Table </div>
bordered <Table
columns={this.columns} bordered
dataSource={data} columns={this.columns}
rowKey='id' dataSource={data}
/> rowKey="id"
/>
</Card> </Card>
</PageHeaderWrapper> </PageHeaderWrapper>
); );
} }
} }
export default Index; export default Index;

View File

@ -1,83 +1,86 @@
import { Steps, Button, message, Spin, Card } from 'antd'; import { Steps, Button, message, Spin, Card } from "antd";
import {connect} from "dva"; import { connect } from "dva";
import { useState, useRef } from 'react'; import { useState, useRef } from "react";
import {InitialStep, ExtraStep, ResultStep} from './steps'; import { InitialStep, ExtraStep, ResultStep } from "./steps";
import PageHeaderWrapper from '@/components/PageHeaderWrapper'; import PageHeaderWrapper from "@/components/PageHeaderWrapper";
import styles from './step.less'; import styles from "./step.less";
import clusterBg from '@/assets/cluster_bg.png'; import clusterBg from "@/assets/cluster_bg.png";
import { formatMessage } from "umi/locale";
const { Step } = Steps; const { Step } = Steps;
const steps = [ const steps = [
{ {
title: '连接', title: formatMessage({
id: "cluster.regist.step.connect.title",
}),
}, },
{ {
title: '确认', title: formatMessage({
id: "cluster.regist.step.confirm.title",
}),
}, },
{ {
title: '完成', title: formatMessage({
id: "cluster.regist.step.complete.title",
}),
}, },
]; ];
const ClusterStep = ({ const ClusterStep = ({ current, changeStep, dispatch, history }) => {
current,
changeStep,
dispatch,
history,
}) => {
const formRef = useRef(); const formRef = useRef();
const [clusterConfig, setClusterConfig] = useState({}) const [clusterConfig, setClusterConfig] = useState({});
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
// const [clusterInfo, setClusterInfo] = useState({}); // const [clusterInfo, setClusterInfo] = useState({});
const handleConnect = async ()=>{ const handleConnect = async () => {
const result = await formRef.current.validateFields((errors, values) => { const result = await formRef.current
if(errors){ .validateFields((errors, values) => {
if (errors) {
return false;
}
return values;
})
.catch((err) => {
return false; return false;
} });
return values;
}).catch((err)=>{ if (!result) {
return false; return false;
});
if(!result){
return false
} }
setIsLoading(true) setIsLoading(true);
const res = await dispatch({ const res = await dispatch({
type: 'clusterConfig/doTryConnect', type: "clusterConfig/doTryConnect",
payload: { payload: {
basic_auth:{ basic_auth: {
username: result.username, username: result.username,
password: result.password, password: result.password,
}, },
host: result.host, host: result.host,
schema: result.isTLS === true ? 'https': 'http', schema: result.isTLS === true ? "https" : "http",
}, },
}); });
if(res && !res.error){ if (res && !res.error) {
setClusterConfig({ setClusterConfig({
...result, ...result,
...res, ...res,
}); });
return true; return true;
}else{ } else {
setIsLoading(false) setIsLoading(false);
return false; return false;
} }
} };
const handleCommit = async ()=>{ const handleCommit = async () => {
const result = await formRef.current.validateFields((errors, values) => { const result = await formRef.current.validateFields((errors, values) => {
if(errors){ if (errors) {
return false; return false;
} }
// console.log(values); // console.log(values);
return values return values;
}); });
if(!result){ if (!result) {
return fasle; return fasle;
} }
const newVals = { const newVals = {
@ -85,71 +88,76 @@ const ClusterStep = ({
version: clusterConfig.version, version: clusterConfig.version,
host: clusterConfig.host, host: clusterConfig.host,
basic_auth: { basic_auth: {
username: clusterConfig.username || '', username: clusterConfig.username || "",
password: clusterConfig.password || '', password: clusterConfig.password || "",
}, },
description: result.description, description: result.description,
enabled: true, enabled: true,
monitored: result.monitored, monitored: result.monitored,
schema: clusterConfig.isTLS ? 'https': 'http' schema: clusterConfig.isTLS ? "https" : "http",
} };
setIsLoading(true); setIsLoading(true);
const res = await dispatch({ const res = await dispatch({
type: 'clusterConfig/addCluster', type: "clusterConfig/addCluster",
payload: newVals, payload: newVals,
}); });
if(res && !res.error){ if (res && !res.error) {
return true; return true;
}else{ } else {
setIsLoading(false) setIsLoading(false);
return false; return false;
} }
} };
const next = async () => { const next = async () => {
let result let result;
if(current === 0){ if (current === 0) {
result = await handleConnect(); result = await handleConnect();
}else if(current === 1){ } else if (current === 1) {
result = await handleCommit(); result = await handleCommit();
} }
if(!result){ if (!result) {
return return;
} }
setIsLoading(false) setIsLoading(false);
changeStep(current + 1) changeStep(current + 1);
}; };
const prev = () => { const prev = () => {
changeStep(current - 1) changeStep(current - 1);
}; };
const oneMoreClick = ()=>{ const oneMoreClick = () => {
setClusterConfig({}); setClusterConfig({});
changeStep(0); changeStep(0);
} };
const goToClusterList = ()=>{ const goToClusterList = () => {
history.push('/system/cluster'); history.push("/system/cluster");
} };
const renderContent = (current)=>{ const renderContent = (current) => {
if(current===0){ if (current === 0) {
return <InitialStep ref={formRef} initialValue={clusterConfig} /> return <InitialStep ref={formRef} initialValue={clusterConfig} />;
}else if(current === 1){ } else if (current === 1) {
return <ExtraStep initialValue={clusterConfig} ref={formRef}/> return <ExtraStep initialValue={clusterConfig} ref={formRef} />;
}else if(current === 2){ } else if (current === 2) {
return <ResultStep clusterConfig={clusterConfig} oneMoreClick={oneMoreClick} return (
goToClusterList={goToClusterList} <ResultStep
/> clusterConfig={clusterConfig}
oneMoreClick={oneMoreClick}
goToClusterList={goToClusterList}
/>
);
} }
} };
const content = ( const content = (
<div className={styles.pageHeaderContent}> <div className={styles.pageHeaderContent}>
<p> <p>
输入集群地址和身份验证信息分步创建集群 {formatMessage({
id: "cluster.regist.description",
})}
</p> </p>
{/* <div className={styles.contentLink}> {/* <div className={styles.contentLink}>
<a> <a>
@ -170,55 +178,63 @@ const ClusterStep = ({
const extraContent = ( const extraContent = (
<div className={styles.extraImg}> <div className={styles.extraImg}>
<img <img src={clusterBg} />
alt="集群管理"
src={clusterBg}
/>
</div> </div>
); );
return ( return (
<PageHeaderWrapper title="集群注册" content={content} extraContent={extraContent}> <PageHeaderWrapper
title={formatMessage({
id: "cluster.regist.title",
})}
content={content}
extraContent={extraContent}
>
<Card> <Card>
<Spin spinning={isLoading}> <Spin spinning={isLoading}>
<div style={{maxWidth:720, margin:'0 auto'}}> <div style={{ maxWidth: 720, margin: "0 auto" }}>
<Steps current={current} style={{marginBottom:24}}> <Steps current={current} style={{ marginBottom: 24 }}>
{steps.map(item => ( {steps.map((item) => (
<Step key={item.title} title={item.title} /> <Step key={item.title} title={item.title} />
))} ))}
</Steps> </Steps>
<div className="steps-content">{renderContent(current)}</div> <div className="steps-content">{renderContent(current)}</div>
<div className="steps-action" style={{textAlign:'center'}}> <div className="steps-action" style={{ textAlign: "center" }}>
{current === 1 && ( {current === 1 && (
<Button style={{ margin: '0 8px' }} onClick={() => prev()}> <Button style={{ margin: "0 8px" }} onClick={() => prev()}>
上一步 {formatMessage({
</Button> id: "form.button.pre",
)} })}
{current < steps.length - 1 && ( </Button>
<Button type="primary" onClick={() => next()}> )}
下一步 {current < steps.length - 1 && (
</Button> <Button type="primary" onClick={() => next()}>
)} {formatMessage({
id: "form.button.next",
})}
</Button>
)}
</div>
</div> </div>
</div> </Spin>
</Spin>
</Card> </Card>
</PageHeaderWrapper> </PageHeaderWrapper>
); );
}; };
const NewCluster = (props)=>{ const NewCluster = (props) => {
const {dispatch, history} = props; const { dispatch, history } = props;
const [current, setCurrent] = useState(0); const [current, setCurrent] = useState(0);
return <ClusterStep current={current} changeStep={setCurrent} return (
history={history} <ClusterStep
dispatch={dispatch} /> current={current}
} changeStep={setCurrent}
history={history}
dispatch={dispatch}
/>
);
};
export default connect(({ export default connect(({ clusterConfig }) => ({
clusterConfig clusterConfig,
})=>({ }))(NewCluster);
clusterConfig
}))(NewCluster)

View File

@ -1,12 +1,23 @@
import {Form, Input, Switch, Icon, InputNumber, Divider, Descriptions} from 'antd'; import {
import {HealthStatusCircle} from '@/components/infini/health_status_circle'; Form,
Input,
Switch,
Icon,
InputNumber,
Divider,
Descriptions,
} from "antd";
import { HealthStatusCircle } from "@/components/infini/health_status_circle";
import { formatMessage } from "umi/locale";
@Form.create() @Form.create()
export class ExtraStep extends React.Component { export class ExtraStep extends React.Component {
state = { state = {};
} render() {
render(){ const {
const {form:{getFieldDecorator}, initialValue} = this.props; form: { getFieldDecorator },
initialValue,
} = this.props;
const formItemLayout = { const formItemLayout = {
labelCol: { labelCol: {
xs: { span: 24 }, xs: { span: 24 },
@ -20,43 +31,81 @@ export class ExtraStep extends React.Component {
return ( return (
<> <>
<Descriptions column={2} size="small" bordered> <Descriptions column={2} size="small" bordered>
<Descriptions.Item label="集群地址" > <Descriptions.Item
{initialValue?.host} label={formatMessage({
id: "cluster.manage.table.column.endpoint",
})}
>
{initialValue?.host}
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="TLS" > <Descriptions.Item label="TLS">
{initialValue?.isTLS ? <Icon type="lock" style={{color: '#52c41a'}}/> : null} {initialValue?.isTLS ? (
<Icon type="lock" style={{ color: "#52c41a" }} />
) : null}
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="集群版本" > <Descriptions.Item
{initialValue?.version} label={formatMessage({
id: "cluster.manage.table.column.version",
})}
>
{initialValue?.version}
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="身份验证" > <Descriptions.Item
{initialValue?.username ? <Icon type="user"/>: null} label={formatMessage({
id: "cluster.regist.step.connect.label.auth",
})}
>
{initialValue?.username ? <Icon type="user" /> : null}
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="健康状态" > <Descriptions.Item
<HealthStatusCircle status={initialValue?.status}/> label={formatMessage({
id: "cluster.manage.table.column.health",
})}
>
<HealthStatusCircle status={initialValue?.status} />
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="节点总数" > <Descriptions.Item
label={formatMessage({
id: "cluster.manage.table.column.node_count",
})}
>
{initialValue?.number_of_nodes} {initialValue?.number_of_nodes}
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="数据节点数" > <Descriptions.Item
label={formatMessage({
id: "cluster.regist.step.connect.label.data_nodes",
})}
>
{initialValue?.number_of_data_nodes} {initialValue?.number_of_data_nodes}
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label="分片总数" > <Descriptions.Item
label={formatMessage({
id: "cluster.regist.step.connect.label.shards",
})}
>
{initialValue?.active_shards} {initialValue?.active_shards}
</Descriptions.Item> </Descriptions.Item>
</Descriptions> </Descriptions>
<Divider/> <Divider />
<Form {...formItemLayout} style={{marginTop:15}} form={this.props.formRef}> <Form
<Form.Item label="集群名称" > {...formItemLayout}
{getFieldDecorator('name', { style={{ marginTop: 15 }}
initialValue: initialValue?.cluster_name || '', form={this.props.formRef}
>
<Form.Item
label={formatMessage({
id: "cluster.manage.table.column.name",
})}
>
{getFieldDecorator("name", {
initialValue: initialValue?.cluster_name || "",
rules: [ rules: [
{ {
required: true, required: true,
message: 'Please input cluster name!', message: "Please input cluster name!",
}, },
], ],
})(<Input autoComplete='off' placeholder="cluster-name" />)} })(<Input autoComplete="off" placeholder="cluster-name" />)}
</Form.Item> </Form.Item>
{/* <Form.Item label="Elasticsearch "> {/* <Form.Item label="Elasticsearch ">
{getFieldDecorator('version', { {getFieldDecorator('version', {
@ -68,10 +117,14 @@ export class ExtraStep extends React.Component {
initialValue: 0, initialValue: 0,
})(<InputNumber />)} })(<InputNumber />)}
</Form.Item> */} </Form.Item> */}
<Form.Item label="描述"> <Form.Item
{getFieldDecorator('description', { label={formatMessage({
initialValue: '', id: "cluster.manage.table.column.description",
})(<Input.TextArea placeholder="集群应用描述" />)} })}
>
{getFieldDecorator("description", {
initialValue: "",
})(<Input.TextArea placeholder="cluster description" />)}
</Form.Item> </Form.Item>
{/* <Form.Item label=""> {/* <Form.Item label="">
{getFieldDecorator('enabled', { {getFieldDecorator('enabled', {
@ -82,17 +135,23 @@ export class ExtraStep extends React.Component {
unCheckedChildren={<Icon type="close" />} unCheckedChildren={<Icon type="close" />}
/>)} />)}
</Form.Item> */} </Form.Item> */}
<Form.Item label="启用监控"> <Form.Item
{getFieldDecorator('monitored', { label={formatMessage({
valuePropName: 'checked', id: "cluster.manage.table.column.monitored",
})}
>
{getFieldDecorator("monitored", {
valuePropName: "checked",
initialValue: true, initialValue: true,
})(<Switch })(
checkedChildren={<Icon type="check" />} <Switch
unCheckedChildren={<Icon type="close" />} checkedChildren={<Icon type="check" />}
/>)} unCheckedChildren={<Icon type="close" />}
/>
)}
</Form.Item> </Form.Item>
</Form> </Form>
</> </>
) );
} }
} }

View File

@ -1,20 +1,24 @@
import {Form, Input, Switch, Icon} from 'antd'; import { Form, Input, Switch, Icon } from "antd";
import { formatMessage } from "umi/locale";
@Form.create() @Form.create()
export class InitialStep extends React.Component { export class InitialStep extends React.Component {
constructor(props){ constructor(props) {
super(props); super(props);
this.state = { this.state = {
needAuth: props.initialValue?.username !== undefined, needAuth: props.initialValue?.username !== undefined,
} };
} }
handleAuthChange = (val) => { handleAuthChange = (val) => {
this.setState({ this.setState({
needAuth: val, needAuth: val,
}) });
} };
render(){ render() {
const {form:{getFieldDecorator}, initialValue} = this.props; const {
form: { getFieldDecorator },
initialValue,
} = this.props;
const formItemLayout = { const formItemLayout = {
labelCol: { labelCol: {
xs: { span: 24 }, xs: { span: 24 },
@ -27,32 +31,41 @@ export class InitialStep extends React.Component {
}; };
return ( return (
<Form {...formItemLayout} form={this.props.formRef}> <Form {...formItemLayout} form={this.props.formRef}>
<Form.Item label="集群地址"> <Form.Item
{getFieldDecorator('host', { label={formatMessage({
initialValue: initialValue?.host || '', id: "cluster.manage.table.column.endpoint",
})}
>
{getFieldDecorator("host", {
initialValue: initialValue?.host || "",
rules: [ rules: [
{ {
type: 'string', type: "string",
pattern: /^[\w\.]+\:\d+$/, //(https?:\/\/)? pattern: /^[\w\.]+\:\d+$/, //(https?:\/\/)?
message: '请输入域名或 IP 地址和端口号', message: "请输入域名或 IP 地址和端口号",
}, },
{ {
required: true, required: true,
message: '请输入集群地址!', message: "请输入集群地址!",
}, },
], ],
})(<Input placeholder="127.0.0.1:9200" />)} })(<Input placeholder="127.0.0.1:9200" />)}
</Form.Item> </Form.Item>
<Form.Item label="TLS"> <Form.Item label="TLS">
{getFieldDecorator('isTLS', { {getFieldDecorator("isTLS", {
initialValue: initialValue?.isTLS || false, initialValue: initialValue?.isTLS || false,
})( })(
<Switch <Switch
checkedChildren={<Icon type="check" />} checkedChildren={<Icon type="check" />}
unCheckedChildren={<Icon type="close" />} unCheckedChildren={<Icon type="close" />}
/>)} />
)}
</Form.Item> </Form.Item>
<Form.Item label="身份验证"> <Form.Item
label={formatMessage({
id: "cluster.regist.step.connect.label.auth",
})}
>
<Switch <Switch
defaultChecked={this.state.needAuth} defaultChecked={this.state.needAuth}
onChange={this.handleAuthChange} onChange={this.handleAuthChange}
@ -60,31 +73,47 @@ export class InitialStep extends React.Component {
unCheckedChildren={<Icon type="close" />} unCheckedChildren={<Icon type="close" />}
/> />
</Form.Item> </Form.Item>
{this.state.needAuth === true ? (<div> {this.state.needAuth === true ? (
<Form.Item label="用户名"> <div>
{getFieldDecorator('username', { <Form.Item
initialValue: initialValue?.username || '', label={formatMessage({
rules: [ id: "cluster.regist.step.connect.label.username",
{ })}
required: true, >
message: 'Please input auth username!', {getFieldDecorator("username", {
}, initialValue: initialValue?.username || "",
], rules: [
})(<Input autoComplete='off' placeholder="auth user name" />)} {
</Form.Item> required: true,
<Form.Item label="密码" hasFeedback> message: "Please input auth username!",
{getFieldDecorator('password', { },
initialValue: initialValue?.password || '', ],
rules: [ })(<Input autoComplete="off" placeholder="auth user name" />)}
{ </Form.Item>
required: true, <Form.Item
message: 'Please input auth password!', label={formatMessage({
}, id: "cluster.regist.step.connect.label.password",
], })}
})(<Input.Password autoComplete='off' placeholder="auth user password"/>)} hasFeedback
</Form.Item> >
</div>):null} {getFieldDecorator("password", {
initialValue: initialValue?.password || "",
rules: [
{
required: true,
message: "Please input auth password!",
},
],
})(
<Input.Password
autoComplete="off"
placeholder="auth user password"
/>
)}
</Form.Item>
</div>
) : null}
</Form> </Form>
) );
} }
} }

View File

@ -1,15 +1,19 @@
import Result from '@/components/Result'; import Result from "@/components/Result";
import React, { Fragment } from 'react'; import React, { Fragment } from "react";
import { Button, Row, Col } from 'antd'; import { Button, Row, Col } from "antd";
import styles from './styles.less'; import styles from "./styles.less";
import { formatMessage } from "umi/locale";
export const ResultStep = (props)=>{ export const ResultStep = (props) => {
const {clusterConfig, oneMoreClick, goToClusterList} = props; const { clusterConfig, oneMoreClick, goToClusterList } = props;
const information = ( const information = (
<div className={styles.information}> <div className={styles.information}>
<Row> <Row>
<Col xs={24} sm={8} className={styles.label}> <Col xs={24} sm={8} className={styles.label}>
集群名称 {formatMessage({
id: "cluster.manage.table.column.name",
})}
</Col> </Col>
<Col xs={24} sm={16}> <Col xs={24} sm={16}>
{clusterConfig?.cluster_name} {clusterConfig?.cluster_name}
@ -17,18 +21,24 @@ export const ResultStep = (props)=>{
</Row> </Row>
<Row> <Row>
<Col xs={24} sm={8} className={styles.label}> <Col xs={24} sm={8} className={styles.label}>
集群版本 {formatMessage({
id: "cluster.manage.table.column.version",
})}
</Col> </Col>
<Col xs={24} sm={16}> <Col xs={24} sm={16}>
{clusterConfig?.version} {clusterConfig?.version}
</Col> </Col>
</Row> </Row>
<Row> <Row>
<Col xs={24} sm={8} className={styles.label}> <Col xs={24} sm={8} className={styles.label}>
集群地址 {formatMessage({
id: "cluster.manage.table.column.endpoint",
})}
</Col> </Col>
<Col xs={24} sm={16}> <Col xs={24} sm={16}>
{clusterConfig?.host} {clusterConfig?.host}
</Col> </Col>
</Row> </Row>
<Row> <Row>
@ -36,7 +46,11 @@ export const ResultStep = (props)=>{
TLS TLS
</Col> </Col>
<Col xs={24} sm={16}> <Col xs={24} sm={16}>
{clusterConfig?.isTLS ? '是': '否'} {formatMessage({
id: clusterConfig?.isTLS
? "cluster.regist.step.complete.tls.yes"
: "cluster.regist.step.complete.tls.no",
})}
</Col> </Col>
</Row> </Row>
</div> </div>
@ -44,20 +58,28 @@ export const ResultStep = (props)=>{
const actions = ( const actions = (
<Fragment> <Fragment>
<Button type="primary" onClick={oneMoreClick}> <Button type="primary" onClick={oneMoreClick}>
再创建一个集群 {formatMessage({
id: "cluster.regist.step.complete.btn.create",
})}
</Button>
<Button onClick={goToClusterList}>
{formatMessage({
id: "cluster.regist.step.complete.btn.goto",
})}
</Button> </Button>
<Button onClick={goToClusterList}>查看集群列表</Button>
</Fragment> </Fragment>
); );
return ( return (
<Result <Result
type="success" type="success"
title="创建成功" title={formatMessage({
id: "cluster.regist.step.complete.success",
})}
description="" description=""
extra={information} extra={information}
actions={actions} actions={actions}
className={styles.result} className={styles.result}
/> />
); );
} };

View File

@ -24,6 +24,7 @@ import {
// import { loader } from "@monaco-editor/react"; // import { loader } from "@monaco-editor/react";
import Editor from "@monaco-editor/react"; import Editor from "@monaco-editor/react";
import { EuiCodeBlock } from "@elastic/eui"; import { EuiCodeBlock } from "@elastic/eui";
import clusterBg from "@/assets/cluster_bg.png";
// loader.config({ // loader.config({
// paths: { // paths: {
// vs: "monaco-editor/min/vs", // vs: "monaco-editor/min/vs",
@ -34,11 +35,28 @@ import styles from "../../List/TableList.less";
import { transformSettingsForApi } from "@/lib/elasticsearch/edit_settings"; import { transformSettingsForApi } from "@/lib/elasticsearch/edit_settings";
import PageHeaderWrapper from "@/components/PageHeaderWrapper"; import PageHeaderWrapper from "@/components/PageHeaderWrapper";
import { TagGenerator } from "@/components/kibana/console/components/CommonCommandModal"; import { TagGenerator } from "@/components/kibana/console/components/CommonCommandModal";
import { formatMessage } from "umi/locale";
import { deleteCommand } from "@/components/kibana/console/modules/mappings/mappings";
const FormItem = Form.Item; const FormItem = Form.Item;
const { TextArea } = Input; const { TextArea } = Input;
const { TabPane } = Tabs; const { TabPane } = Tabs;
const content = (
<div className={styles.pageHeaderContent}>
<p>
常用命令可以帮助您保存常用的请求并且在开发工具里面通过 LOAD
命令快速地加载
</p>
</div>
);
const extraContent = (
<div className={styles.extraImg}>
<img src={clusterBg} />
</div>
);
/* eslint react/no-multi-comp:0 */ /* eslint react/no-multi-comp:0 */
@connect(({ command }) => ({ @connect(({ command }) => ({
command, command,
@ -125,6 +143,7 @@ class Index extends PureComponent {
}, },
}).then((res) => { }).then((res) => {
if (!res.error) { if (!res.error) {
deleteCommand(id);
message.success("删除成功!"); message.success("删除成功!");
} }
}); });
@ -235,7 +254,11 @@ class Index extends PureComponent {
} = this.props; } = this.props;
return ( return (
<PageHeaderWrapper> <PageHeaderWrapper
title="常用命令管理"
content={content}
extraContent={extraContent}
>
<Card bordered={false}> <Card bordered={false}>
<div className={styles.tableList}> <div className={styles.tableList}>
<div className={styles.tableListForm}> <div className={styles.tableListForm}>
@ -313,7 +336,7 @@ class Index extends PureComponent {
<div>标签</div> <div>标签</div>
<div> <div>
<TagGenerator <TagGenerator
value={editingCommand.tag} value={editingCommand.tag || []}
onChange={this.onEditTagChange} onChange={this.onEditTagChange}
/> />
{/* <Input style={{ width: 250 }} /> */} {/* <Input style={{ width: 250 }} /> */}