diff --git a/nezha-fronted/package.json b/nezha-fronted/package.json index 29eec676d..80494db7a 100644 --- a/nezha-fronted/package.json +++ b/nezha-fronted/package.json @@ -12,6 +12,13 @@ "unit": "jest --config test/unit/jest.conf.js --coverage" }, "dependencies": { + "@codemirror/autocomplete": "^0.19.15", + "@codemirror/basic-setup": "^0.19.3", + "@codemirror/highlight": "^0.19.8", + "@codemirror/language": "^0.19.10", + "@codemirror/lint": "^0.19.6", + "@codemirror/state": "^0.19.9", + "@codemirror/view": "^0.19.48", "@johmun/vue-tags-input": "^2.1.0", "@riophae/vue-treeselect": "^0.4.0", "@svgdotjs/svg.js": "^3.0.16", @@ -24,6 +31,7 @@ "@topology/layout": "^0.3.0", "@topology/sequence-diagram": "^0.3.0", "axios": "^0.19.0", + "codemirror-promql": "^0.19.0", "cytoscape": "^3.15.2", "d3": "^6.7.0", "d3-hexbin": "^0.2.2", diff --git a/nezha-fronted/src/assets/css/components/page/dashboard/explore/promqlInput.scss b/nezha-fronted/src/assets/css/components/page/dashboard/explore/promqlInput.scss index a1755ea4b..d5593f4f7 100644 --- a/nezha-fronted/src/assets/css/components/page/dashboard/explore/promqlInput.scss +++ b/nezha-fronted/src/assets/css/components/page/dashboard/explore/promqlInput.scss @@ -2,6 +2,9 @@ position: relative; width: 100%; display: flex; + #editor{ + width: 100%; + } .no-resize{ background: rgba(255,255,255,0); .el-textarea__inner { diff --git a/nezha-fronted/src/components/chart/chartMixin.js b/nezha-fronted/src/components/chart/chartMixin.js index 5a15ee1fc..dab16c545 100644 --- a/nezha-fronted/src/components/chart/chartMixin.js +++ b/nezha-fronted/src/components/chart/chartMixin.js @@ -145,7 +145,6 @@ export default { } }, handleLegendAlias (legend, aliasExpression) { - console.log(legend, aliasExpression) if (/\{\{.+\}\}/.test(aliasExpression)) { const labelValue = aliasExpression.replace(/(\{\{.+?\}\})/g, function (i) { const label = i.substr(i.indexOf('{{') + 2, i.indexOf('}}') - i.indexOf('{{') - 2) diff --git a/nezha-fronted/src/components/common/rightBox/alertRuleBox.vue b/nezha-fronted/src/components/common/rightBox/alertRuleBox.vue index a2ea304b0..b8f742494 100644 --- a/nezha-fronted/src/components/common/rightBox/alertRuleBox.vue +++ b/nezha-fronted/src/components/common/rightBox/alertRuleBox.vue @@ -348,6 +348,7 @@ import { noSpecialChar, nzNumber } from '../js/validate' import editRigthBox from '../mixin/editRigthBox' import richTextEditor from '@/components/chart/richTextEditor' import promqlInputMixin from '@/components/common/mixin/promqlInput' + export default { name: 'alertRuleBox', props: { diff --git a/nezha-fronted/src/components/page/dashboard/explore/CMTheme.tsx b/nezha-fronted/src/components/page/dashboard/explore/CMTheme.tsx new file mode 100644 index 000000000..cb9051b71 --- /dev/null +++ b/nezha-fronted/src/components/page/dashboard/explore/CMTheme.tsx @@ -0,0 +1,183 @@ +import { HighlightStyle, tags } from '@codemirror/highlight'; +import { EditorView } from '@codemirror/view'; + +export const baseTheme = EditorView.theme({ + '&': { + '&.cm-focused': { + outline: 'none', + outline_fallback: 'none', + }, + }, + '.cm-scroller': { + overflow: 'hidden', + fontFamily: '"DejaVu Sans Mono", monospace', + }, + '.cm-placeholder': { + fontFamily: + '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"', + }, + + '.cm-matchingBracket': { + color: '#000', + backgroundColor: '#dedede', + fontWeight: 'bold', + outline: '1px dashed transparent', + }, + '.cm-nonmatchingBracket': { borderColor: 'red' }, + + '.cm-tooltip': { + backgroundColor: '#f8f8f8', + borderColor: 'rgba(52, 79, 113, 0.2)', + }, + + '.cm-tooltip.cm-tooltip-autocomplete': { + '& > ul': { + maxHeight: '350px', + fontFamily: '"DejaVu Sans Mono", monospace', + maxWidth: 'unset', + }, + '& > ul > li': { + padding: '2px 1em 2px 3px', + }, + '& li:hover': { + backgroundColor: '#ddd', + }, + '& > ul > li[aria-selected]': { + backgroundColor: '#d6ebff', + color: 'unset', + }, + minWidth: '30%', + }, + + '.cm-completionDetail': { + float: 'right', + color: '#999', + }, + + '.cm-tooltip.cm-completionInfo': { + marginTop: '-11px', + padding: '10px', + fontFamily: "'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande', sans-serif;", + border: 'none', + backgroundColor: '#d6ebff', + minWidth: '250px', + maxWidth: 'min-content', + }, + + '.cm-completionInfo.cm-completionInfo-right': { + '&:before': { + content: "' '", + height: '0', + position: 'absolute', + width: '0', + left: '-20px', + border: '10px solid transparent', + borderRightColor: '#d6ebff', + }, + marginLeft: '12px', + }, + '.cm-completionInfo.cm-completionInfo-left': { + '&:before': { + content: "' '", + height: '0', + position: 'absolute', + width: '0', + right: '-20px', + border: '10px solid transparent', + borderLeftColor: '#d6ebff', + }, + marginRight: '12px', + }, + + '.cm-completionMatchedText': { + textDecoration: 'none', + fontWeight: 'bold', + color: '#0066bf', + }, + + '.cm-line': { + '&::selection': { + backgroundColor: '#add6ff', + }, + '& > span::selection': { + backgroundColor: '#add6ff', + }, + }, + + '.cm-selectionMatch': { + backgroundColor: '#e6f3ff', + }, + + '.cm-diagnostic': { + '&.cm-diagnostic-error': { + borderLeft: '3px solid #e65013', + }, + }, + + '.cm-completionIcon': { + boxSizing: 'content-box', + fontSize: '16px', + lineHeight: '1', + marginRight: '10px', + verticalAlign: 'top', + '&:after': { content: "'\\ea88'" }, + fontFamily: 'codicon', + paddingRight: '0', + opacity: '1', + color: '#007acc', + }, + + '.cm-completionIcon-function, .cm-completionIcon-method': { + '&:after': { content: "'\\ea8c'" }, + color: '#652d90', + }, + '.cm-completionIcon-class': { + '&:after': { content: "'○'" }, + }, + '.cm-completionIcon-interface': { + '&:after': { content: "'◌'" }, + }, + '.cm-completionIcon-variable': { + '&:after': { content: "'𝑥'" }, + }, + '.cm-completionIcon-constant': { + '&:after': { content: "'\\eb5f'" }, + color: '#007acc', + }, + '.cm-completionIcon-type': { + '&:after': { content: "'𝑡'" }, + }, + '.cm-completionIcon-enum': { + '&:after': { content: "'∪'" }, + }, + '.cm-completionIcon-property': { + '&:after': { content: "'□'" }, + }, + '.cm-completionIcon-keyword': { + '&:after': { content: "'\\eb62'" }, + color: '#616161', + }, + '.cm-completionIcon-namespace': { + '&:after': { content: "'▢'" }, + }, + '.cm-completionIcon-text': { + '&:after': { content: "'\\ea95'" }, + color: '#ee9d28', + }, +}); + +export const promqlHighlighter = HighlightStyle.define([ + { tag: tags.name, color: '#000' }, + { tag: tags.number, color: '#09885a' }, + { tag: tags.string, color: '#a31515' }, + { tag: tags.keyword, color: '#008080' }, + { tag: tags.function(tags.variableName), color: '#008080' }, + { tag: tags.labelName, color: '#800000' }, + { tag: tags.operator }, + { tag: tags.modifier, color: '#008080' }, + { tag: tags.paren }, + { tag: tags.squareBracket }, + { tag: tags.brace }, + { tag: tags.invalid, color: 'red' }, + { tag: tags.comment, color: '#888', fontStyle: 'italic' }, +]); \ No newline at end of file diff --git a/nezha-fronted/src/components/page/dashboard/explore/promqlInput.vue b/nezha-fronted/src/components/page/dashboard/explore/promqlInput.vue index 446d3814f..0d4f4be44 100644 --- a/nezha-fronted/src/components/page/dashboard/explore/promqlInput.vue +++ b/nezha-fronted/src/components/page/dashboard/explore/promqlInput.vue @@ -6,100 +6,268 @@
- - - + + - +
-
- -
{{errorMsg}}
-
{{appendMsg}}
+
+
+
+ + +
+ {{ errorMsg }} +
+
+ {{ appendMsg }} +
- - - + + +
+
+ {{ appendMsg }} +
+
+ + + -
-
+
+
+ +
+
+
-
- + center + > + Expression - + - Variable - + Variable + - + - + - + - + - -