CN-1479 fix: 搜索组件showHint提示文本修改

This commit is contained in:
刘洪洪
2023-12-13 17:05:16 +08:00
parent 3d1fbfa5fd
commit f5f857bcb4
14 changed files with 471 additions and 579 deletions

View File

@@ -375,12 +375,16 @@ span.CodeMirror-selectedtext { background: none; }
} }
.hint-title { .hint-title {
margin: 10px 10px 10px 4px; margin: 10px 10px 10px 0;
line-height: 20px; height: 24px;
font-weight: bold; line-height: 24px;
/* 禁止选中 样式 */ /* 禁止选中 样式 */
background: #fff !important; background: #fff !important;
color: #000 !important; font-family: NotoSansHans-Medium;
font-size: 14px;
color: #333333 !important;
letter-spacing: 0;
font-weight: 500;
} }
.cm-s-eclipse span.cm-string-2 { .cm-s-eclipse span.cm-string-2 {
@@ -433,3 +437,55 @@ span.CodeMirror-selectedtext { background: none; }
.cm-variable-2{ .cm-variable-2{
font-weight: bold; font-weight: bold;
} }
.default-tips-header,.default-tips-title {
height: 24px;
line-height: 24px;
font-weight: 700;
color: #333333;
font-size: 14px;
margin: 6px 0;
font-family: NotoSansSC-Bold;
letter-spacing: 0;
}
.default-tips-header {
font-size: 15px;
}
.show-hint-tips__p {
word-break: keep-all;
margin: 0;
line-height: 24px;
color: #575757;
font-weight: 400;
}
.Hint {
padding: 0;
z-index: 2;
.hint__block {
display: flex;
flex-direction: row;
width: calc(100% - 41px);
min-height: 320px;
margin-top: 6px;
box-shadow: 0 2px 8px 0 rgba(0,0,0,.3);
z-index: 2;
.hint__block-filter {
width: 326px;
background: #fff;
border-right: 1px solid #DEDEDE;
padding: 12px;
z-index: 2;
}
.hint__block-helper {
width: calc(100% - 326px);
background: #fff;
z-index: 2;
}
}
}

View File

@@ -43,7 +43,7 @@
align-content: center; align-content: center;
padding: 16px 0; padding: 16px 0;
margin-bottom: 1px; margin-bottom: 1px;
background-color: white; //background-color: white;
border-radius: 0 4px 4px 0; border-radius: 0 4px 4px 0;
.cn-entity__icon { .cn-entity__icon {

View File

@@ -15,6 +15,7 @@ import filterTips from '@/components/advancedSearch/showhint/const/filterTips.js
import varTips from '@/components/advancedSearch/showhint/const/varTips.js' import varTips from '@/components/advancedSearch/showhint/const/varTips.js'
import { fieldRender } from '@/components/advancedSearch/showhint/const/fieldTips.js' import { fieldRender } from '@/components/advancedSearch/showhint/const/fieldTips.js'
import { EN, storageKey, ZH } from '@/utils/constants'
export default { export default {
name: 'HelperInfo', name: 'HelperInfo',
@@ -104,8 +105,12 @@ export default {
return fieldRender return fieldRender
} }
} }
const language = localStorage.getItem(storageKey.language) || EN
return defaultTips.default.description if (language === ZH) {
return defaultTips.zhDefault.description
}
return defaultTips.enDefault.description
} }
} }
} }
@@ -122,7 +127,7 @@ export default {
} }
.tips-container { .tips-container {
padding: 6px; padding: 12px;
} }
/deep/ ul li { /deep/ ul li {
@@ -143,9 +148,10 @@ export default {
/deep/ code, /deep/ code,
.code { .code {
background: initial; background: initial;
border: 1px solid #DEDEDE;
border: 1px solid #ccc; height: 24px;
padding: 4px 12px; line-height: 24px;
padding: 0 12px;
margin: 6px 0; margin: 6px 0;
display: block; display: block;
} }

View File

@@ -1,19 +1,11 @@
<!-- 提示信息 --> <!-- 提示信息 -->
<template> <template>
<div class="Hint" style="padding: 0;z-index: 2;" @click.stop> <div class="Hint" @click.stop>
<!-- <el-row style="padding: 0;display: flex;flex-direction: row">--> <div class="hint__block">
<!-- <el-col style="width: 300px;min-height: 302px;z-index: 2;">--> <div class="hint__block-filter">
<!-- <hint-info v-on="$listeners" :hintList="hintList"></hint-info>-->
<!-- </el-col>-->
<!-- <el-col style="width: calc(100% - 300px);min-height: 302px">-->
<!-- <helper-info :hintSearch="hintSearch"></helper-info>-->
<!-- </el-col>-->
<!-- </el-row>-->
<div style="display: flex;flex-direction: row;width: calc(100% - 41px);box-shadow: 0 2px 12px 0 rgba(0,0,0,.2);margin-top: 6px;">
<div style="width: 324px;min-height: 302px;z-index: 2;border: 1px solid #DEDEDE;">
<hint-info v-on="$listeners" :hintList="hintList" @select="onSelect"></hint-info> <hint-info v-on="$listeners" :hintList="hintList" @select="onSelect"></hint-info>
</div> </div>
<div style="width: calc(100% - 324px);min-height: 302px;z-index:2"> <div class="hint__block-helper">
<helper-info :hintSearch="hintSearch"></helper-info> <helper-info :hintSearch="hintSearch"></helper-info>
</div> </div>
</div> </div>
@@ -41,7 +33,3 @@ export default {
} }
} }
</script> </script>
<style lang="" scoped>
</style>

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="HintInfo"> <div class="HintInfo">
<ul class="CodeMirror-hints-manual eclipse" style="padding-left: 0"> <ul style="padding-left: 0;margin: -10px 0 0 0;">
<template v-for="(item,index) in hintList" :key="index"> <template v-for="(item,index) in hintList" :key="index">
<li :ref="'hint_'+index" class="relative-item CodeMirror-hint" <li :ref="'hint_'+index" class="relative-item CodeMirror-hint"
@click="handleSelect(item,index,hintList)" @click="handleSelect(item,index,hintList)"
@@ -115,8 +115,9 @@ export default {
} }
.hint-title{ .hint-title{
margin: 10px !important; margin: 10px !important;
margin-left: 4px !important; margin-left: 0 !important;
font-size: 14px; font-size: 14px;
line-height: 24px;
} }
.el-dropdown-menu__item{ .el-dropdown-menu__item{
text-indent: 1em; text-indent: 1em;

View File

@@ -1,56 +1,51 @@
export default { export default {
enDefault: {
default: {
description () { description () {
const code = `SELECT aggregate_function(field) [as field] … (5)
FROM [db.]table|$log_type(1)
WHERE $filter [and <expression-list> ](2)
GROUP BY <field-list>(3)
[HAVING <expression-list>](4)
[ORDER BY <sort-field> [ASC|DESC]](6)
[LIMIT [n, ]m ](7)`
return (<div className='default-tips'> return (<div className='default-tips'>
<h2>How To Search</h2> <div class='default-tips-header'>How To Search</div>
<p> You can write a query to retieve logs from an log type, use group by aggregation keywords to calculate <p class='show-hint-tips__p'> You can write queries to retrieve entities, including their basic information, activity levels, network performance, threat events, relationships with other entities, and so on. A query has three basic parts: fields, operators, and values.</p>
metrics
and generate statistical results , search for specific conditions within a rolling time window, predict future
trends, and so on. </p>
<h3> 1. Filter Mode</h3>
<p> A query in SQL ( also known as a "Where clause") has three basic parts: fields, operators, and values. Where
clause can be combined with AND , OR and NOT keywords. </p>
<code>[Field + operator + value] keyword [operator(Field)]</code> <code>[Field + operator + value] keyword [operator(Field)]</code>
<p class='show-hint-tips__p'>Field - Fields are different types of traffic attributes in the system. Fields include ip, domain, app, and so on.</p>
<p class='show-hint-tips__p'>Operator - Operators are the foundation of the query. They relate the field to the value and build a query condition. Common operators include =, IN, Like, and so on.</p>
<p class='show-hint-tips__p'>Value - Values are the actual data in the query.</p>
<p class='show-hint-tips__p'>Use the percent(%) wildcard substitutes for one or more characters in a string. Such as: </p>
<code>domain like '%google.com'</code>
<p class='show-hint-tips__p'>Strings containing spaces must be enclosed in single quotes ('). Such as:</p>
<code>ip=192.168.10.53</code>
<code>ip.country='United States'</code>
<p class='show-hint-tips__p'>Keyword - Keywords are specific words in the SQL. You can specify the AND and OR to create more complex query conditions. Currently only support AND.</p>
<p class='show-hint-tips__p'>There are two input modes, which can be switched by clicking the button on the right side of the input box.</p>
<ul> <div class='default-tips-title'> 1. Text Mode</div>
<li>Field - Fields are different types of traffic attributes int the system. Fields include server_ip, <p class='show-hint-tips__p'>In text mode, you will write your query with the help of input suggestions.</p>
server_port, ssl_sni , and so on.
</li> <div class='default-tips-title'> 2. Tag Mode </div>
<li>Operator - Operators are the foundation of the query. They relate the field to the value and build a query <p class='show-hint-tips__p'>In tag mode, you will be guided through preset steps to write a query.</p>
condition. Common operators include equals(=), IN, Like, etc. </div>)
</li> }
<li> },
<span>Value - Values are the actual data in the query.</span> zhDefault: {
<ul class="sub-url"> description () {
<li>Use the percent (%) wildcard substitutes for one or more characters in a string. Such as ssl_sni like return (<div className='default-tips'>
'%google.com' . <div class='default-tips-header'>如何搜索</div>
</li> <p class='show-hint-tips__p'>您可以编写查询来检索实体。查询具有三个基本部分:字段、运算符和值。</p>
<li>Use underscore (_) wildcard substitutes for exactly one character in a string. Such as <code>[字段 + 运算符 + 值] 关键字 [运算符(字段)]</code>
client_ip like '192.168.10.1_'. <p class='show-hint-tips__p'>字段 - 字段是系统中不同类型的属性。字段包括 ip、domain、app 等。</p>
</li> <p class='show-hint-tips__p'>运算符 - 运算符是查询的基础。他们将字段与值相关联并构建查询条件。常见的运算符包括 =、IN、Like 等。</p>
<li>String requires single quotes (') around text values. Such as client_ip='192.168.10.53'.</li> <p class='show-hint-tips__p'>值 - 值是查询中的实际数据。</p>
</ul> <p class='show-hint-tips__p'>使用百分号(%)通配符替换字符串中的一个或多个字符。例如:</p>
</li> <code>domain like '%google.com'</code>
<li>Keyword - Keywords are specific words in the SQL. You can specify the AND and OR in the WHERE clause to <p class='show-hint-tips__p'>包含空格的字符串必须用单引号(')括住例如</p>
create more complex query conditions. <code>ip=192.168.10.53</code>
</li> <code>ip.country='United States'</code>
</ul> <p class='show-hint-tips__p'>关键字 - 关键字是 SQL 中的特定单词您可以指定 AND OR 来创建更复杂的查询条件暂时只支持AND</p>
<h3> 2. Statistics Mode </h3> <p class='show-hint-tips__p'>有两种输入模式通过点击输入框右侧的按钮进行切换</p>
<p>More advanced searches use the SQL keywords WHERE, GROUP BY to build aggregated query and return aggregated
results.</p> <div class='default-tips-title'> 1. 文本模式</div>
<i class='ref-txt'>All clauses are optional , except for the required list of expressions after SELECT, WHERE and GROUP BY .</i> <p class='show-hint-tips__p'>文本模式中您将在输入建议的帮助下编写查询语句</p>
<pre class="code">
{code} <div class='default-tips-title'> 2. 标签模式 </div>
</pre> <p class='show-hint-tips__p'>标签模式中您将在引导下按预设好的步骤编写查询</p>
</div>) </div>)
} }
} }

View File

@@ -1,19 +1,20 @@
export function fieldRender(h, {fieldInfo = {}, funcReference = [], operatorReference = [], operates = [], funs = []}) { import i18n from '@/i18n'
export function fieldRender (h, { fieldInfo = {}, funcReference = [], operatorReference = [], operates = [], funs = [] }) {
return (<div className='field-tips'> return (<div className='field-tips'>
<h2>{fieldInfo.label}</h2> <div class='default-tips-header'>{fieldInfo.label}</div>
<p> Name: {fieldInfo.name}</p> <p class='show-hint-tips__p'> {i18n.global.t('overall.name')}: {fieldInfo.name}</p>
<p> Type:{fieldInfo.type} </p> <p class='show-hint-tips__p'> {i18n.global.t('overall.type')}: {typeof fieldInfo.type === 'object' ? fieldInfo.type.type : fieldInfo.type} </p>
<p> Operator: {operates.join(',')} </p> <p class='show-hint-tips__p'> {i18n.global.t('overall.operators')}: {operates.join(',')} </p>
<p> Function: {funs.join(',')} </p> {/* <p> Function: {funs.join(',')} </p> */}
<p> {fieldInfo.options && ( <p> {fieldInfo.options && (
'Options: ' + fieldInfo.options.map(item => { 'Options: ' + fieldInfo.options.map(item => {
return `${item.displayText}(${item.text})` return `${item.displayText}(${item.text})`
}).join(',') }).join(',')
)} </p> )} </p>
<h3>Enable Operators</h3> <div class='default-tips-header'>{i18n.global.t('overall.enableOperators')}</div>
{/* 提示超过一屏幕 明显不合理 --- 换成简单形式 */} {/* 提示超过一屏幕 明显不合理 --- 换成简单形式 */}
<ul style="padding-left: 20px;"> <ul style="padding-left: 0;margin: 12px 0;">
{operatorReference.map(item => { {operatorReference.map(item => {
return <li> return <li>
<span>{item.name}</span> <span>{item.name}</span>
@@ -21,16 +22,5 @@ export function fieldRender(h, {fieldInfo = {}, funcReference = [], operatorRefe
</li> </li>
})} })}
</ul> </ul>
<h3>Enable Functions</h3>
<ul style="padding-left: 20px;">
{funcReference.map(item => {
return <li>
<span>{item.name}</span>
<code> {item.function} </code>
</li>
})}
</ul>
</div>) </div>)
} }

View File

@@ -1,110 +1,109 @@
export const helpInfo=[ import i18n from '@/i18n'
import { EN, storageKey, ZH } from '@/utils/constants'
export const helpInfo = [
{ {
operator: "AND", operator: 'AND',
describe: `Search logs that contain all the search fields. You can use parentheses "()" to control the order in which clauses are executed. `, zhDescribe: '搜索包含所有搜索字段的实体。',
enDescribe: 'Search entities that contain all the search fields. ',
example: [ example: [
"Client IP = '192.168.10.53' AND Server IP = '8.8.8.8'", "ip = '192.168.10.53' AND domain = 'google.com'",
"Client IP = '192.168.10.53' AND SSL.SNI='google.com'", "domain = 'google.com' AND app = 'google'"
] ]
}, }
// { // {
// operator: "OR", // // operator: '= , !=',
// describe: `Search logs that contain any of the search fields. You can use parentheses "()" to control the order in which clauses are executed. `, // operator: ' = ',
// describe: 'Search logs that do EQUALS or NOT EQUALS the search value. ',
// example: [ // example: [
// "Client IP = '192.168.10.53' OR Server IP = '8.8.8.8'", // "Client IP = '192.168.10.53' "
// "Client IP = '192.168.10.53' OR Client IP = '192.168.10.54'", // // 'Server Port != 443'
// ] // ]
// }, // },
{ // {
operator: "= , !=", // operator: '> , < , >= , <=',
describe: `Search logs that do EQUALS or NOT EQUALS the search value. `, // describe: 'Search logs greater than and equal or less than and equal a value , or whtin a range. This operator cant be used with string fields. ',
example: [ // example: [
"Client IP != '192.168.10.53' ", // 'Bytes Sent >= 751',
"Server Port != 443", // 'Bytes Sent >= 751 and Bytes Sent <= 1024'
] // ]
}, // },
{ // {
operator: "> , < , >= , <=", // operator: ' LIKE ',
describe: `Search logs greater than and equal or less than and equal a value , or whtin a range. This operator cant be used with string fields. `, // // operator: 'LIKE , NOT LIKE',
example: [ // describe: 'You can use wildcard searches for value that contain or not contain search fields. Using percent (%) wildcard substitutes for one or more characters in a string. Using underscore (_) wildcard substitutes for exactly one character in a string. ',
"Bytes Sent >= 751", // example: [
"Bytes Sent >= 751 and Bytes Sent <= 1024", // "SSL.SNI LIKE '%google.com' ",
] // "Client IP LIKE '192.168.10.1_'"
}, // // "SSL.SNI NOT LIKE '%google.com'",
{ // // "Client IP NOT LIKE '192.168%'"
operator: "LIKE , NOT LIKE", // ]
describe: `You can use wildcard searches for value that contain or not contain search fields. Using percent (%) wildcard substitutes for one or more characters in a string. Using underscore (_) wildcard substitutes for exactly one character in a string. `, // },
example: [ // {
"SSL.SNI LIKE '%google.com' ", // operator: ' IN ',
"Client IP LIKE '192.168.10.1_'", // // operator: 'IN , NOT IN',
"SSL.SNI NOT LIKE '%google.com'", // describe: 'Specify or exclude multiple values for search fields. IN IN condition you can use when you need to use multiple OR condition. ',
"Client IP NOT LIKE '192.168%'", // example: [
] // "l7 Protocol IN ('HTTP', 'HTTPS')"
}, // // 'Server Port NOT IN (443,80)'
{ // ]
operator: "IN , NOT IN", // },
describe: `Specify or exclude multiple values for search fields. IN/NOT IN condition you can use when you need to use multiple OR condition. `, // {
example: [ // operator: 'EMPTY , NOT EMPTY',
"l7 Protocol IN ('HTTP', 'HTTPS')", // describe: 'Specify or exclude empty value for search fields. A string or array is considered non-empty if it contains at least one byte, even if this is a space or a null byte. ',
"Server Port NOT IN (443,80)" // example: [
] // 'NOT EMPTY(SSL.SNI)',
}, // 'EMPTY(Application Label)'
{ // ]
operator: "EMPTY , NOT EMPTY", // },
describe: `Specify or exclude empty value for search fields. A string or array is considered non-empty if it contains at least one byte, even if this is a space or a null byte. `, // {
example: [ // operator: 'HAS',
"NOT EMPTY(SSL.SNI)", // describe: 'Search logs that has element value for array type. Example:',
"EMPTY(Application Label)" // example: [
] // 'HAS(FQDN Category, music)'
}, // ]
{ // }
operator: "HAS", // {
describe: `Search logs that has element value for array type. Example:`, // operator: 'bitAnd',
example: [ // describe: 'A bitwise And(&) is a binary operation that compares each bit of the first operand to the corresponding bit of the second operand. Both expressions must have integral types. Examples:',
"HAS(FQDN Category, music)" // example: [
] // 'bitAnd(Flags, Asymmetric|Download) = Asymmetric|Download',
}, // 'bitAnd(Flags, Asymmetric|Download) >0'
{ // ]
operator: "bitAnd", // }
describe: `A bitwise And(&) is a binary operation that compares each bit of the first operand to the corresponding bit of the second operand. Both expressions must have integral types. Examples:`,
example: [
"bitAnd(Flags, Asymmetric|Download) = Asymmetric|Download",
"bitAnd(Flags, Asymmetric|Download) >0"
]
},
] ]
var renderData=[ const renderData = [
helpInfo[0], helpInfo[0]
helpInfo[1], ]
]; export const filterList = renderData
export const filterList=renderData function main () {
function main(){ const sqlTips = {}
var sqlTips={} const language = localStorage.getItem(storageKey.language) || EN
renderData.forEach((item,index)=>{ renderData.forEach((item, index) => {
var data=item // 这是个闭包 const data = item // 这是个闭包
sqlTips[item.operator]={ sqlTips[item.operator] = {
name: item.operator, name: item.operator,
// syntax: item.syntax, // syntax: item.syntax,
type: "filter", type: 'filter',
description() { description () {
return (<div className='filter-tips'> return (<div className='filter-tips'>
<h2>{data.operator}</h2> <div class='default-tips-header'>{data.operator}</div>
<h3> Description: </h3> <div class='default-tips-title'> {i18n.global.t('overall.remark')}: </div>
<p> {data.describe}</p> <p class='show-hint-tips__p'> {language === ZH ? data.zhDescribe : data.enDescribe}</p>
<h3>Examples:</h3> <div class='default-tips-title'>{i18n.global.t('overall.examples')}:</div>
<ul> <ul style="padding-left: 0;">
{item.example.map(v => { {item.example.map(v => {
return <li> return <li>
<span>{v}</span> <code>{v}</code>
</li> </li>
})} })}
</ul> </ul>
</div>) </div>)
} }
}; }
}) })
return sqlTips return sqlTips
} }
var filterTips=main(); const filterTips = main()
export default filterTips export default filterTips

View File

@@ -1,20 +1,20 @@
var renderData = [ var renderData = [
{ {
name: "COUNT", name: 'COUNT',
syntax: "count(expr)", syntax: 'count(expr)',
description: "Aggregate function is used to count the number of rows", description: 'Aggregate function is used to count the number of rows',
example: [ example: [
{ {
purpose: "Total count of all logs :", purpose: 'Total count of all logs :',
code: "count(*)" code: 'count(*)'
}, },
{ {
purpose: "Counts the occurrences of a Client IP :", purpose: 'Counts the occurrences of a Client IP :',
code: "count(client_ip)" code: 'count(client_ip)'
}, }
], ],
details() { details () {
//支持jsx 嵌套写法,万一测试要关键字加重呢 // 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div> return <div>
You can use COUNT function by count(*), count(1) or count(field). But there are something difference: You can use COUNT function by count(*), count(1) or count(field). But there are something difference:
<ul> <ul>
@@ -25,110 +25,113 @@ var renderData = [
} }
}, },
{ {
name: "COUNT_DISTINCT", name: 'COUNT_DISTINCT',
syntax: "count(distinct expr)", syntax: 'count(distinct expr)',
description: "Aggregate function is used to count only distinct(unique) rows in the specified field", description: 'Aggregate function is used to count only distinct(unique) rows in the specified field',
example: [ example: [
{ {
purpose: "Counts the number of different Client IP :", purpose: 'Counts the number of different Client IP :',
code: "count(distinct client_ip)" code: 'count(distinct client_ip)'
}, },
{ {
purpose: `Counts the number of different "Server IP" and "Server port" :`, purpose: `Counts the number of different "Server IP" and "Server port" :`,
code: "count(distinct server_ip, server_port)" code: 'count(distinct server_ip, server_port)'
}, }
], ],
details() { details () {
//支持jsx 嵌套写法,万一测试要关键字加重呢 // 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div>The COUNT DISTINCT function returns the number of unique values in the field or multiple fields. return <div>The COUNT DISTINCT function returns the number of unique values in the field or multiple fields.
System will uses an adaptive sampling algorithm to perform fast count distinct operations.</div> System will uses an adaptive sampling algorithm to perform fast count distinct operations.</div>
} }
}, },
{ {
name: "AVG", name: 'AVG',
syntax: "avg(expr)", syntax: 'avg(expr)',
description: "Aggregate function is used to calculate the arithmetic mean in the specified field. EXPR must be Integer,Float or Decimal and returned value as Float.", description: 'Aggregate function is used to calculate the arithmetic mean in the specified field. EXPR must be Integer,Float or Decimal and returned value as Float.',
example: [ example: [
{ {
purpose: `Calculates the average(mean) "Byte sent (sent_bytes)" field:`, purpose: `Calculates the average(mean) "Byte sent (sent_bytes)" field:`,
code: "avg(sent_bytes)" code: 'avg(sent_bytes)'
}, },
{ {
purpose: `Calculates the average(mean) "Bytes" , rounded to 2 decimal points:`, purpose: `Calculates the average(mean) "Bytes" , rounded to 2 decimal points:`,
code: "round(avg(sent_bytes+received_bytes),2)" code: 'round(avg(sent_bytes+received_bytes),2)'
}, }
], ],
details() { details () {
//支持jsx 嵌套写法,万一测试要关键字加重呢 // 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div>You can use ROUND(expr[,decimal_places]) or FLOOR(expr[,decimal_places]) function that rounds or floors a value to a specified number of decimal places.</div> return <div>You can use ROUND(expr[,decimal_places]) or FLOOR(expr[,decimal_places]) function that rounds or
floors a value to a specified number of decimal places.</div>
} }
}, },
{ {
name: "SUM", name: 'SUM',
syntax: "sum(expr)", syntax: 'sum(expr)',
description: "Aggregate function is used to sum of the values of the specified field. EXPR must be Integer,Float or Decimal.", description: 'Aggregate function is used to sum of the values of the specified field. EXPR must be Integer,Float or Decimal.',
example: [ example: [
{ {
purpose: `The sum of the "Byte sent (sent_bytes)" field:`, purpose: `The sum of the "Byte sent (sent_bytes)" field:`,
code: "sum(sent_bytes)" code: 'sum(sent_bytes)'
}, },
{ {
purpose: `The sum of the "sent_bytes" and "received_bytes" fields , and rename as "Bytes ":`, purpose: `The sum of the "sent_bytes" and "received_bytes" fields , and rename as "Bytes ":`,
code: "sum(sent_bytes+received_bytes) as Bytes" code: 'sum(sent_bytes+received_bytes) as Bytes'
}, }
], ],
details() { details () {
//支持jsx 嵌套写法,万一测试要关键字加重呢 // 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div>You can rename the field using the AS keyword.</div> return <div>You can rename the field using the AS keyword.</div>
} }
}, },
{ {
name: "MAX", name: 'MAX',
syntax: "max(expr)", syntax: 'max(expr)',
description: "Aggregate function is used to return the maximum value of the specified field.", description: 'Aggregate function is used to return the maximum value of the specified field.',
example: [ example: [
{ {
purpose: `Returns the maximum value of the "Byte sent (sent_bytes)" field:`, purpose: `Returns the maximum value of the "Byte sent (sent_bytes)" field:`,
code: "max(sent_bytes)" code: 'max(sent_bytes)'
} }
], ],
details() { details () {
//支持jsx 嵌套写法,万一测试要关键字加重呢 // 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div>The <b>MAX</b> aggregate function can also be used with the DateTime data type, where it will sort the DateTime values and return the last value from the sorted logs.</div> return <div>The <b>MAX</b> aggregate function can also be used with the DateTime data type, where it will sort the
DateTime values and return the last value from the sorted logs.</div>
} }
}, },
{ {
name: "MIN", name: 'MIN',
syntax: "min(expr)", syntax: 'min(expr)',
description: "Aggregate function is used to return the minimum value of the specified field.", description: 'Aggregate function is used to return the minimum value of the specified field.',
example: [ example: [
{ {
purpose: `Returns the minimum value of the "Byte sent (sent_bytes)" field:`, purpose: `Returns the minimum value of the "Byte sent (sent_bytes)" field:`,
code: "min(sent_bytes)" code: 'min(sent_bytes)'
} }
], ],
details() { details () {
//支持jsx 嵌套写法,万一测试要关键字加重呢 // 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div>The MIN aggregate function can also be used with the DateTime data type, where it will sort the DateTime values and return the minimum value from the sorted logs.</div> return <div>The MIN aggregate function can also be used with the DateTime data type, where it will sort the
DateTime values and return the minimum value from the sorted logs.</div>
} }
}, },
{ {
name: "TIME_FLOOR_WITH_FILL", name: 'TIME_FLOOR_WITH_FILL',
syntax: "TIME_FLOOR_WITH_FILL(<timestamp_expr>, <period>[,<fill>])", syntax: 'TIME_FLOOR_WITH_FILL(<timestamp_expr>, <period>[,<fill>])',
description: "Rounds down a timestamp, returning it as a new timestamp,optionally from some reference fill, and fills time gaps and impute missing values.", description: 'Rounds down a timestamp, returning it as a new timestamp,optionally from some reference fill, and fills time gaps and impute missing values.',
example: [ example: [
{ {
purpose: `Round the recv_time down to a 5 minutes increment and fill time gaps and impute zero value.`, purpose: `Round the recv_time down to a 5 minutes increment and fill time gaps and impute zero value.`,
code: "TIME_FLOOR_WITH_FILL(recv_time,'PT5M','zero')" code: 'TIME_FLOOR_WITH_FILL(recv_time,\'PT5M\',\'zero\')'
} }
], ],
details() { details () {
//支持jsx 嵌套写法,万一测试要关键字加重呢 // 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div> return <div>
<p>The TIME_FLOOR_WITH_FILL function as Timeseries granularity is used for time-based grouping.</p> <p>The TIME_FLOOR_WITH_FILL function as Timeseries granularity is used for time-based grouping.</p>
<ul> <ul>
<li> timestamp_expr - Unix Timestamp field</li> <li> timestamp_expr - Unix Timestamp field</li>
<li>period - can be any ISO8601 period, like P3M (quarters) or PT12H (half-days) </li> <li>period - can be any ISO8601 period, like P3M (quarters) or PT12H (half-days)</li>
<li> <li>
<span>fill - optionnal. Includes none, null, zero, previous, next value.</span> <span>fill - optionnal. Includes none, null, zero, previous, next value.</span>
<ul class="sub-url"> <ul class="sub-url">
@@ -144,62 +147,66 @@ var renderData = [
} }
}, },
{ {
name: "UNIX_TIMESTAMP", name: 'UNIX_TIMESTAMP',
syntax: `UNIX_TIMESTAMP(date)`, syntax: `UNIX_TIMESTAMP(date)`,
description: `Returns a Unix timestamp the value of the argument as seconds since '1970-01-01 00:00:00' UTC.`, description: `Returns a Unix timestamp the value of the argument as seconds since '1970-01-01 00:00:00' UTC.`,
example: [ example: [
{ {
purpose: `Specify a datetime string "2019-06-06 19:11:12", calculate the Unix timestamp:`, purpose: `Specify a datetime string "2019-06-06 19:11:12", calculate the Unix timestamp:`,
code: "UNIX_TIMESTAMP('2019-06-06 19:11:12')" code: 'UNIX_TIMESTAMP(\'2019-06-06 19:11:12\')'
}, },
{ {
purpose: `Specify a ISO8601 datetime string with time zone information "2019-10-12T14:20:50+08:00", calculate the Unix timestamp:`, purpose: `Specify a ISO8601 datetime string with time zone information "2019-10-12T14:20:50+08:00", calculate the Unix timestamp:`,
code: "UNIX_TIMESTAMP('2019-10-12T14:20:50+08:00')" code: 'UNIX_TIMESTAMP(\'2019-10-12T14:20:50+08:00\')'
}, },
{ {
purpose: `Specify a ISO8601 datetime string with UTC+0 time zone information "2019-10-12T14:20:50Z", calculate the Unix timestamp:`, purpose: `Specify a ISO8601 datetime string with UTC+0 time zone information "2019-10-12T14:20:50Z", calculate the Unix timestamp:`,
code: "UNIX_TIMESTAMP('2019-10-12T14:20:50Z')" code: 'UNIX_TIMESTAMP(\'2019-10-12T14:20:50Z\')'
}, },
], ],
details() { details () {
//支持jsx 嵌套写法,万一测试要关键字加重呢 // 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div> return <div>
<p>The date argument may be a DATE, DATETIME or TIMESTAMP string, or a number in YYMMDD, YYMMDDhhmmss, YYYYMMDD, or YYYYMMDDhhmmss format.</p> <p>The date argument may be a DATE, DATETIME or TIMESTAMP string, or a number in YYMMDD, YYMMDDhhmmss, YYYYMMDD,
or YYYYMMDDhhmmss format.</p>
<ul> <ul>
<li> Standard datetime string(UTC+0) : UNIX_TIMESTAMP('2019-06-06 19:11:12')</li> <li> Standard datetime string(UTC+0) : UNIX_TIMESTAMP('2019-06-06 19:11:12')</li>
<li>ISO8601 datetime stringUNIX_TIMESTAMP('2019-10-12T14:20:50Z') or UNIX_TIMESTAMP('2019-10-12T14:20:50+08:00')</li> <li>ISO8601 datetime stringUNIX_TIMESTAMP('2019-10-12T14:20:50Z') or
<li>Date: UNIX_TIMESTAMP(DATE('2019-06-06 19:11:12')) </li> UNIX_TIMESTAMP('2019-10-12T14:20:50+08:00')
</li>
<li>Date: UNIX_TIMESTAMP(DATE('2019-06-06 19:11:12'))</li>
</ul> </ul>
</div> </div>
} }
}, },
{ {
name: "FROM_UNIXTIME", name: 'FROM_UNIXTIME',
syntax: `FROM_UNIXTIME(unix_timestamp)`, syntax: `FROM_UNIXTIME(unix_timestamp)`,
description: `Returns a representation of unix_timestamp as a datetime or character string value. The value returned is expressed using the UTC+0 time zone.`, description: `Returns a representation of unix_timestamp as a datetime or character string value. The value returned is expressed using the UTC+0 time zone.`,
example: [ example: [
{ {
purpose: `Specify a Unix Timestamp "1570881546", calculate the datetime string:`, purpose: `Specify a Unix Timestamp "1570881546", calculate the datetime string:`,
code: "FROM_UNIXTIME(1570881546)" code: 'FROM_UNIXTIME(1570881546)'
}, },
], ],
details() { details () {
//支持jsx 嵌套写法,万一测试要关键字加重呢 // 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div>The unix_timestamp is an internal timestamp value representing seconds since '1970-01-01 00:00:00' UTC.</div> return <div>The unix_timestamp is an internal timestamp value representing seconds since '1970-01-01 00:00:00'
UTC.</div>
} }
}, },
{ {
name: "DATE_FORMAT", name: 'DATE_FORMAT',
syntax: "DATE_FORMAT(date, format)", syntax: 'DATE_FORMAT(date, format)',
description: `Formats the date value according to the format string.`, description: `Formats the date value according to the format string.`,
example: [ example: [
{ {
purpose: `Specify a Unix Timestamp "1570881546", calculate the datetime string with format "%Y-%m-%d %H:%i:%s":`, purpose: `Specify a Unix Timestamp "1570881546", calculate the datetime string with format "%Y-%m-%d %H:%i:%s":`,
code: "DATE_FORMAT(FROM_UNIXTIME(1570881546), '%Y-%m-%d %H:%i:%s')" code: 'DATE_FORMAT(FROM_UNIXTIME(1570881546), \'%Y-%m-%d %H:%i:%s\')'
} }
], ],
details() { details () {
//支持jsx 嵌套写法,万一测试要关键字加重呢 // 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div> return <div>
<p>The DATE_FORMAT function accepts two parameters as given below :</p> <p>The DATE_FORMAT function accepts two parameters as given below :</p>
<ul> <ul>
@@ -225,25 +232,25 @@ var renderData = [
} }
}, },
{ {
name: "CONVERT_TZ", name: 'CONVERT_TZ',
syntax:`CONVERT_TZ(dt, from_tz, to_tz)`, syntax: `CONVERT_TZ(dt, from_tz, to_tz)`,
description: `Converts a datetime value dt from the time zone given by from_tz to the time zone given by to_tz and returns the resulting value.`, description: `Converts a datetime value dt from the time zone given by from_tz to the time zone given by to_tz and returns the resulting value.`,
example: [ example: [
{ {
purpose: `Specify a datetime string "2021-11-11 00:00:00", converted from GMT(Greenwich Mean Time) to Asia/Shanghai time zone:`, purpose: `Specify a datetime string "2021-11-11 00:00:00", converted from GMT(Greenwich Mean Time) to Asia/Shanghai time zone:`,
code: "CONVERT_TZ('2021-11-11 00:00:00','GMT','Asia/Shanghai')" code: 'CONVERT_TZ(\'2021-11-11 00:00:00\',\'GMT\',\'Asia/Shanghai\')'
}, },
{ {
purpose: `Specify a Unix timestamp "1636588800", converted from GMT(Greenwich Mean Time) to Asia/Shanghai time zone:`, purpose: `Specify a Unix timestamp "1636588800", converted from GMT(Greenwich Mean Time) to Asia/Shanghai time zone:`,
code: "CONVERT_TZ(FROM_UNIXTIME(1636588800),'GMT','Asia/Shanghai')" code: 'CONVERT_TZ(FROM_UNIXTIME(1636588800),\'GMT\',\'Asia/Shanghai\')'
}, },
{ {
purpose: `Specify a Unix timestamp "1636588800", converted from Europe/London to America/New_York time zone:`, purpose: `Specify a Unix timestamp "1636588800", converted from Europe/London to America/New_York time zone:`,
code: "CONVERT_TZ(DATE_FORMAT(FROM_UNIXTIME(1636588800), '%Y-%m-%d %H:%i:%s'),'Europe/London','America/New_York')" code: 'CONVERT_TZ(DATE_FORMAT(FROM_UNIXTIME(1636588800), \'%Y-%m-%d %H:%i:%s\'),\'Europe/London\',\'America/New_York\')'
}, },
], ],
details() { details () {
//支持jsx 嵌套写法,万一测试要关键字加重呢 // 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div> return <div>
<p>The CONVERT_TZ function accepts a three-parameter:</p> <p>The CONVERT_TZ function accepts a three-parameter:</p>
<ul> <ul>
@@ -255,53 +262,57 @@ var renderData = [
} }
}, },
{ {
name: "MEDIAN", name: 'MEDIAN',
syntax:`MEDIAN(<expr>)`, syntax: `MEDIAN(<expr>)`,
description: `Aggregate function is used to calculate median value. expr must be Integer, Float or Decimal.`, description: `Aggregate function is used to calculate median value. expr must be Integer, Float or Decimal.`,
example: [ example: [
{ {
purpose: `Calculates the median "TCP Handshake Latency (tcp_handshake_latency_ms)" field:`, purpose: `Calculates the median "TCP Handshake Latency (tcp_handshake_latency_ms)" field:`,
code: "MEDIAN(tcp_handshake_latency_ms)" code: 'MEDIAN(tcp_handshake_latency_ms)'
} }
], ],
details() { details () {
//支持jsx 嵌套写法,万一测试要关键字加重呢 // 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div>In Traffic logs analysis, the function can be useful in calculating the median of certain numbers, e.g. median SSL Handshake Latency or TCP Handshake Latency.</div> return <div>In Traffic logs analysis, the function can be useful in calculating the median of certain numbers,
e.g. median SSL Handshake Latency or TCP Handshake Latency.</div>
} }
}, },
{ {
name: "QUANTILE", name: 'QUANTILE',
syntax:`QUANTILE(<expr>[, <level>])`, syntax: `QUANTILE(<expr>[, <level>])`,
description: `Aggregate function is used to calculate an approximate quantile of a numeric data sequence.`, description: `Aggregate function is used to calculate an approximate quantile of a numeric data sequence.`,
example: [ example: [
{ {
purpose: `Calculates the 90th percentile "TCP Handshake Latency (tcp_handshake_latency_ms)" field:`, purpose: `Calculates the 90th percentile "TCP Handshake Latency (tcp_handshake_latency_ms)" field:`,
code: "QUANTILE(tcp_handshake_latency_ms, 0.9)" code: 'QUANTILE(tcp_handshake_latency_ms, 0.9)'
} }
], ],
details() { details () {
//支持jsx 嵌套写法,万一测试要关键字加重呢 // 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div> return <div>
<p>The QUANTILE function accepts a two-parameter:</p> <p>The QUANTILE function accepts a two-parameter:</p>
<ul> <ul>
<li>expr - The column values resulting in integer, Flot or Decimal.</li> <li>expr - The column values resulting in integer, Flot or Decimal.</li>
<li>level - Level of quantile. Optional parameter. Constant floating-point number from 0 to 1. We recommend using a level value in the range of [0.01, 0.99]. Default value is 0.5. At level=0.5 the function calculates MEDIAN.</li> <li>level - Level of quantile. Optional parameter. Constant floating-point number from 0 to 1. We recommend
using a level value in the range of [0.01, 0.99]. Default value is 0.5. At level=0.5 the function calculates
MEDIAN.
</li>
</ul> </ul>
</div> </div>
} }
}, },
]; ]
function main() { function main () {
var functionTips = {} var functionTips = {}
renderData.forEach((item, index) => { renderData.forEach((item, index) => {
var data=item // 这是个闭包 var data = item // 这是个闭包
functionTips[item.name] = { functionTips[item.name] = {
name: item.name, name: item.name,
syntax: item.syntax, syntax: item.syntax,
type: "Function", type: 'Function',
description() { description () {
return (<div className='function-tips'> return (<div className="function-tips">
<h2>{data.name}</h2> <h2>{data.name}</h2>
<h3>Syntax:<span>{data.syntax}</span></h3> <h3>Syntax:<span>{data.syntax}</span></h3>
<h3> Description: </h3> <h3> Description: </h3>
@@ -320,10 +331,11 @@ function main() {
<renderer renderFun={data.details}></renderer> : <p>{data.details} </p>} <renderer renderFun={data.details}></renderer> : <p>{data.details} </p>}
</div>) </div>)
} }
}; }
}) })
return functionTips return functionTips
} }
export const functionList=renderData
var functionTips = main(); export const functionList = renderData
var functionTips = main()
export default functionTips export default functionTips

View File

@@ -1,274 +1,111 @@
var renderData=[ import i18n from '@/i18n'
import { EN, storageKey, ZH } from '@/utils/constants'
const renderData = [
{ {
name:"EQUALS", name: 'EQUALS',
syntax:"=", syntax: '=',
primaryKey:"=", primaryKey: '=',
description:"Search for logs where the value of a specified field exactly matches a specified value.", zhDescription: '搜索指定字段的值与指定值完全匹配的实体。',
example:[ enDescription: 'Search for entities where the value of a specified field exactly matches a specified value.',
example: [
{ {
purpose:"Search all logs that are sent by 192.168.10.53:", zhPurpose: '通过192.168.10.53查询ip实体:',
code:"client_ip='192.168.10.53'" enPurpose: 'Search entity of ip by 192.168.10.53:',
code: 'ip=\'192.168.10.53\''
}, },
{ {
purpose:"Search all logs that are communication destination port by 443", zhPurpose: '通过google.com查询domain实体',
code:"server_port=443" enPurpose: 'Search entity of domain by google.com',
}, code: 'domain=\'google.com\''
],
details(){
//支持jsx 嵌套写法,万一测试要关键字加重呢
return <div>If you want search for logs where the value of a specified field is one of multiple specified values. Use multiple <b>EQUALS(=)</b> statements with the OR keyword, or use IN operator.</div>
}
},
{
name:"NOT EQUALS",
syntax:"!=",
primaryKey:"!=",
description:"Search for logs where the value of a specified field doesn't match a specified value.",
example:[
{
purpose:"Search all logs that are sent to any Client IP except 192.168.10.53:",
code:"client_ip!='192.168.10.53'"
},
{
purpose:"Search all logs that are not communication port to 443",
code:"server_port!=443"
},
],
details:`If you want search for logs where the value of a specified field is one of multiple specified values. Use multiple NOT EQUALS(!=) statements with the AND keyword, or use NOT IN operator.`
},
{
name:"GREATER THAN",
syntax:">",
primaryKey:">",
description:"Search logs greater than a value . This operator can't be used with string fields. ",
example:[
{
purpose:"Search all logs more than 751 Bytes ",
code:"sent_bytes > 751"
},
{
purpose:"Search all logs where bandwidth is higher than 751 Bytes:",
code:"received_bytes + sent_bytes > 751"
},
],
details:`The GREATER THAN(>) condition is usally used with LESS THAN(<) as a range query. `
},
{
name:"GREATER THAN EQUALS",
syntax:">=",
primaryKey:">=",
description:"Search logs greater than and equal a value. This operator can't be used with string fields. ",
example:[
{
purpose:"Search all logs with 751 or more Bytes",
code:"sent_bytes >= 751"
},
{
purpose:"Search all logs where bandwidth is equal or higher than 751 Bytes:",
code:"received_bytes + sent_bytes >= 751"
},
],
details:`The GREATER THAN EQUALS(>=) condition is usally used with LESS THAN EQUALS(<=) as a range query.`
},
{
name:"LESS THAN",
syntax:"<",
primaryKey:"<",
description:"Search logs less than a value. This operator can't be used with string fields.",
example:[
{
purpose:"Search all logs less than 751 Bytes :",
code:"sent_bytes < 751"
},
{
purpose:"Search all logs where bandwidth is less than 751 Bytes:",
code:"received_bytes + sent_bytes < 751"
},
],
details:`The LESS THAN(<) condition is usally used with GREATER THAN(>) as a range query.`
},
{
name:"LESS THAN EQUALS",
syntax:"<=",
primaryKey:"<=",
description:"Search logs less than and equal a value. This operator can't be used with string fields. ",
example:[
{
purpose:"Search all logs with 751 or fewer Bytes",
code:"sent_bytes <= 751"
},
{
purpose:"Search all logs where bandwidth is equal or fewer than 751 Bytes:",
code:"received_bytes + sent_bytes <= 751"
},
],
details:`LESS THAN EQUALS(<=) condition is usally used with GREATER THAN EQUALS(>=) as a range query. `
},
{
name:"IN",
syntax:"in",
primaryKey:"IN",
description:"Search for logs where the value of a specified field is one of multiple specified values.",
example:[
{
purpose:"Search all logs in communication destination port 443 or 80",
code:"server_port in (443, 80)"
},
{
purpose:"Search all logs where the Server IP or Client IP is either 8.8.8.8 or 192.168.10.53:",
code:"client_ip in ('8.8.8.8', '192.168.50.53') or server_ip in ('8.8.8.8', '192.168.10.53')"
},
],
details:`The IN condition you can use when you need to use multiple OR condition. The values are specified as a comma-separated(,) list,surrouded by parentheses. Using IN is equivalent to using multiple EQUALS(=)statements with OR expression. That is server_port in (443,80) is the same as (server_port=443 OR server_port=80).`
},
{
name:"NOT IN",
syntax:"not in",
primaryKey:"NOT IN",
description:"Search for logs where the value of a specified field isn't one of multiple specified values.",
example:[
{
purpose:"Search all logs not in communication destination port 443 or 80",
code:"server_port not in (443, 80)"
},
{
purpose:"Search all logs where the Server IP and Client IP isn't 8.8.8.8 or 192.168.10.53:",
code:"client_ip not in ('8.8.8.8', '192.168.10.53') and server_ip not in ('8.8.8.8', '192.168.10.53')"
},
],
details:`The NOT IN condition you can use when you need to use multiple OR condition. The values are specified as a comma-separated(,) list,surrouded by parentheses. Using NOT IN is equivalent to using multiple NOT EQUALS(!=)statements with AND expression. That is , server_port not in (443,80) is the same as (server_port !=443 AND server_port !=80).`
},
{
name:"LIKE",
syntax:"like",
primaryKey:"LIKE",
description:"Search for logs where use wildcard searches for value that contain search fields. This operator can be used with string fields. ",
example:[
{
purpose:`Search all logs where the SSL SNI end with( suffix match) "google.com":`,
code:"ssl_sni like '%google.com'"
},
{
purpose:"Search all logs where the Client IP start with(prefix match) '192.168':",
code:"client_ip like '192.168%'"
},
{
purpose:`Search all logs where the Client IP contains "192.168.1" , between 192.168.10.10 and 192.168.10.19`,
code:"client_ip like '192.168.10.1_'"
},
],
details:`The LIKE condition supports single and multiple character searches.Using percent (%) wildcard substitutes for one or more characters in a string. Using underscore (_) wildcard substitutes for exactly one character in a string. This operator can be used for searval purposes : checking a substring , checking the start or end of a string.`
},
{
name:"NOT LIKE",
syntax:"not like",
primaryKey:"NOT LIKE",
description:"Search for logs where use wildcard searches for value that not contain search fields. This operator can be used with string fields.",
example:[
{
purpose:`Search all logs where the SSL SNI not contain end with( suffix match) "google.com":`,
code:"ssl_sni not like '%google.com'"
},
{
purpose:"Search all logs where the Client IP not contain start with(prefix match) '192.168':",
code:"client_ip not like '192.168%'"
},
{
purpose:`Search all logs where the Client IP not contains "192.168.1" , between 192.168.10.10 and 192.168.10.19`,
code:"client_ip not like '192.168.10.1_'"
},
],
details:`The NOT LIKE condition supports single and multiple character searches. Using percent (%) wildcard substitutes for one or more characters in a string. Using underscore (_) wildcard substitutes for exactly one character in a string. This operator can be used for searval purposes : checking a substring , checking the start or end of a string.`
},
{
name:"HAS",
syntax:"has",
primaryKey:"HAS",
description:"Search for logs where the values of a specified field is one of specified value.This operator can be used with array fields.",
example:[
{
purpose:`Search all logs where the FQDN Category has the music(60):`,
code:"has(service_category,60)"
} }
], ]
details:`The HAS condition checks whether the "expr" array has the "value" element. The syntax has(expr, value).`
}, },
{ {
name:"EMPTY", name: 'IN',
syntax:"empty", syntax: 'in',
primaryKey:"EMPTY", primaryKey: 'IN',
description:"Search for logs where the specified field has empty value. This operator can be used with string and array fields.", zhDescription: '搜索指定字段的值是多个指定值之一的实体。',
example:[ enDescription: 'Search for entities where the value of a specified field is one of multiple specified values.',
example: [
{ {
purpose:`Search all logs where Application is not identified.`, zhPurpose: '通过192.168.10.53 或 192.168.10.54查询ip实体',
code:"empty(common_app_label)" enPurpose: 'Search entity by 192.168.10.53 or 192.168.10.54',
} code: 'ip in (\'192.168.10.53\', \'192.168.10.54\')'
],
details:`An empty string is a string of zero length. However , a NULL has no value at all. An empty string is useful when the data comes from multiple resources. NULL is used when some fields are optional, and the data is unknown.`
},
{
name:"NOT EMPTY",
syntax:"notEmpty",
primaryKey:"NOTEMPTY",
description:"Search for logs where the specified field has a value. This operator can be used with string and array fields.",
example:[
{
purpose:`Search all logs that have one or more SNIs.`,
code:"notEmpty(ssl_sni)"
}
],
details:`A not empty string is considered at least one byte, even if this a space.`
},
{
name:"Bitwise AND",
syntax:"bitAnd",
primaryKey:"BITAND",
description:`A bitwise And(&) is a binary operation that compares each bit of the first operand to the corresponding bit of the second operand. Both expressions must have integral types.`,
example:[
{
purpose:`Search all logs where the Flags has the Asymmetric(524288) and Download(134217728):`,
code:"bitAnd(Flags, 134742016) = 134742016"
}, },
{ {
purpose:`Search all logs where the flags has either Asymmetric(524288) or Download(134217728):`, zhPurpose: '通过appName1 或 appName2查询app实体:',
code:"bitAnd(Flags, 134742016)>0" enPurpose: 'Search entity by appName1 or appName2:',
code: 'app in (\'appName1\', \'appName2\')'
} }
], ]
details:`The operands are converted to 64-bit integers and expressed by a series of bits (zeroes and ones). Sets each bit to 1 if both bits are 1.`
}, },
{
name: 'LIKE',
syntax: 'like',
primaryKey: 'LIKE',
zhDescription: '搜索使用通配符搜索包含搜索字段的值的实体。此运算符与字符串字段一起使用。',
enDescription: 'Search for entities where use wildcard searches for value that contain search fields. This operator is used with array fields.',
example: [
{
zhPurpose: '通过google.com查询domain实体:',
enPurpose: 'Search entity of domain by google.com:',
code: 'domain like \'%google.com\''
},
{
zhPurpose: '通过appName查询app实体:',
enPurpose: 'Search entity of app by appName:',
code: 'app like \'%appName%\''
}
]
},
{
name: 'HAS',
syntax: 'has',
primaryKey: 'HAS',
zhDescription: '搜索指定字段的值是指定值之一的实体。此运算符与数组字段一起使用。',
enDescription: 'Search for entities where the values of a specified field is one of specified value. This operator is used with array fields.',
example: [
{
zhPurpose: '通过ADNS查询tag实体:',
enPurpose: 'Search entity of tag by ADNS:',
code: 'has(tag,\'ADNS\')'
}
]
}
] ]
export const operatorList=renderData export const operatorList = renderData
function main(){
var operatorTips={} function main () {
renderData.forEach((item,index)=>{ const operatorTips = {}
var data=item // 这是个闭包 const language = localStorage.getItem(storageKey.language) || EN
operatorTips[item.primaryKey]={ renderData.forEach((item, index) => {
const data = item // 这是个闭包
operatorTips[item.primaryKey] = {
name: item.name, name: item.name,
syntax: item.syntax, syntax: item.syntax,
type: "Operators", type: 'Operators',
description() { description () {
return (<div className='operator-tips'> return (<div className="operator-tips">
<h2>{data.name}</h2> <div class='default-tips-header'>{data.name}</div>
<h3>Syntax:<span>{data.syntax}</span></h3> <div class='default-tips-title'>{i18n.global.t('overall.syntax')}: <span>{data.syntax}</span></div>
<h3> Description: </h3> <div class='default-tips-title'>{i18n.global.t('overall.remark')}: </div>
<p> {data.description}</p> <p class='show-hint-tips__p'> {language === ZH ? data.zhDescription : data.enDescription}</p>
<h3>Examples:</h3> <div class='default-tips-title'>{i18n.global.t('overall.examples')}: </div>
<ul> <ul style="padding-left: 0;">
{item.example.map(v=>{ {item.example.map(v => {
return <li> return <li>
<span>{v.purpose}</span> <span>{language === ZH ? v.zhPurpose : v.enPurpose}</span>
<code>{v.code}</code> <code>{v.code}</code>
</li> </li>
})} })}
</ul> </ul>
<h3> Details: </h3>
{Object.prototype.toString.call(data.details) === '[object Function]' ? <renderer renderFun={data.details}></renderer> : <p>{data.details} </p>}
</div>) </div>)
} }
}; }
}) })
return operatorTips return operatorTips
} }
var operatorTips=main(); const operatorTips = main()
export default operatorTips export default operatorTips

View File

@@ -1,28 +1,28 @@
var renderData=[ var renderData = [
{ {
name: "FROM", name: 'FROM',
syntax: `FROM [db.]table |$log_type`, syntax: `FROM [db.]table |$log_type`,
description: { description: {
title:`The table name of logs. If you type $log_type, the variable value is the current table name of logs.` title: `The table name of logs. If you type $log_type, the variable value is the current table name of logs.`
} }
}, },
{ {
name: "SELECT", name: 'SELECT',
syntax: `Optional. The selected columns(also known as dimensions and metrics).`, syntax: `Optional. The selected columns(also known as dimensions and metrics).`,
description: { description: {
title:'可选,获取列', title: '可选,获取列',
list:[ list: [
`aggregate_function(field) - Aggregate functions, default is count.`, `aggregate_function(field) - Aggregate functions, default is count.`,
`as field - Use as to specify a aliases for a field or expression.` `as field - Use as to specify a aliases for a field or expression.`
] ]
} }
}, },
{ {
name: "GROUP BY", name: 'GROUP BY',
syntax: `GROUP BY <field-list>`, syntax: `GROUP BY <field-list>`,
description: { description: {
title:'Aggregate data. GROUP BY clause switches the SELECT query into an aggregation mode', title: 'Aggregate data. GROUP BY clause switches the SELECT query into an aggregation mode',
list:[ list: [
`The list of fields known as "grouping key", while each individual expression be referred to as a "key expression".`, `The list of fields known as "grouping key", while each individual expression be referred to as a "key expression".`,
`All the expressions in the SELECT, HAVING and ORDER BY , must be "key expression" or on aggregate functions.`, `All the expressions in the SELECT, HAVING and ORDER BY , must be "key expression" or on aggregate functions.`,
`The result of aggregating SELECT query will return unique values of "grouping key" in log type.` `The result of aggregating SELECT query will return unique values of "grouping key" in log type.`
@@ -30,67 +30,68 @@ var renderData=[
} }
}, },
{ {
name: "HAVING", name: 'HAVING',
syntax: `HAVING <expression-list>`, syntax: `HAVING <expression-list>`,
description: { description: {
title:`Optional. HAVING clause filtering the aggregation results retrieved by GROUP BY. It is difference is that WHERE is performed before aggregation, while HAVING is performed after it. title: `Optional. HAVING clause filtering the aggregation results retrieved by GROUP BY. It is difference is that WHERE is performed before aggregation, while HAVING is performed after it.
Note: HAVING can't be performed if GROUP BY is not performed.` Note: HAVING can't be performed if GROUP BY is not performed.`
} }
}, },
{ {
name: "LIMIT", name: 'LIMIT',
syntax: `LIMIT [n, ]m`, syntax: `LIMIT [n, ]m`,
description: { description: {
title:`Select the m rows from the aggregate results after skipping the first n rows. Default is 10 rows.` title: `Select the m rows from the aggregate results after skipping the first n rows. Default is 10 rows.`
} }
}, },
{ {
name: "ORDER BY", name: 'ORDER BY',
syntax: `ORDER BY <sort-field> [ASC|DESC]`, syntax: `ORDER BY <sort-field> [ASC|DESC]`,
description: { description: {
title:`Sort all of the results by the specified fields.` title: `Sort all of the results by the specified fields.`
} }
}, },
{ {
name: "WHERE", name: 'WHERE',
syntax: `where $filter [and <expression-list>]`, syntax: `where $filter [and <expression-list>]`,
description: { description: {
title:`Filter the data.`, title: `Filter the data.`,
list:[ list: [
`$filter - Default global filter clause. Include Time period, Vsys ID, and other expressions, etc`, `$filter - Default global filter clause. Include Time period, Vsys ID, and other expressions, etc`,
`and <expression-list> - filter clauses` `and <expression-list> - filter clauses`
] ]
} }
} }
] ]
export const sqlList=renderData export const sqlList = renderData
function main(){
var sqlTips={} function main () {
renderData.forEach((item,index)=>{ var sqlTips = {}
var data=item // 这是个闭包 renderData.forEach((item, index) => {
sqlTips[item.name]={ var data = item // 这是个闭包
sqlTips[item.name] = {
name: item.name, name: item.name,
syntax: item.syntax, syntax: item.syntax,
type: "sql", type: 'sql',
description() { description () {
return (<div className='sql-tips'> return (<div className="sql-tips">
<h2>{data.name}</h2> <h2>{data.name}</h2>
<h3>Syntax: <span>{data.syntax}</span></h3> <h3>Syntax: <span>{data.syntax}</span></h3>
<h3> Description: </h3> <h3> Description: </h3>
<p> {data.description.title}</p> <p> {data.description.title}</p>
{ {
data.description.list && <ul> data.description.list && <ul>
{data.description.list.map(v=>{ {data.description.list.map(v => {
return <li>{v} </li> return <li>{v} </li>
})} })}
</ul> </ul>
} }
</div>) </div>)
} }
}; }
}) })
return sqlTips return sqlTips
} }
var sqlTips=main(); var sqlTips = main()
export default sqlTips export default sqlTips

View File

@@ -2,8 +2,8 @@ var renderData = [
{ {
name: '$LOG_TYPE', name: '$LOG_TYPE',
description: 'A variable is a symbolic representation of data that enables you to access a value without having to enter it manually wherever you need it. You can use $ to reference variables throughout Advanced Search. ', description: 'A variable is a symbolic representation of data that enables you to access a value without having to enter it manually wherever you need it. You can use $ to reference variables throughout Advanced Search. ',
details() { details () {
//支持jsx 嵌套写法,万一测试要关键字加重呢 // 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div> return <div>
$log_type: The table name of logs. $log_type: The table name of logs.
</div> </div>
@@ -12,24 +12,24 @@ var renderData = [
{ {
name: '$FILTER', name: '$FILTER',
description: 'A variable is a symbolic representation of data that enables you to access a value without having to enter it manually wherever you need it. You can use $ to reference variables throughout Advanced Search. ', description: 'A variable is a symbolic representation of data that enables you to access a value without having to enter it manually wherever you need it. You can use $ to reference variables throughout Advanced Search. ',
details() { details () {
//支持jsx 嵌套写法,万一测试要关键字加重呢 // 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div> return <div>
$filter: The default filter clauses. such as time period, Vsys ID, and other default expressions, etc. $filter: The default filter clauses. such as time period, Vsys ID, and other default expressions, etc.
</div> </div>
} }
}, }
]; ]
function main() { function main () {
const varTips = {} const varTips = {}
renderData.forEach((item, index) => { renderData.forEach((item, index) => {
const data = item // 这是个闭包 const data = item // 这是个闭包
varTips[item.name] = { varTips[item.name] = {
name: item.name, name: item.name,
type: 'Variables', type: 'Variables',
description() { description () {
return (<div className='var-tips'> return (<div className="var-tips">
<h2>{data.name}</h2> <h2>{data.name}</h2>
<h3> Description: </h3> <h3> Description: </h3>
<p> {data.description}</p> <p> {data.description}</p>
@@ -38,7 +38,7 @@ function main() {
<renderer renderFun={data.details}></renderer> : <p>{data.details} </p>} <renderer renderFun={data.details}></renderer> : <p>{data.details} </p>}
</div>) </div>)
} }
}; }
}) })
return varTips return varTips
} }

View File

@@ -1,5 +1,6 @@
// 改js 用户获取初始化的 SchemaData // 改js 用户获取初始化的 SchemaData
import { Scheme } from './service/Scheme' import { Scheme } from './service/Scheme'
import i18n from '@/i18n'
export class Dataset { export class Dataset {
constructor ({ operatesList, filtersList, operatesDic, funcDic, operatorManual, fields, doc }) { constructor ({ operatesList, filtersList, operatesDic, funcDic, operatorManual, fields, doc }) {
@@ -66,7 +67,7 @@ export class Dataset {
type: 'abstract', type: 'abstract',
text: '', text: '',
// displayText: "Filter", // displayText: "Filter",
displayText: 'filter', displayText: i18n.global.t('overall.fields'),
className: 'divider hint-title', className: 'divider hint-title',
hint (cm, callback, options) { hint (cm, callback, options) {
} }
@@ -96,7 +97,7 @@ export class Dataset {
type: 'abstract', type: 'abstract',
text: '', text: '',
// displayText: "Operator", // displayText: "Operator",
displayText: 'operator', displayText: i18n.global.t('overall.keyword'),
className: 'divider hint-title' className: 'divider hint-title'
// hint(cm, callback, options) {} // hint(cm, callback, options) {}
} }

View File

@@ -6,7 +6,7 @@
<i class="cn-icon cn-icon-arrow-right"></i> <i class="cn-icon cn-icon-arrow-right"></i>
</span> </span>
</div> </div>
<div class="cn-entity__case"> <div class="cn-entity__case" ref="rowBlock">
<div class="cn-entity__icon"><i :class="iconClass"></i></div> <div class="cn-entity__icon"><i :class="iconClass"></i></div>
<div class="cn-entity__row"> <div class="cn-entity__row">
<!--标签--> <!--标签-->
@@ -327,6 +327,12 @@ export default {
/* 切换折叠状态 */ /* 切换折叠状态 */
switchCollapse () { switchCollapse () {
this.isCollapse = !this.isCollapse this.isCollapse = !this.isCollapse
// 因为默认的背景白色会导致showhint的box-shadow被盖住所以展开详情时才渲染颜色
if (this.isCollapse) {
this.$refs.rowBlock.style.cssText = 'background-color: none'
} else {
this.$refs.rowBlock.style.cssText = 'background-color: #fff'
}
this.$emit('switchCollapse', this.isCollapse, this.index) this.$emit('switchCollapse', this.isCollapse, this.index)
}, },
/* 设为折叠状态 */ /* 设为折叠状态 */