perf:explore 编辑功能(operator function 待完成)

This commit is contained in:
wangwenrui
2020-06-18 16:38:07 +08:00
parent 29b57265b6
commit b3ac8130d7
3 changed files with 228 additions and 43 deletions

View File

@@ -1580,7 +1580,9 @@
} }
}, },
getAlertListChartData:function(chartInfo,filterType){ getAlertListChartData:function(chartInfo,filterType){
if(this.additionalInfo){
this.$set(chartInfo, "param", {endpointId: this.additionalInfo.id}); this.$set(chartInfo, "param", {endpointId: this.additionalInfo.id});
}
this.$refs['editChart'+chartInfo.id][0].getAlertList(filterType); this.$refs['editChart'+chartInfo.id][0].getAlertList(filterType);
}, },
getAlertRuleChartData(chartInfo) { getAlertRuleChartData(chartInfo) {

View File

@@ -4,9 +4,9 @@
<div class="metric-editor-popper" :style="{left:popperPos.left+'px'}"> <div class="metric-editor-popper" :style="{left:popperPos.left+'px'}">
<div class="metric-popper-main" > <div class="metric-popper-main" >
<el-scrollbar style="height: 100%" class="ps-scroll-small" ref="scroll"> <el-scrollbar style="height: 100%" class="ps-scroll-small" ref="scroll">
<div v-for="(value, key, index) in showSuggestions" > <div v-for="(key, index) in orders" >
<div v-html="key" class="popper-group"></div> <div v-html="key" class="popper-group" v-show="showSuggestions[key]"></div>
<div class="popper-item" v-for="(item,i) in value" v-html="item.label" :key="item.insertText" :type="key" :value="item.insertText" @click.stop="handleItemClick(key,item,$event)"></div> <div class="popper-item" v-for="(item,i) in showSuggestions[key]" v-html="item.label" :key="item.insertText" :type="key" :value="item.insertText" @click.stop="handleItemClick(key,item,$event)"></div>
</div> </div>
</el-scrollbar> </el-scrollbar>
</div> </div>
@@ -18,7 +18,7 @@
<script> <script>
import 'quill/dist/quill.snow.css' import 'quill/dist/quill.snow.css'
import Quill from 'quill' import Quill from 'quill'
import {del} from "../../../../http"; import suggestions from "./suggestions";
export default { export default {
name: "editor", name: "editor",
props: { props: {
@@ -32,7 +32,10 @@
id:'editor-'+this.guid(), id:'editor-'+this.guid(),
cursorIndex:0, cursorIndex:0,
pivotalCursorIndex:0,//用于记录输入特殊符号后当前光标的位置,方便选择后覆盖 pivotalCursorIndex:0,//用于记录输入特殊符号后当前光标的位置,方便选择后覆盖
newExpressionIndex:0,
editRange:{start:0,end:0},
noStyleSuggestions:{},//存储最原始的item数据 noStyleSuggestions:{},//存储最原始的item数据
orders:['history','operators','functions','metrics','labels','values'],
showSuggestions:{},//存储显示的item数据包含mark样式 showSuggestions:{},//存储显示的item数据包含mark样式
storedSuggestions:[],//存储每个item的dom storedSuggestions:[],//存储每个item的dom
toggleSelectIndex:-1, toggleSelectIndex:-1,
@@ -46,6 +49,7 @@
placeholder: 'Insert text here ...' placeholder: 'Insert text here ...'
}, },
labelValues:{}, labelValues:{},
tempStoreMetric:{},
} }
}, },
created(){ created(){
@@ -54,59 +58,194 @@
methods:{ methods:{
userChange:function(char,operation,newContent,oldContent){ userChange:function(char,operation,newContent,oldContent){
this.dealSpecilChar(char,operation); this.dealSpecilChar(char,operation);
this.changeSuggestions('type')
if(this.pivotalCursorIndex>this.editRange.start && this.pivotalCursorIndex < this.editRange.end){
if(this.pivotalCursorIndex!=0){ if(this.pivotalCursorIndex!=0){
console.log('pivotalCursorIndex',this.pivotalCursorIndex,'cursorIndex',this.cursorIndex) console.log('pivotalCursorIndex',this.pivotalCursorIndex,'cursorIndex',this.cursorIndex)
newContent=newContent.substring(this.pivotalCursorIndex,this.cursorIndex); newContent=newContent.substring(this.pivotalCursorIndex,this.cursorIndex);
} }
}else{
newContent=newContent.substring(this.editRange.start,this.editRange.end)
}
this.filterItems(newContent); this.filterItems(newContent);
}, },
dealSpecilChar:function(char,operation){ dealSpecilChar:function(char,operation){
if(/^[\{\(\[]$/g.test(char)){ if(/^[\{\(\[\,]$/g.test(char)){
if(operation=='insert'){ if(operation=='insert'){
if(char == '{'||char==','){
if(char == '{'){ if(char == '{'){
this.insertTextAtIndex('}',this.cursorIndex) this.addDoubleChar('}')
this.quill.setSelection(this.cursorIndex) }
this.changeSuggestions('label') this.changeSuggestions('label')
}else if(char == '('){ }else if(char == '('){
this.insertTextAtIndex(')',this.cursorIndex) this.addDoubleChar(')')
this.quill.setSelection(this.cursorIndex)
}else if(char == '['){ }else if(char == '['){
this.insertTextAtIndex(']',this.cursorIndex) this.addDoubleChar(']')
this.quill.setSelection(this.cursorIndex)
} }
}else{ }else{
this.quill.deleteText(this.cursorIndex,1,'api') this.delDoubleChar(char);
} }
}else if(/^[=]/g.test(char)){ }else if(/^[=\"]/g.test(char)){
if(operation=='insert'){ if(operation=='insert'){
let labelValuesReg=/\{((\w*?=.*?,{0,1})+?)\}/ if(char == '"'){
if(labelValuesReg.test(this.content)){ this.addDoubleChar('"');
let labelValues=labelValuesReg.exec(this.content)[0] }
if(labelValues){ this.changeSuggestions('values')
let unCompleteInputReg=/\w*?=[^"|\s]/
if(unCompleteInputReg.test(labelValues)){
let unCompleteInput=unCompleteInputReg.exec(labelValues)[0];
unCompleteInput=unCompleteInput.substring(0,unCompleteInput.length-2)
let values=this.labelValues.get(unCompleteInput);
console.log('values',values)
this.noStyleSuggestions={values:values}
this.showSuggestions=this.deepClone(this.noStyleSuggestions);
}
}
}
}else{ }else{
if(char == '"'){
this.delDoubleChar(char);
} }
} }
}
},
addDoubleChar:function(char){
this.insertTextAtIndex(char,this.cursorIndex);
this.quill.setSelection(this.cursorIndex)
},
delDoubleChar:function(leftChar){
let char=this.content.charAt(this.cursorIndex);
let temp=leftChar+char;
if(/(\{\})|(\(\))|(\[\])|(\"\")/.test(temp)){
this.quill.deleteText(this.cursorIndex,1,'api');
}
if(leftChar == '{'){
this.pivotalCursorIndex=0;
}
}, },
changeSuggestions:function(type){ changeSuggestions:function(type){
if(type == 'label'){ if(type == 'label'){
this.queryLabels(); this.queryLabels();
}else if(type == 'values'){
this.queryValues();
}else if(type == 'type'){
this.packageTypeInfo();
}
},
packageTypeInfo:function(){
let metricReg=/[a-zA-Z_]\w*?\b\{.*?\}/g
let functionReg=/[a-zA-Z_]\w*?\(.*?\)/g
if(functionReg.test(this.content)){
let tempIndex=this.cursorIndex;
let tempStart,tempChar=this.content.charAt(tempIndex-1);
//向前查找,找到边界
while(tempIndex>0&&/[a-zA-Z_]/.test(tempChar)){
tempIndex--;
tempChar=this.content.charAt(tempIndex);
}
this.editRange.start=tempIndex+1;
this.editRange.end=this.cursorIndex;
}else{
if(metricReg.test(this.content)){
let match=this.globalMatch(metricReg,this.content)
if(match&&match.length>0){
let isInnerExpression=false;
let editExpression=null;
match.forEach(item=>{
let content=item[0];
let index=item.index;
let length=content.length;
if(index < this.cursorIndex && index+length>this.cursorIndex){ //判断是否在一个完整子表达式中
isInnerExpression=true;
editExpression=item;
}
})
console.log('match',match,'isInnerExpress',isInnerExpression)
if(isInnerExpression&&editExpression){
let expression=editExpression[0];
let labelValuesReg=/\{((\w*?=.*?,{0,1})+?)\}/
if(labelValuesReg.test(expression)){
let match=labelValuesReg.exec(expression);
if(editExpression.index+match.index>this.cursorIndex){
this.queryTypeInfos();
}
}
this.editRange.start=editExpression.index;
this.editRange.end=editExpression.index+expression.length;
}else{
let tempIndex=this.cursorIndex;
let tempStart,tempChar=this.content.charAt(tempIndex-1);
//向前查找,找到边界
while(tempIndex>0&&/[a-zA-Z_]/.test(tempChar)){
tempIndex--;
tempChar=this.content.charAt(tempIndex);
}
this.editRange.start=tempIndex+1;
this.editRange.end=this.cursorIndex;
console.log('multi expression',this.editRange)
this.queryTypeInfos();
}
}
}else{
console.log('mo match metric')
this.editRange.start=0;
this.editRange.end=this.cursorIndex;
this.queryTypeInfos();
}
}
},
queryTypeInfos:function(){
this.noStyleSuggestions={};
this.$set(this.noStyleSuggestions,'metrics',this.tempStoreMetric)
this.$set(this.noStyleSuggestions,'operators',suggestions.getOperators())
this.$set(this.noStyleSuggestions,'functions',suggestions.getFunctions())
this.showSuggestions=this.deepClone(this.noStyleSuggestions)
},
queryValues:function(){
let labelValuesReg=/\{((\w*?=.*?,{0,1})+?)\}/
if(labelValuesReg.test(this.content)){
let match=labelValuesReg.exec(this.content);
let labelValues=match[0]
let index=match.index;
if(labelValues){
let tempCounter=this.cursorIndex;
let equalIndex=-1;
let boundaryIndex=-1;
while(tempCounter>=index){
let char=this.content.charAt(tempCounter);
if(char=='='){
equalIndex=tempCounter;
}
if(char==','||char == '{'){
boundaryIndex=tempCounter+1;
break;
}
tempCounter--;
}
let label=this.content.substring(boundaryIndex,equalIndex);
console.log('label',this.content.substring(boundaryIndex,equalIndex))
let values=this.labelValues.get(label);
this.noStyleSuggestions={values:values}
this.showSuggestions=this.deepClone(this.noStyleSuggestions)
}
} }
}, },
queryLabels:function(){ queryLabels:function(){
let labels=/\{.*\}/;
if(labels.test(this.content)){
let match=labels.exec(this.content);
let index=match.index;
let matchContent=match[0];
if(this.cursorIndex<index || this.cursorIndex>index + matchContent.length){
return ;
}
}else{
this.queryTypeInfos();
return;
}
let metric=/([a-zA-Z_]\w*)\b(?=\{)/.exec(this.content)[0]; let metric=/([a-zA-Z_]\w*)\b(?=\{)/.exec(this.content)[0];
let timeRange=this.getDefaultTimeRange(); let timeRange=this.getDefaultTimeRange();
this.$get('/prom/api/v1/series?match[]={__name__="'+metric+'"}&start='+timeRange[0]+"&end="+timeRange[1]).then(response=>{ this.$get('/prom/api/v1/series?match[]={__name__="'+metric+'"}&start='+timeRange[0]+"&end="+timeRange[1]).then(response=>{
@@ -141,6 +280,7 @@
this.noStyleSuggestions={labels:labels} this.noStyleSuggestions={labels:labels}
this.showSuggestions=this.deepClone(this.noStyleSuggestions); this.showSuggestions=this.deepClone(this.noStyleSuggestions);
console.log('change labels',this.showSuggestions)
this.storeSuggestions(); this.storeSuggestions();
}else{ }else{
this.noStyleSuggestions={}; this.noStyleSuggestions={};
@@ -163,12 +303,25 @@
this.handleLabelClick(item) this.handleLabelClick(item)
}else if(type == 'values'){ }else if(type == 'values'){
this.handleValueClick(item); this.handleValueClick(item);
}else if(type == 'operators'){
this.handleOperatorClick(item);
} }
}, },
handleOperatorClick:function(item){
this.deleteTextInRange(this.editRange.start,this.cursorIndex)
this.insertTextAtIndex(item.insertText,this.editRange.start == 0?this.editRange.start-1:this.editRange.start);
this.quill.setSelection(this.cursorIndex+item.insertText.length);
this.storeCursor().then(()=>{
this.insertTextAtIndex('(',this.cursorIndex,'user')
this.quill.setSelection(this.cursorIndex+1)
this.editRange.start=this.cursorIndex;
this.editRange.end=this.cursorIndex;
})
},
handleMetricClick:function(item){ handleMetricClick:function(item){
this.clearContent(); this.deleteTextInRange(this.editRange.start,this.cursorIndex)
this.$nextTick(()=>{ this.$nextTick(()=>{
this.insertTextAtIndex(item.insertText); this.insertTextAtIndex(item.insertText,this.editRange.start==0?this.editRange.start-1:this.editRange.start);
}) })
this.moveCursorToEnd(); this.moveCursorToEnd();
}, },
@@ -183,7 +336,14 @@
}) })
}, },
handleValueClick:function(item){ handleValueClick:function(item){
let preChar=this.content.substring(this.pivotalCursorIndex-1,this.pivotalCursorIndex);
this.quill.setSelection(this.pivotalCursorIndex,this.cursorIndex-this.pivotalCursorIndex,'api');
this.deleteTextInRange(this.pivotalCursorIndex,this.cursorIndex-this.pivotalCursorIndex)
if(preChar == '='){
this.insertTextAtIndex('"'+item.insertText+'"',this.pivotalCursorIndex)
}else{
this.insertTextAtIndex(item.insertText,this.pivotalCursorIndex)
}
}, },
toggleSelect:function(event){//上下键选择 toggleSelect:function(event){//上下键选择
if(!this.storedSuggestions||this.storedSuggestions.length<1){ if(!this.storedSuggestions||this.storedSuggestions.length<1){
@@ -283,6 +443,7 @@
return new Promise(function(resolve,reject){ return new Promise(function(resolve,reject){
$temp.$nextTick(()=>{ $temp.$nextTick(()=>{
let range=$temp.quill.getSelection(); let range=$temp.quill.getSelection();
console.log('range',range)
if(range&&range.length == 0){ if(range&&range.length == 0){
$temp.cursorIndex=range.index; $temp.cursorIndex=range.index;
console.log('current cursor-->',$temp.cursorIndex) console.log('current cursor-->',$temp.cursorIndex)
@@ -371,14 +532,25 @@
deepClone:function(source){ deepClone:function(source){
return JSON.parse(JSON.stringify(source)) return JSON.parse(JSON.stringify(source))
}, },
globalMatch:function(pattern,content){
let result=[];
let temp;
pattern.lastIndex=0;
while ((temp = pattern.exec(content)) != null) {
result.push(temp)
}
return result;
},
queryMetrics:function(){ queryMetrics:function(){
this.$get('/prom/api/v1/label/__name__/values').then(response=>{ this.$get('/prom/api/v1/label/__name__/values').then(response=>{
if(response.status == 'success'){ if(response.status == 'success'){
let metrics=response.data.map(item=>{ let metrics=response.data.map(item=>{
return {label:item,insertText:item}; return {label:item,insertText:item};
}) })
this.$set(this.noStyleSuggestions,'metrics',metrics)
this.showSuggestions=this.deepClone(this.noStyleSuggestions) this.tempStoreMetric=this.deepClone(metrics);
this.queryTypeInfos();
} }
}) })
}, },
@@ -428,6 +600,11 @@
}) })
this.storeSuggestions(); this.storeSuggestions();
this.registerKeydown(); this.registerKeydown();
},
watch:{
content:function(n,o){
}
} }
} }
</script> </script>

View File

@@ -57,7 +57,6 @@
}, },
]; ];
const funcs=[ const funcs=[
...operators,
{ {
insertText: 'abs', insertText: 'abs',
label: 'abs', label: 'abs',
@@ -361,5 +360,12 @@
}, },
] ]
export default { export default {
getOperators:function(){
return JSON.parse(JSON.stringify(operators));
},
getFunctions:function(){
return JSON.parse(JSON.stringify(funcs))
},
} }
</script> </script>