@cloudcare/guance-front-tools 1.0.12 → 1.0.13

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.
Files changed (39) hide show
  1. package/guance-all-charts.json +3415 -0
  2. package/lib/cjs/generated/dashboardCharts.d.ts +54 -13
  3. package/lib/cjs/scripts/grafana-covert-to-guance-core.d.ts +1 -1
  4. package/lib/cjs/scripts/grafana-covert-to-guance-core.js +5 -289
  5. package/lib/esm/generated/dashboardCharts.d.ts +54 -13
  6. package/lib/esm/scripts/grafana-covert-to-guance-core.d.ts +1 -1
  7. package/lib/esm/scripts/grafana-covert-to-guance-core.js +5 -289
  8. package/lib/example/grafana2.json +878 -0
  9. package/lib/example/guance-dahs-3.json +348 -0
  10. package/lib/scripts/grafana-covert-to-guance-core.js +5 -286
  11. package/lib/scripts/grafana-covert-to-guance-core.ts +12 -326
  12. package/lib/scripts/grafana-covert-to-guance.js +52 -29
  13. package/lib/scripts/grafana-covert-to-guance.ts +60 -32
  14. package/package.json +4 -3
  15. package/schemas/charts/chart-schema.json +8 -5
  16. package/schemas/charts/common/chart-link-item-schema.json +48 -0
  17. package/schemas/charts/common/chart-links-schema.json +9 -0
  18. package/schemas/charts/common/common-chart-types-schema.json +3 -1
  19. package/schemas/charts/dashboard-schema.json +11 -4
  20. package/schemas/charts/query/query-item-schema.json +19 -1
  21. package/schemas/charts/settings/settings-time-schema.json +1 -5
  22. package/schemas/charts/settings/settings-unit-items-schema.json +3 -1
  23. package/schemas/charts/settings/settings-units-schema.json +2 -3
  24. package/scripts/validate-file.mjs +57 -0
  25. package/skills/grafana-to-guance-dashboard/SKILL.md +102 -0
  26. package/skills/grafana-to-guance-dashboard/agents/openai.yaml +4 -0
  27. package/skills/grafana-to-guance-dashboard/references/converter-notes.md +134 -0
  28. package/skills/grafana-to-guance-dashboard/scripts/convert-grafana-dashboard.mjs +1899 -0
  29. package/test/cli.test.mjs +316 -0
  30. package/test-output/grafana2.cli.guance.json +1029 -0
  31. package/test-output/grafana2.guance.json +1029 -0
  32. package/test-output/grafana2.keep-meta.guance.json +1384 -0
  33. package/test-output/pod.guance.json +2153 -0
  34. package/test-output/skill-test2-enhanced.guance.json +21596 -0
  35. package/test-output/skill-test2-validated.guance.json +11610 -0
  36. package/test-output/skill-test2.guance.json +11610 -0
  37. package/test-output/test.guance.json +1086 -0
  38. package/test-output/test2.guance.guance-promql.json +23212 -0
  39. package/test-output/test2.guance.json +17554 -0
@@ -25,8 +25,10 @@
25
25
  "heatmap",
26
26
  "topology",
27
27
  "sankey",
28
+ "change",
28
29
  "log",
29
30
  "object",
31
+ "monitor",
30
32
  "alarm",
31
33
  "text",
32
34
  "video",
@@ -34,4 +36,4 @@
34
36
  "command",
35
37
  "iframe"
36
38
  ]
37
- }
39
+ }
@@ -48,9 +48,16 @@
48
48
  }
49
49
  },
50
50
  "type": {
51
- "type": "string",
52
- "description": "固定字段",
53
- "const": "template"
51
+ "description": "仪表板主体类型,现有数据中常缺省,存在时固定为 template",
52
+ "anyOf": [
53
+ {
54
+ "type": "string",
55
+ "const": "template"
56
+ },
57
+ {
58
+ "type": "null"
59
+ }
60
+ ]
54
61
  }
55
62
  }
56
63
  },
@@ -70,4 +77,4 @@
70
77
  }
71
78
  }
72
79
  }
73
- }
80
+ }
@@ -31,12 +31,30 @@
31
31
  "type": "string",
32
32
  "description": "图表查询语句,可以是 dql语句,也可以是 promql 语句"
