@fc-components/monaco-editor 0.1.16 → 0.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,6 +9,7 @@ export declare class DataProvider {
9
9
  private readonly errorHandler?;
10
10
  private readonly httpMethod;
11
11
  private readonly apiPrefix;
12
+ private enableRequests;
12
13
  private readonly customRequest;
13
14
  metrics: string[];
14
15
  labelKeys: string[];
@@ -23,8 +24,8 @@ export declare class DataProvider {
23
24
  fetchLabels: (selector: string) => Promise<string[]>;
24
25
  fetchLabelValues: (labelName: string, selector: string) => Promise<string[]>;
25
26
  getAllMetricNames(): string[];
26
- start: () => Promise<void[]>;
27
- loadMetricsMetadata(): Promise<void>;
27
+ start: () => Promise<PromMetricsMetadata[]>;
28
+ loadMetricsMetadata(): Promise<PromMetricsMetadata>;
28
29
  metricNamesToMetrics(metricNames: string[]): Metric[];
29
30
  private setInputInRange;
30
31
  private enableAutocompleteSuggestionsUpdate;
@@ -8,6 +8,7 @@ interface PromQLEditorProps {
8
8
  placeholder?: string;
9
9
  enableAutocomplete?: boolean;
10
10
  durationVariablesCompletion?: boolean;
11
+ enableRequests?: boolean;
11
12
  readOnly?: boolean;
12
13
  disabled?: boolean;
13
14
  interpolateString?: (query: string) => string;
@@ -27,5 +27,6 @@ export interface DataProviderParams {
27
27
  httpMethod?: 'POST' | 'GET';
28
28
  apiPrefix?: string;
29
29
  httpErrorHandler?: (error: any) => void;
30
+ enableRequests?: boolean;
30
31
  }
31
32
  export {};
@@ -0,0 +1,4 @@
1
+ import * as monaco from 'monaco-editor';
2
+ export declare const getSqlCompletionProvider: () => {
3
+ provideCompletionItems(model: monaco.editor.ITextModel, position: monaco.Position, _context: monaco.languages.CompletionContext, _token: monaco.CancellationToken): monaco.languages.ProviderResult<monaco.languages.CompletionList>;
4
+ };
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import type * as monacoTypes from 'monaco-editor/esm/vs/editor/editor.api';
3
+ interface SqlEditorProps {
4
+ size?: 'small' | 'middle' | 'large';
5
+ theme?: 'light' | 'dark';
6
+ value?: string;
7
+ placeholder?: string;
8
+ enableAutocomplete?: boolean;
9
+ readOnly?: boolean;
10
+ disabled?: boolean;
11
+ onChange?: (value: string) => void;
12
+ onEnter?: (value: string) => void;
13
+ onBlur?: (value: string) => void;
14
+ editorDidMount?: (editor: monacoTypes.editor.IStandaloneCodeEditor) => void;
15
+ }
16
+ export default function SqlEditor(props: SqlEditorProps): React.JSX.Element;
17
+ export {};
@@ -0,0 +1,85 @@
1
+ export declare const languageConfiguration: {
2
+ wordPattern: RegExp;
3
+ comments: {
4
+ lineComment: string;
5
+ blockComment: [string, string];
6
+ };
7
+ brackets: any;
8
+ autoClosingPairs: any;
9
+ surroundingPairs: any;
10
+ folding: {
11
+ offSide: boolean;
12
+ };
13
+ };
14
+ export declare const language: {
15
+ defaultToken: string;
16
+ tokenPostfix: string;
17
+ ignoreCase: boolean;
18
+ brackets: {
19
+ open: string;
20
+ close: string;
21
+ token: string;
22
+ }[];
23
+ keywords: string[];
24
+ operators: string[];
25
+ builtinFunctions: string[];
26
+ escapes: RegExp;
27
+ digits: RegExp;
28
+ octaldigits: RegExp;
29
+ hexdigits: RegExp;
30
+ regexpctl: RegExp;
31
+ regexpattern: RegExp;
32
+ tokenizer: {
33
+ root: ((string | RegExp)[] | {
34
+ include: string;
35
+ } | (RegExp | {
36
+ cases: {
37
+ '@builtinFunctions': string;
38
+ '@default': string;
39
+ };
40
+ })[] | (RegExp | {
41
+ cases: {
42
+ '@keywords': string;
43
+ '@default': string;
44
+ };
45
+ })[])[];
46
+ whitespace: (string | RegExp)[][];
47
+ comments: ((string | RegExp)[] | (RegExp | {
48
+ token: string;
49
+ next: string;
50
+ })[])[];
51
+ comment: ((string | RegExp)[] | (RegExp | {
52
+ token: string;
53
+ next: string;
54
+ })[])[];
55
+ 'pseudo-columns': (RegExp | {
56
+ cases: {
57
+ '@keywords': string;
58
+ '@default': string;
59
+ };
60
+ })[][];
61
+ builtinVariables: (RegExp | {
62
+ cases: {
63
+ '@keywords': string;
64
+ '@default': string;
65
+ };
66
+ })[][];
67
+ numbers: (string | RegExp)[][];
68
+ strings: (RegExp | {
69
+ token: string;
70
+ next: string;
71
+ })[][];
72
+ string: ((string | RegExp)[] | (RegExp | {
73
+ token: string;
74
+ next: string;
75
+ })[])[];
76
+ string_double: ((string | RegExp)[] | (RegExp | {
77
+ token: string;
78
+ next: string;
79
+ })[])[];
80
+ string_backtick: ((string | RegExp)[] | (RegExp | {
81
+ token: string;
82
+ next: string;
83
+ })[])[];
84
+ };
85
+ };
@@ -0,0 +1,8 @@
1
+ export interface SqlEditorMarker {
2
+ startLineNumber: number;
3
+ startColumn: number;
4
+ endLineNumber: number;
5
+ endColumn: number;
6
+ message: string;
7
+ severity: 'Error' | 'Warning' | 'Information';
8
+ }
@@ -0,0 +1,2 @@
1
+ import * as monaco from 'monaco-editor';
2
+ export declare const validateSql: (sql: string) => Omit<monaco.editor.IMarker, 'owner' | 'resource'>[];
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.1.16",
6
+ "version": "0.1.18",
7
7
  "license": "MIT",
8
8
  "main": "dist/index.js",
9
9
  "module": "dist/monaco-editor.esm.js",
package/src/index.tsx CHANGED
@@ -1,5 +1,7 @@
1
1
  import promql from './promql';
2
2
  import yaml from './yaml';
3
+ import sql from './sql';
3
4
 
4
5
  export { promql as PromQLMonacoEditor };
5
6
  export { yaml as YamlMonacoEditor };
7
+ export { sql as SqlMonacoEditor };
@@ -26,6 +26,7 @@ export class DataProvider {
26
26
  private readonly errorHandler?: (error: any) => void;
27
27
  private readonly httpMethod: 'POST' | 'GET' = 'GET';
28
28
  private readonly apiPrefix: string = '/api/v1';
29
+ private enableRequests: boolean = true;
29
30
  private readonly customRequest: CustomRequest = (input: RequestInfo, init?: RequestInit): Promise<Response> => fetch(input, init);
30
31
  metrics: string[];
31
32
  labelKeys: string[];
@@ -56,6 +57,11 @@ export class DataProvider {
56
57
  this.apiPrefix = params.apiPrefix;
57
58
  }
58
59
 
60
+ // control whether DataProvider should actually send network requests
61
+ if (typeof params.enableRequests !== 'undefined') {
62
+ this.enableRequests = !!params.enableRequests;
63
+ }
64
+
59
65
  this.metrics = [];
60
66
  this.labelKeys = [];
61
67
  }
@@ -113,6 +119,9 @@ export class DataProvider {
113
119
  }
114
120
 
115
121
  fetchSeries = async (selector: string, withLimit?: string): Promise<Record<string, string | undefined>[]> => {
122
+ if (!this.enableRequests) {
123
+ return [] as Record<string, string | undefined>[];
124
+ }
116
125
  const end = new Date();
117
126
  const start = new Date(end.getTime() - this.lookbackInterval);
118
127
  const url = `${this.apiPrefix}/series`;
@@ -138,6 +147,9 @@ export class DataProvider {
138
147
  };
139
148
 
140
149
  fetchLabels = async (selector: string): Promise<string[]> => {
150
+ if (!this.enableRequests) {
151
+ return [] as string[];
152
+ }
141
153
  const end = new Date();
142
154
  const start = new Date(end.getTime() - this.lookbackInterval);
143
155
  const url = `${this.apiPrefix}/labels`;
@@ -164,6 +176,9 @@ export class DataProvider {
164
176
  };
165
177
 
166
178
  fetchLabelValues = async (labelName: string, selector: string): Promise<string[]> => {
179
+ if (!this.enableRequests) {
180
+ return [] as string[];
181
+ }
167
182
  const end = new Date();
168
183
  const start = new Date(end.getTime() - this.lookbackInterval);
169
184
  const url = `${this.apiPrefix}/label/${labelName}/values`;
@@ -198,7 +213,11 @@ export class DataProvider {
198
213
  ]);
199
214
  };
200
215
 
201
- async loadMetricsMetadata() {
216
+ async loadMetricsMetadata(): Promise<PromMetricsMetadata> {
217
+ if (!this.enableRequests) {
218
+ this.metricsMetadata = {} as PromMetricsMetadata;
219
+ return this.metricsMetadata;
220
+ }
202
221
  const request = this.buildRequest(`${this.apiPrefix}/metadata`, new URLSearchParams({}));
203
222
  this.metricsMetadata = await this.request<PromMetricsMetadata>(request.uri, {
204
223
  method: this.httpMethod,
@@ -206,6 +225,8 @@ export class DataProvider {
206
225
  }).catch(() => {
207
226
  return {} as PromMetricsMetadata;
208
227
  });
228
+
229
+ return this.metricsMetadata || ({} as PromMetricsMetadata);
209
230
  }
210
231
 
211
232
  metricNamesToMetrics(metricNames: string[]): Metric[] {
@@ -20,6 +20,8 @@ interface PromQLEditorProps {
20
20
  placeholder?: string;
21
21
  enableAutocomplete?: boolean;
22
22
  durationVariablesCompletion?: boolean;
23
+ // When false, DataProvider will not send network requests. Default: true
24
+ enableRequests?: boolean;
23
25
  readOnly?: boolean;
24
26
  disabled?: boolean;
25
27
  interpolateString?: (query: string) => string;
@@ -92,6 +94,7 @@ export default function PromQLEditor(props: PromQLEditorProps & DataProviderPara
92
94
  placeholder,
93
95
  interpolateString,
94
96
  enableAutocomplete = true,
97
+ enableRequests = true,
95
98
  readOnly = false,
96
99
  disabled = false,
97
100
  onChange,
@@ -266,6 +269,7 @@ export default function PromQLEditor(props: PromQLEditorProps & DataProviderPara
266
269
  httpMethod: props.httpMethod,
267
270
  apiPrefix: props.apiPrefix,
268
271
  httpErrorHandler: props.httpErrorHandler,
272
+ enableRequests: enableRequests,
269
273
  });
270
274
  dataProviderRef.current = dataProvider;
271
275
  dataProvider.start();
@@ -331,6 +335,7 @@ export default function PromQLEditor(props: PromQLEditorProps & DataProviderPara
331
335
  props.httpMethod,
332
336
  props.apiPrefix,
333
337
  placeholder,
338
+ enableRequests,
334
339
  ]);
335
340
 
336
341
  return (
@@ -33,4 +33,6 @@ export interface DataProviderParams {
33
33
  httpMethod?: 'POST' | 'GET';
34
34
  apiPrefix?: string;
35
35
  httpErrorHandler?: (error: any) => void;
36
+ // When false, DataProvider will not send any network requests.
37
+ enableRequests?: boolean;
36
38
  }
@@ -0,0 +1,140 @@
1
+ # SQL Editor
2
+
3
+ 这是一个基于 Monaco Editor 和 `monaco-sql-languages` 的 SQL 编辑器组件。
4
+
5
+ ## 功能特性
6
+
7
+ - ✨ 完整的 SQL 语法高亮
8
+ - 🎯 智能代码补全(关键字、函数等)
9
+ - ✅ SQL 语法验证(括号、引号匹配等)
10
+ - 🎨 支持浅色和深色主题
11
+ - 📏 支持不同尺寸(small, middle, large)
12
+ - ♿ 只读和禁用模式
13
+ - 🎹 快捷键支持(Ctrl+Enter 执行)
14
+
15
+ ## 使用方法
16
+
17
+ ### 基本用法
18
+
19
+ ```tsx
20
+ import { SqlMonacoEditor } from '@fc-components/monaco-editor';
21
+
22
+ function MyComponent() {
23
+ const [sql, setSql] = React.useState('SELECT * FROM users;');
24
+
25
+ return (
26
+ <div style={{ height: '400px' }}>
27
+ <SqlMonacoEditor value={sql} onChange={setSql} placeholder='Enter SQL query...' />
28
+ </div>
29
+ );
30
+ }
31
+ ```
32
+
33
+ ### 完整示例
34
+
35
+ ```tsx
36
+ import React, { useState } from 'react';
37
+ import { SqlMonacoEditor } from '@fc-components/monaco-editor';
38
+
39
+ function SqlQueryBuilder() {
40
+ const [sql, setSql] = useState('');
41
+ const [result, setResult] = useState<any>(null);
42
+
43
+ const handleChange = (value: string) => {
44
+ setSql(value);
45
+ };
46
+
47
+ const handleExecute = (value: string) => {
48
+ console.log('执行 SQL:', value);
49
+ // 发送到后端执行
50
+ };
51
+
52
+ const handleBlur = (value: string) => {
53
+ console.log('SQL 失焦:', value);
54
+ };
55
+
56
+ return (
57
+ <div>
58
+ <div style={{ height: '300px', border: '1px solid #ccc', marginBottom: '20px' }}>
59
+ <SqlMonacoEditor
60
+ size='large'
61
+ theme='light'
62
+ value={sql}
63
+ placeholder='输入 SQL 查询...'
64
+ enableAutocomplete={true}
65
+ onChange={handleChange}
66
+ onEnter={handleExecute}
67
+ onBlur={handleBlur}
68
+ />
69
+ </div>
70
+ {result && (
71
+ <div>
72
+ <h3>查询结果:</h3>
73
+ <pre>{JSON.stringify(result, null, 2)}</pre>
74
+ </div>
75
+ )}
76
+ </div>
77
+ );
78
+ }
79
+
80
+ export default SqlQueryBuilder;
81
+ ```
82
+
83
+ ## Props
84
+
85
+ | 参数 | 类型 | 默认值 | 说明 |
86
+ | -------------------- | ------------------------------ | -------- | ---------------------- |
87
+ | `size` | 'small' \| 'middle' \| 'large' | 'middle' | 编辑器尺寸 |
88
+ | `theme` | 'light' \| 'dark' | 'light' | 主题 |
89
+ | `value` | string | '' | 编辑器内容 |
90
+ | `placeholder` | string | - | 占位符文本 |
91
+ | `enableAutocomplete` | boolean | true | 启用代码补全 |
92
+ | `readOnly` | boolean | false | 只读模式 |
93
+ | `disabled` | boolean | false | 禁用编辑 |
94
+ | `onChange` | (value: string) => void | - | 内容变化回调 |
95
+ | `onEnter` | (value: string) => void | - | Ctrl+Enter 时触发 |
96
+ | `onBlur` | (value: string) => void | - | 编辑器失焦时触发 |
97
+ | `editorDidMount` | (editor) => void | - | 编辑器挂载完成后的回调 |
98
+
99
+ ## 快捷键
100
+
101
+ - **Ctrl+Enter** 或 **Cmd+Enter**: 触发 `onEnter` 事件(通常用于执行查询)
102
+ - **Ctrl+Z** 或 **Cmd+Z**: 撤销
103
+ - **Ctrl+Y** 或 **Cmd+Y**: 重做
104
+ - **Ctrl+F** 或 **Cmd+F**: 查找
105
+ - **Ctrl+H** 或 **Cmd+H**: 查找替换
106
+ - **Ctrl+L**: 选中当前行
107
+
108
+ ## 支持的 SQL 关键字
109
+
110
+ 包括 SELECT, FROM, WHERE, JOIN, GROUP BY, ORDER BY, INSERT, UPDATE, DELETE, CREATE, DROP 等。
111
+
112
+ ## 支持的 SQL 函数
113
+
114
+ - 聚合函数: COUNT, SUM, AVG, MIN, MAX
115
+ - 字符串函数: UPPER, LOWER, LENGTH, SUBSTRING, TRIM, CONCAT
116
+ - 数值函数: ROUND, ABS
117
+ - 日期函数: DATE, NOW, YEAR, MONTH, DAY
118
+ - 其他函数: COALESCE, NULLIF, IFNULL
119
+
120
+ ## 验证
121
+
122
+ 编辑器会自动检测以下 SQL 语法问题:
123
+
124
+ - 未闭合的单引号、双引号和反引号
125
+ - 未匹配的括号
126
+ - 其他基本的语法问题
127
+
128
+ ## 主题定制
129
+
130
+ 如需自定义主题,可以添加 CSS 规则覆盖默认样式:
131
+
132
+ ```css
133
+ .sql-light {
134
+ /* 浅色主题样式 */
135
+ }
136
+
137
+ .sql-dark {
138
+ /* 深色主题样式 */
139
+ }
140
+ ```
@@ -0,0 +1,125 @@
1
+ import * as monaco from 'monaco-editor';
2
+
3
+ const SQL_KEYWORDS = [
4
+ 'SELECT',
5
+ 'FROM',
6
+ 'WHERE',
7
+ 'AND',
8
+ 'OR',
9
+ 'NOT',
10
+ 'JOIN',
11
+ 'INNER',
12
+ 'LEFT',
13
+ 'RIGHT',
14
+ 'FULL',
15
+ 'OUTER',
16
+ 'ON',
17
+ 'ORDER',
18
+ 'BY',
19
+ 'GROUP',
20
+ 'HAVING',
21
+ 'LIMIT',
22
+ 'OFFSET',
23
+ 'INSERT',
24
+ 'INTO',
25
+ 'VALUES',
26
+ 'UPDATE',
27
+ 'SET',
28
+ 'DELETE',
29
+ 'CREATE',
30
+ 'TABLE',
31
+ 'ALTER',
32
+ 'DROP',
33
+ 'PRIMARY',
34
+ 'KEY',
35
+ 'FOREIGN',
36
+ 'CONSTRAINT',
37
+ 'UNIQUE',
38
+ 'INDEX',
39
+ 'VIEW',
40
+ 'DATABASE',
41
+ 'SCHEMA',
42
+ 'AS',
43
+ 'DISTINCT',
44
+ 'CASE',
45
+ 'WHEN',
46
+ 'THEN',
47
+ 'ELSE',
48
+ 'END',
49
+ 'CAST',
50
+ 'BETWEEN',
51
+ 'IN',
52
+ 'LIKE',
53
+ 'IS',
54
+ 'NULL',
55
+ 'TRUE',
56
+ 'FALSE',
57
+ 'WITH',
58
+ 'UNION',
59
+ 'EXCEPT',
60
+ 'INTERSECT',
61
+ 'ASC',
62
+ 'DESC',
63
+ 'ALL',
64
+ 'ANY',
65
+ 'EXISTS',
66
+ 'CROSS',
67
+ ];
68
+
69
+ const SQL_FUNCTIONS = [
70
+ { name: 'COUNT', signature: 'COUNT(expression)', description: 'Returns the number of rows' },
71
+ { name: 'SUM', signature: 'SUM(expression)', description: 'Returns the sum of values' },
72
+ { name: 'AVG', signature: 'AVG(expression)', description: 'Returns the average value' },
73
+ { name: 'MIN', signature: 'MIN(expression)', description: 'Returns the minimum value' },
74
+ { name: 'MAX', signature: 'MAX(expression)', description: 'Returns the maximum value' },
75
+ { name: 'UPPER', signature: 'UPPER(string)', description: 'Converts string to uppercase' },
76
+ { name: 'LOWER', signature: 'LOWER(string)', description: 'Converts string to lowercase' },
77
+ { name: 'LENGTH', signature: 'LENGTH(string)', description: 'Returns the length of string' },
78
+ { name: 'SUBSTRING', signature: 'SUBSTRING(string, start, length)', description: 'Extracts substring' },
79
+ { name: 'TRIM', signature: 'TRIM(string)', description: 'Removes leading and trailing spaces' },
80
+ { name: 'ROUND', signature: 'ROUND(number, decimals)', description: 'Rounds a number' },
81
+ { name: 'ABS', signature: 'ABS(number)', description: 'Returns absolute value' },
82
+ { name: 'COALESCE', signature: 'COALESCE(value1, value2, ...)', description: 'Returns first non-null value' },
83
+ { name: 'NULLIF', signature: 'NULLIF(value1, value2)', description: 'Returns null if two values are equal' },
84
+ { name: 'IFNULL', signature: 'IFNULL(value, default)', description: 'Returns alternative if null' },
85
+ { name: 'CONCAT', signature: 'CONCAT(string1, string2, ...)', description: 'Concatenates strings' },
86
+ { name: 'DATE', signature: 'DATE(date)', description: 'Extracts date part' },
87
+ { name: 'NOW', signature: 'NOW()', description: 'Returns current date and time' },
88
+ ];
89
+
90
+ export const getSqlCompletionProvider = () => {
91
+ return {
92
+ provideCompletionItems(
93
+ model: monaco.editor.ITextModel,
94
+ position: monaco.Position,
95
+ _context: monaco.languages.CompletionContext,
96
+ _token: monaco.CancellationToken,
97
+ ): monaco.languages.ProviderResult<monaco.languages.CompletionList> {
98
+ const word = model.getWordUntilPosition(position);
99
+ const range = new monaco.Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn);
100
+
101
+ const suggestions: monaco.languages.CompletionItem[] = [
102
+ ...SQL_KEYWORDS.map((keyword) => ({
103
+ label: keyword,
104
+ kind: monaco.languages.CompletionItemKind.Keyword,
105
+ insertText: keyword,
106
+ range: range,
107
+ sortText: '1' + keyword,
108
+ })),
109
+ ...SQL_FUNCTIONS.map((func) => ({
110
+ label: func.name,
111
+ kind: monaco.languages.CompletionItemKind.Function,
112
+ insertText: func.name,
113
+ detail: func.signature,
114
+ documentation: func.description,
115
+ range: range,
116
+ sortText: '2' + func.name,
117
+ })),
118
+ ];
119
+
120
+ return {
121
+ suggestions: suggestions,
122
+ };
123
+ },
124
+ };
125
+ };