NEZ-3213 feat:promql & logql 表达式输入支持 step 和 querytype 组件开发 (80%)

This commit is contained in:
zhangyu
2023-10-13 16:40:21 +08:00
parent 33e63c0bd3
commit 50654bfa7a
18 changed files with 141 additions and 85 deletions

View File

@@ -35,10 +35,12 @@
}
}
.nz-icon-alert-list {
.nz-icon-sousuoliebiao {
cursor: pointer;
top: 50%;
transform: translateY(-50%);
}
.nz-icon-alert-list:hover{
.nz-icon-sousuoliebiao:hover{
color: $--color-primary;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -5,6 +5,13 @@
"css_prefix_text": "nz-icon-",
"description": "",
"glyphs": [
{
"icon_id": "37668864",
"name": "搜索列表",
"font_class": "sousuoliebiao",
"unicode": "e804",
"unicode_decimal": 59396
},
{
"icon_id": "37448064",
"name": "Notebook",

View File

@@ -1,4 +1,5 @@
@import './nzIcon.css'; // 自定义图标的字体
//@import './nzIcon.css'; // 自定义图标的字体
@import './font/iconfont.css'; // 自定义图标的字体
@import './common/maplibre-gl.css'; // 地图样式
@import './font.scss'; // 字体
@import './index.scss'; // 主样式

File diff suppressed because one or more lines are too long

View File

@@ -219,6 +219,7 @@ export default {
if (chartInfo.elements) {
if (chartInfo.elements[expressionIndex]) {
alias = alias + this.handleLegendAlias(legend, chartInfo.elements[expressionIndex].legend, tagKeysArr)
console.log(alias, this.handleLegendAlias(legend, chartInfo.elements[expressionIndex].legend, tagKeysArr), legend, chartInfo.elements[expressionIndex].legend, tagKeysArr)
}
if (!alias) {
alias = chartInfo.elements[expressionIndex].expression || ''

View File

@@ -80,7 +80,7 @@
</span>
</span>
</div>
<transition name="el-zoom-in-top">
<!-- <transition name="el-zoom-in-top">-->
<el-row v-show="expressionsShow[index-1].show">
<el-form-item :prop="'elements.' + (index -1) + '.expression'" :rules="{ required: true, message: $t('validate.required'), trigger: 'change'}">
<promql-input
@@ -123,7 +123,7 @@
</el-popover>
</div>
<div style="flex: 1">
<el-select size="small" v-model="expressionsShow[index-1].queryType" @change="expressionChange">
<el-select size="small" v-model="expressionsShow[index-1].queryType" @change="queryTypeChange(index - 1)">
<el-option :label="'Range'" :value="1">Range</el-option>
<el-option :label="'Instant'" :value="2">Instant</el-option>
</el-select>
@@ -150,7 +150,7 @@
</div>
</el-row>
</el-row>
</transition>
<!-- </transition>-->
</el-row>
</draggable>
</div>

View File

@@ -340,6 +340,10 @@ export default {
this.$refs.chartForm?.clearValidate('elements.' + (index) + '.expression')
this.change()
},
queryTypeChange (index) {
this.expressionsShow[index].step = undefined
this.expressionChange(index)
},
switchExpression (index, flag) {
if (flag === 1) {
this.$set(this.expressionsShow[index], 'state', 0)

View File

@@ -126,6 +126,9 @@
<span v-else @click="()=>{switchExpression(index - 1,0)}" :title="$t('overall.invisible')" style="margin-right: 5px;padding-left: 10px">
<i class="nz-icon nz-icon-mimabukejian"></i>
</span>
<span @click="()=>{showHistoryBox(index - 1)}" style="margin-right: 5px" :title="$t('overall.history')">
<i class="nz-icon nz-icon-time" style="fontSize:16px"></i>
</span>
<span @click="()=>{addExpression()}" style="margin-right: 5px" :title="$t('tip.add')">
<i class="nz-icon nz-icon-create-square" style="font-weight: normal; font-size: 17px; cursor: pointer;"></i>
</span>
@@ -140,7 +143,7 @@
</span>
</span>
</div>
<transition name="el-zoom-in-top">
<!-- <transition name="el-zoom-in-top">-->
<el-row v-show="expressionsShow[index-1].show">
<promql-input
:from-father-data="true"
@@ -185,7 +188,7 @@
</el-popover>
</div>
<div style="flex: 1">
<el-select size="small" v-model="expressionsShow[index-1].queryType" @change="expressionChange" style="width: 100%;">
<el-select size="small" v-model="expressionsShow[index-1].queryType" @change="queryTypeChange(index - 1)" style="width: 100%;">
<el-option :label="'Range'" :value="1">Range</el-option>
<el-option :label="'Instant'" :value="2">Instant</el-option>
</el-select>
@@ -205,15 +208,14 @@
:min="minStep"
:precision="0"
:controls="false"
class="append_unit"
:placeholder="$t('overall.auto')"
:data-unit="$t('overall.seconds')">
>
</el-input-number>
</div>
</div>
</el-row>
</el-row>
</transition>
<!-- </transition>-->
</el-row>
</draggable>
</div>
@@ -3892,6 +3894,7 @@ export default {
this.saveDisabled = false
}
axios.all(requestArr).then(res => {
this.postHistory()
this.chartLoading = false
const errorRowIndex = []
res.forEach((r, i) => {
@@ -4007,8 +4010,11 @@ export default {
legendName = queryExpression[index]
}
seriesItem.name = legendName + '-' + index
const tagKeysArr = Object.keys(result.metric)
// console.log(queryExpression[index], this.expressions[index], tagKeysArr)
const legendAlias = this.handleLegendAlias(legendName, this.promqlKeys[promqlInputIndexs[index]].legend, tagKeysArr)
series.push(seriesItem)
legend.push({ name: seriesItem.name, alias: legendName, isGray: false })
legend.push({ name: seriesItem.name, alias: legendAlias, isGray: false })
})
this.$refs['promql-' + promqlIndex][0].setError('')
@@ -4035,10 +4041,17 @@ export default {
// 过滤掉state为0的元素
this.expressions.forEach((item, index) => {
if (item != '' && this.promqlKeys[index].state && !this.promqlKeys[index].matrix) {
const step = bus.getStep(bus.formateTimeToTime(this.filterTime[0]), bus.formateTimeToTime(this.filterTime[1]))
let step = bus.getStep(bus.formateTimeToTime(this.filterTime[0]), bus.formateTimeToTime(this.filterTime[1]))
if (this.promqlKeys[index].step) {
step = this.promqlKeys[index].step
}
promqlInputIndexs.push(index)
queryExpression.push(item)
requestArr.push(this.$get('/prom/api/v1/query_range?query=' + encodeURIComponent(item) + '&start=' + this.$stringTimeParseToUnix(bus.formateTimeToTime(this.filterTime[0])) + '&end=' + this.$stringTimeParseToUnix(bus.formateTimeToTime(this.filterTime[1])) + '&step=' + step + '&nullType=null'))
if (this.promqlKeys[index].queryType === 2) {
requestArr.push(this.$get('/prom/api/v1/query_instant?query=' + encodeURIComponent(item) + '&time=' + this.$stringTimeParseToUnix(bus.formateTimeToTime(this.filterTime[1]))))
} else {
requestArr.push(this.$get('/prom/api/v1/query_range?query=' + encodeURIComponent(item) + '&start=' + this.$stringTimeParseToUnix(bus.formateTimeToTime(this.filterTime[0])) + '&end=' + this.$stringTimeParseToUnix(bus.formateTimeToTime(this.filterTime[1])) + '&step=' + step + '&nullType=null'))
}
}
})
if (requestArr.length > 0) {
@@ -4100,8 +4113,11 @@ export default {
legendName = queryExpression[index]
}
seriesItem.name = legendName + '-' + index
const tagKeysArr = Object.keys(result.metric)
// console.log(queryExpression[index], this.expressions[index], tagKeysArr)
const legendAlias = this.handleLegendAlias(legendName, this.promqlKeys[promqlInputIndexs[index]].legend, tagKeysArr)
series.push(seriesItem)
legend.push({ name: seriesItem.name, alias: legendName, isGray: false })
legend.push({ name: seriesItem.name, alias: legendAlias, isGray: false })
})
this.$refs['promql-' + promqlIndex][0].setError('')
@@ -4255,6 +4271,50 @@ export default {
this.tools.loading = false
}
},
handleLegendAlias (legend, aliasExpression, params) { // 处理别名
const self = this
const myParams = JSON.parse(JSON.stringify(params))
myParams.$labels = JSON.parse(JSON.stringify(params))
myParams.$value = myParams.value
// if (this.from !== 'meta2dTooltip') {
// aliasExpression = this.globalVariablesReplace(aliasExpression)
// }
if (/\{\{.+\}\}/.test(aliasExpression)) {
const labelValue = aliasExpression.replace(/(\{\{.+?\}\})/g, function (i) {
const label = i.substr(i.indexOf('{{') + 2, i.indexOf('}}') - i.indexOf('{{') - 2)
if (!legend) {
return label
}
let value = null
if (params && self.$lodash.get(myParams, label)) {
value = self.$lodash.get(myParams, label)
}
if (label) {
const reg = new RegExp(label + '=".+?"', 'g')
if (reg.test(legend)) {
const ans = legend.match(reg)
let find = ''
ans.forEach(item => {
const index = legend.indexOf(item)
if (legend[index - 1] !== '_') {
find = item
}
})
value = find.substr(find.indexOf('"') + 1, find.lastIndexOf('"') - find.indexOf('"') - 1)
}
}
return value || ''
})
return labelValue
} else {
if (!aliasExpression) {
return legend
// let result =legend.substr(legend.indexOf('"') + 1,legend.lastIndexOf('"') - legend.indexOf('"') - 1);
// return result
}
return aliasExpression
}
},
handlerRowData (data) {
const metric = this.$lodash.cloneDeep(data)
const metricName = metric.__name__ || ''
@@ -4322,7 +4382,7 @@ export default {
const promiseArr = []
this.expressions.forEach((item, index) => {
if (item != '' && this.promqlKeys[index].state) {
promiseArr.push(this.$get('/logs/loki/api/v1/format_query', { query: item }))
promiseArr.push(this.$get('logs/loki/api/v1/format_query', { query: item }))
} else {
promiseArr.push('')
}
@@ -4331,7 +4391,6 @@ export default {
console.log(res)
})
this.queryLogData()
this.postHistory()
}
}
this.updatePath()
@@ -4362,13 +4421,10 @@ export default {
this.promqlCount = data.queries.length
data.queries.forEach((item, index) => {
this.$set(this.expressions, index, item.expr)
if (this.promqlKeys[index]) {
this.promqlKeys[index].state = item.state
} else {
this.promqlKeys[index] = {
id: getUUID(),
state: item.state
}
this.promqlKeys[index] = {
...item,
id: getUUID(),
state: item.state
}
})
this.init()

View File

@@ -336,7 +336,7 @@ export default {
state: this.expressionsShow[i].state,
orderNum: i,
step: this.expressionsShow[i].step,
queryType: this.expressionsShow[i].queryType,
queryType: this.expressionsShow[i].queryType
})
}
})
@@ -344,6 +344,10 @@ export default {
this.promqlKeys = []
}
},
queryTypeChange (index) {
this.expressionsShow[index].step = undefined
this.expressionChange()
},
switchExpression (index, flag) {
if (flag === 1) {
this.$set(this.expressionsShow[index], 'state', 0)
@@ -463,5 +467,10 @@ export default {
this.expressionsShow[index - 1].show = !this.expressionsShow[index - 1].show
this.$set(this.expressionsShow, index - 1, this.expressionsShow[index - 1])
},
showHistoryBox (index) {
console.log(this.$refs['promql-' + (index)])
const historyshow = this.$refs['promql-' + (index)][0]?.historyshow
this.$refs['promql-' + (index)][0]?.showHistoryBox(!historyshow)
}
}
}

View File

@@ -178,6 +178,7 @@ export default {
},
selectHistory (item) {
this.$emit('selectHistory', item.queryValue)
this.hideMe()
}
}
}

View File

@@ -8,7 +8,7 @@ export default {
LANGUAGE_SETUP_STARTED: false,
parser,
MONACO_EDITOR_OPTIONS: {
automaticLayout: false,
automaticLayout: true,
formatOnType: true,
formatOnPaste: true,
codeLens: false,

View File

@@ -6,7 +6,7 @@
<div
v-if="plugins.indexOf('metric-input') > -1"
class="input-box"
:class="type == 'log' ? 'input-box-log' : ''"
style="margin-right: 0;"
@click="dropDownVisible = false"
>
<div
@@ -41,53 +41,9 @@
<div v-if="appendMsg" class="append-msg error" style="position: absolute">
<span>{{ appendMsg }}</span>
</div>
<i class="nz-icon nz-icon-alert-list" style="position: absolute;top: 4px; right: 6px" @click="queryPromptShowChange"/>
<i class="nz-icon nz-icon-sousuoliebiao" style="position: absolute; right: 6px" @click="queryPromptShowChange"/>
<queryPrompt v-if="queryPromptShow" @close="queryPromptShowChange" :type="type" :width="queryPromptWidth" :position="queryPromptPosition" class="no-style-class" @selectMetric="selectMetric" @selectLog="selectLog"/>
</div>
<div class="top-tool-btn-group">
<button
v-if="plugins.indexOf('enable') > -1"
class="top-tool-btn"
:title="state?$t('overall.enabled'):$t('profile.close')"
@click="enableExpression"
>
<i v-if="state" class="nz-icon nz-icon-mimakejian"></i>
<i v-else class="nz-icon nz-icon-mimabukejian" style="fontSize:16px"></i>
</button>
<button
v-if="plugins.indexOf('history') > -1"
class="top-tool-btn"
:title="$t('overall.history')"
@click.stop="showHistoryBox(!historyshow)"
>
<i class="nz-icon nz-icon-time" style="fontSize:16px"></i>
</button>
<button
v-if="plugins.indexOf('add') > -1"
class="top-tool-btn"
:title="$t('tip.add')"
@click="addExpression"
>
<i class="nz-icon nz-icon-plus"></i>
</button>
<button
v-if="plugins.indexOf('copy') > -1"
class="top-tool-btn"
@click="copyExpression"
:title="$t('overall.duplicate')"
>
<i class="nz-icon nz-icon-override"></i>
</button>
<button
v-if="plugins.indexOf('remove') > -1"
class="top-tool-btn"
@click="removeExpression"
:title="$t('overall.delete')"
>
<i class="nz-icon nz-icon-minus"></i>
</button>
</div>
<explore-history v-if="historyshow" :type="type" @close="showHistoryBox(false)" @selectHistory="selectHistory"/>
</template>
<!--right-box里的样式-->
@@ -144,7 +100,7 @@
<span>{{ appendMsg }}</span>
</div>
</el-col>
<i class="nz-icon nz-icon-alert-list" style="position: absolute;right: 15px;height: 24px; width: 24px;line-height: 24px;top: 3px;" @click="queryPromptShowChange"/>
<i class="nz-icon nz-icon-sousuoliebiao" style="position: absolute;right: 15px;height: 24px; width: 24px;line-height: 24px;" @click="queryPromptShowChange"/>
<queryPrompt v-if="queryPromptShow" @close="queryPromptShowChange" :type="type" :width="queryPromptWidth" :position="queryPromptPosition" class="no-style-class" @selectMetric="selectMetric" @selectLog="selectLog"/>
</el-row>
</template>
@@ -1085,8 +1041,9 @@ export default {
const windowWidth = window.innerWidth// 窗口宽度
const windowHeight = window.innerHeight// 窗口高度
const boxHeight = 400
const parentHeight = 40
const parentHeight = this.$refs.queryRow.offsetHeight + 10
let top = 0
console.log()
const left = position.left
if (position.top + parentHeight + boxHeight > windowHeight - 100) {
top = position.top - boxHeight - 10

View File

@@ -289,12 +289,12 @@ export default {
str += key
if (this.selectLogLabels[key].length === 1) {
str += '="'
str += this.selectLogLabels[key][0]
str += this.escapeLabelValueInExactSelector(this.selectLogLabels[key][0])
str += '"'
} else {
str += '=~"'
this.selectLogLabels[key].forEach(item => {
str += this.$lodash.escapeRegExp(item)
str += this.escapeLabelValueInRegexSelector(item)
str += '|'
})
str = str.slice(0, -1)
@@ -344,6 +344,16 @@ export default {
this.$copyText(value).then(() => {
this.$message.success({ message: this.$t('overall.copySuccess') })
})
},
escapeLabelValueInExactSelector (labelValue) {
return labelValue.replace(/\\/g, '\\\\').replace(/\n/g, '\\n').replace(/"/g, '\\"')
},
escapeLabelValueInRegexSelector (labelValue) {
return this.escapeLabelValueInExactSelector(this.escapeLokiRegexp(labelValue))
},
escapeLokiRegexp (value) {
const RE2_METACHARACTERS = /[*+?()|\\.\[\]{}^$]/g
return value.replace(RE2_METACHARACTERS, '\\$&')
}
}
}