33
33
  },
34
+ "content": {
35
+ "type": "string",
36
+ "description": "文本图内容,支持 HTML 或 Markdown 文本"
37
+ },
34
38
  "code": {
35
39
  "type": "string",
36
40
  "description": "查询语句的唯一标识,由单个大写英文字母构成"
41
+ },
42
+ "type": {
43
+ "type": "string",
44
+ "description": "查询语句类型冗余字段,实际数据中可能是 promql/dql,也可能是 default/simple 这类查询模式",
45
+ "enum": [
46
+ "default",
47
+ "simple",
48
+ "dql",
49
+ "promql"
50
+ ]
51
+ },
52
+ "promqlCode": {
53
+ "type": "integer",
54
+ "description": "PromQL 查询顺序编号"
37
55
  }
38
56
  }
39
57
  }
40
58
  },
41
59
  "additionalProperties": true
42
- }
60
+ }
@@ -4,10 +4,6 @@
4
4
  "title": "ChartTimeSettings",
5
5
  "description": "图表时间相关配置完整结构。",
6
6
  "type": "object",
7
- "required": [
8
- "timeInterval",
9
- "fixedTime"
10
- ],
11
7
  "properties": {
12
8
  "timeInterval": {
13
9
  "type": "string",
@@ -44,4 +40,4 @@
44
40
  "$ref": "settings-fixed-time-schema.json"
45
41
  }
46
42
  }
47
- }
43
+ }
@@ -4,7 +4,9 @@
4
4
  "title": "ChartUnitItemsSettings",
5
5
  "description": "图表单位数据配置",
6
6
  "type": "array",
7
+ "minItems": 2,
7
8
  "maxItems": 2,
9
+ "additionalItems": false,
8
10
  "items": [
9
11
  {
10
12
  "enum": [
@@ -223,4 +225,4 @@
223
225
  ]
224
226
  }
225
227
  ]
226
- }
228
+ }
@@ -28,8 +28,7 @@
28
28
  "required": [
29
29
  "name",
30
30
  "key",
31
- "unit",
32
- ""
31
+ "unit"
33
32
  ],
34
33
  "properties": {
35
34
  "name": {
@@ -57,4 +56,4 @@
57
56
  }
58
57
  }
59
58
  }
60
- }
59
+ }
@@ -0,0 +1,57 @@
1
+ import Ajv from 'ajv'
2
+ import { readdirSync, readFileSync } from 'fs'
3
+
4
+ const SCHEMAS_DIRECTORY = './schemas'
5
+
6
+ const args = process.argv.slice(2)
7
+ const schemaFlagIndex = args.indexOf('--schema')
8
+ const schemaId = schemaFlagIndex >= 0 ? args[schemaFlagIndex + 1] : 'dashboard-schema.json'
9
+ const jsonPaths =
10
+ schemaFlagIndex >= 0 ? args.filter((_, index) => index !== schemaFlagIndex && index !== schemaFlagIndex + 1) : args
11
+
12
+ if (jsonPaths.length === 0) {
13
+ console.error('Usage: node scripts/validate-file.mjs <json-path...> [--schema <schema-id>]')
14
+ process.exit(1)
15
+ }
16
+
17
+ const ajv = new Ajv({ allErrors: true })
18
+
19
+ forEachFile(SCHEMAS_DIRECTORY, (schemaPath) => {
20
+ if (!schemaPath.endsWith('.json')) return
21
+ ajv.addSchema(readJson(schemaPath))
22
+ })
23
+
24
+ let hasError = false
25
+
26
+ for (const jsonPath of jsonPaths) {
27
+ const valid = ajv.validate(schemaId, readJson(jsonPath))
28
+
29
+ if (valid) {
30
+ console.log(`✅ ${jsonPath} is valid against ${schemaId}`)
31
+ continue
32
+ }
33
+
34
+ hasError = true
35
+ console.log(`❌ ${jsonPath} is not valid against ${schemaId}:`)
36
+ for (const error of ajv.errors || []) {
37
+ const instancePath = error.instancePath || '/'
38
+ console.log(`- ${instancePath} ${error.message}`)
39
+ }
40
+ }
41
+
42
+ process.exit(hasError ? 1 : 0)
43
+
44
+ function forEachFile(directoryPath, callback) {
45
+ for (const entry of readdirSync(directoryPath, { withFileTypes: true })) {
46
+ const entryPath = `${directoryPath}/${entry.name}`
47
+ if (entry.isFile()) {
48
+ callback(entryPath)
49
+ } else {
50
+ forEachFile(entryPath, callback)
51
+ }
52
+ }
53
+ }
54
+
55
+ function readJson(filePath) {
56
+ return JSON.parse(readFileSync(filePath, 'utf8'))
57
+ }
@@ -0,0 +1,102 @@
1
+ ---
2
+ name: grafana-to-guance-dashboard
3
+ description: Convert Grafana dashboard JSON into Guance dashboard JSON in this repository. Use when the user wants to convert a Grafana dashboard file, adjust mapping logic for panels or variables, preserve settings, groups, and vars as much as possible, validate generated Guance dashboard JSON against local schemas, or debug why a Grafana dashboard does not convert cleanly.
4
+ ---
5
+
6
+ # Grafana To Guance Dashboard
7
+
8
+ ## Overview
9
+
10
+ Use this skill when working on Grafana dashboard to Guance dashboard conversion in this repository.
11
+
12
+ This skill ships its own standalone converter script under `skills/grafana-to-guance-dashboard/scripts/`. Use that script first. Only inspect the older repository converter when the user explicitly wants comparison or historical behavior.
13
+
14
+ ## Core Workflow
15
+
16
+ 1. Identify the input Grafana dashboard and output path.
17
+ 2. Run the standalone skill script.
18
+ 3. Validate the generated Guance dashboard against local schemas.
19
+ 4. If conversion gaps remain, patch the standalone skill script and re-run validation.
20
+ 5. Only inspect the older repository converter if the user asks to compare outputs.
21
+
22
+ ## Commands
23
+
24
+ Use this command from the repository root.
25
+
26
+ ```bash
27
+ # Convert a Grafana dashboard JSON to Guance JSON
28
+ node skills/grafana-to-guance-dashboard/scripts/convert-grafana-dashboard.mjs \
29
+ --input path/to/grafana-dashboard.json \
30
+ --output path/to/guance-dashboard.json \
31
+ --validate
32
+
33
+ # Convert and normalize PromQL metric names toward Guance measurement:field style
34
+ node skills/grafana-to-guance-dashboard/scripts/convert-grafana-dashboard.mjs \
35
+ --input path/to/grafana-dashboard.json \
36
+ --output path/to/guance-dashboard.guance-promql.json \
37
+ --validate \
38
+ --guance-promql-compatible
39
+
40
+ # Convert and keep original Grafana metadata under extend.grafana for debugging
41
+ node skills/grafana-to-guance-dashboard/scripts/convert-grafana-dashboard.mjs \
42
+ --input path/to/grafana-dashboard.json \
43
+ --output path/to/guance-dashboard.keep-meta.json \
44
+ --validate \
45
+ --keep-grafana-meta
46
+ ```
47
+
48
+ ## What The Standalone Skill Converter Supports
49
+
50
+ - Grafana variables of type `query`, `custom`, `textbox`, `constant`, `interval`, and `datasource`
51
+ - Grafana row panels mapped to Guance groups
52
+ - Row collapse state mapped to `dashboardExtend.groupUnfoldStatus`
53
+ - Panel links gathered from panel links, default links, and override links
54
+ - Common panel types:
55
+ - `stat`, `singlestat` -> `singlestat`
56
+ - `timeseries`, `graph` -> `sequence`
57
+ - `barchart` -> `bar`
58
+ - `piechart` -> `pie`
59
+ - `histogram` -> `histogram`
60
+ - `bargauge` -> `toplist`
61
+ - `gauge` -> `gauge`
62
+ - `table` -> `table`
63
+ - `text` -> `text`
64
+ - `heatmap` -> `heatmap`
65
+ - `treemap` -> `treemap`
66
+ - Query extraction from Grafana `targets[]` using `expr`, `query`, or `queryText`
67
+ - Datasource-aware query classification for Prometheus-like and SQL-like targets
68
+ - `guance-guance-datasource` targets default to `dql`, but explicit `qtype: "promql"` is preserved as `promql`
69
+ - Optional `--guance-promql-compatible` mode to rewrite PromQL metric selectors from `metric_name` toward Guance `measurement:field` style
70
+ - Default output omits raw `extend.grafana` metadata; pass `--keep-grafana-meta` only when debugging conversion fidelity
71
+ - Variable replacement from Grafana `$var` / `${var}` to Guance `#{var}`
72
+ - Settings extraction from both newer `fieldConfig` / `options` panels and older Grafana `graph` / `singlestat` fields
73
+ - Settings mapping for thresholds, value mappings, legend, units, decimals, min, max, stack mode, null handling, panel links, and common chart display settings
74
+ - Transformation-aware table mapping for `organize`, `filterFieldsByName`, and `filterByValue`
75
+ - Extra appearance metadata preserved under `extend.grafana` and `settings.extend.appearance`, including line width, fill opacity, point mode, stat text/color mode, reduce calcs, and gauge display hints
76
+
77
+ ## Known Limits
78
+
79
+ - The converter is still Prometheus/PromQL-oriented for query extraction.
80
+ - Plugin-specific Grafana options are converted heuristically, not losslessly.
81
+ - Unsupported panel types are filtered out unless the mapping table is extended.
82
+ - Complex transformations and non-standard datasource payloads may still need manual cleanup.
83
+
84
+ When conversion fails or output is incomplete, read [references/converter-notes.md](references/converter-notes.md).
85
+
86
+ ## Editing Rules
87
+
88
+ - Prefer patching `skills/grafana-to-guance-dashboard/scripts/convert-grafana-dashboard.mjs` for conversion behavior.
89
+ - Only change schemas when the generated Guance JSON is valid real data but the schema is too strict.
90
+ - Keep validation green:
91
+ - `npm run validate`
92
+ - `npm run validate:dashboard`
93
+ - When adding support for a new Grafana panel type, update the standalone script's panel type map first, then validate an example dashboard.
94
+
95
+ ## Typical Requests This Skill Should Handle
96
+
97
+ - "Convert this Grafana dashboard JSON to Guance format."
98
+ - "Why did this Grafana panel disappear after conversion?"
99
+ - "Add support for Grafana panel type `xyz`."
100
+ - "Map Grafana variables into Guance vars correctly."
101
+ - "Validate the converted Guance dashboard against the local schema."
102
+ - "Compare a Grafana dashboard and generated Guance dashboard to find missing panels."
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Grafana to Guance"
3
+ short_description: "Convert Grafana dashboards to Guance format"
4
+ default_prompt: "Use $grafana-to-guance-dashboard to convert a Grafana dashboard JSON into a Guance dashboard and validate the result."
@@ -0,0 +1,134 @@
1
+ # Converter Notes
2
+
3
+ ## Skill Files
4
+
5
+ - `skills/grafana-to-guance-dashboard/scripts/convert-grafana-dashboard.mjs`: standalone converter shipped by this skill
6
+ - `schemas/dashboard-schema.json`: Guance dashboard schema entrypoint
7
+
8
+ ## Current Mapping Notes
9
+
10
+ ### Variables
11
+
12
+ - Supported Grafana variable types:
13
+ - `query`
14
+ - `custom`
15
+ - Variable mapping:
16
+ - `query` -> `PROMQL_QUERY`
17
+ - `custom` -> `CUSTOM_LIST`
18
+
19
+ Additional Grafana variable types such as `textbox`, `constant`, `interval`, and `datasource` are converted into Guance custom-list style variables by the standalone script.
20
+
21
+ The standalone script also preserves extra variable metadata such as `refresh`, `skipUrlSync`, `sort`, `description`, and raw option lists under `var.extend`.
22
+
23
+ ### Panels
24
+
25
+ Panel type mapping currently lives in `convert-grafana-dashboard.mjs`.
26
+
27
+ If a Grafana panel type is missing, the panel is filtered out before conversion. Add the panel type to the standalone script map before debugging deeper.
28
+
29
+ By default, the converter does not emit raw `extend.grafana` metadata in the generated Guance dashboard. Use `--keep-grafana-meta` only when you need source-level debugging context.
30
+
31
+ ### Queries
32
+
33
+ The converter pulls query text from the first defined field among:
34
+
35
+ 1. `target.expr`
36
+ 2. `target.query`
37
+ 3. `target.queryText`
38
+ 4. `target.expression`
39
+ 5. `target.rawSql`
40
+
41
+ Generated Guance queries default to PromQL-style output unless the query looks like DQL:
42
+
43
+ ```json
44
+ {
45
+ "datasource": "dataflux",
46
+ "qtype": "promql",
47
+ "type": "sequence",
48
+ "query": {
49
+ "q": "...",
50
+ "type": "promql",
51
+ "code": "a",
52
+ "promqlCode": 1
53
+ }
54
+ }
55
+ ```
56
+
57
+ Variable replacement is intentionally conservative:
58
+
59
+ - only known Grafana dashboard variables are rewritten from `$var` / `${var}` to `#{var}`
60
+ - Grafana built-ins such as `${__from}` and `${__to}` are preserved
61
+ - unknown template expressions such as JavaScript local variables in text panels stay unchanged, for example `${hotcall}`
62
+
63
+ Query classification is datasource-aware:
64
+
65
+ - Prometheus-like datasources stay `promql`
66
+ - SQL-like datasources such as MySQL/Postgres/MSSQL are emitted as `dql`
67
+ - `guance-guance-datasource` defaults to `dql`
68
+ - if a `guance-guance-datasource` target explicitly sets `qtype: "promql"`, that explicit PromQL mode wins
69
+ - the generated `query.type` now follows the same classification instead of falling back to `simple`
70
+
71
+ Guance PromQL compatibility mode:
72
+
73
+ - pass `--guance-promql-compatible` to rewrite PromQL metric selectors from `metric_name` to `measurement:field`
74
+ - the rewrite is conservative and only applies to metric selector tokens outside label braces
75
+ - label keys such as `app_name` and grouping keys such as `by (app_name)` are preserved
76
+ - keep this mode opt-in, because some dashboards may already target Guance-native metric names
77
+
78
+ ### Layout
79
+
80
+ Grafana `gridPos` is not copied directly.
81
+
82
+ - `x` and `w` are kept close to Grafana values
83
+ - `y` and `h` are scaled into a Guance-friendly layout ratio
84
+
85
+ If the final dashboard looks vertically misaligned, inspect the layout conversion helpers first.
86
+
87
+ ## Debug Checklist
88
+
89
+ When output is wrong:
90
+
91
+ 1. Confirm the panel type is in the standalone script panel map.
92
+ 2. Confirm the panel has `gridPos`.
93
+ 3. Confirm the panel has usable `targets`.
94
+ 4. Check whether the query lives in `expr`, `query`, or `queryText`.
95
+ 5. Check whether row panels are collapsed, because collapsed and expanded rows are handled differently.
96
+ 6. Validate the generated JSON with:
97
+
98
+ ```bash
99
+ node scripts/validate-file.mjs path/to/output.json
100
+ ```
101
+
102
+ ## Settings Conversion
103
+
104
+ The standalone script attempts to convert:
105
+
106
+ - thresholds -> Guance `levels`
107
+ - Grafana value maps and range maps -> Guance `mappings`
108
+ - table override mappings -> Guance `valMappings`
109
+ - legend placement and legend values, including older Grafana `legend.current/avg/min/max/total`
110
+ - units, decimals, min, max from both newer and older Grafana panel formats
111
+ - stacking and connect-nulls behavior from both newer and older Grafana panel formats
112
+ - table column organize / rename / exclude / order transformations
113
+ - panel links and field links into `extend.links`
114
+ - appearance metadata into `settings.extend.appearance`, including:
115
+ - `lineWidth`
116
+ - `fillOpacity`
117
+ - `pointMode`
118
+ - `graphMode`
119
+ - `colorMode`
120
+ - `textMode`
121
+ - `reduceCalcs`
122
+ - `gaugeMode`
123
+
124
+ This is heuristic conversion. For plugin-specific panels, validate the generated JSON and then refine the script with a real sample.
125
+
126
+ ## Safe Extension Pattern
127
+
128
+ When adding support for a new panel type:
129
+
130
+ 1. Add the Grafana panel type to the standalone script panel map.
131
+ 2. Decide the Guance chart type target.
132
+ 3. Add any special-case settings generation in the standalone script.
133
+ 4. Convert a real dashboard containing that panel.
134
+ 5. Run `npm run validate`.