@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
@@ -1,13 +1,4 @@
1
- import type {
2
- DashboardData as GuanceDashboardType,
3
- ChartVarsSettings,
4
- ChartVarsItem,
5
- ChartData as GuanceChartData,
6
- ChartType1 as GuanceChartType,
7
- ChartQueries as GuanceChartQueries,
8
- ChartQueryItem as GuanceChartQueryItem,
9
- ChartSettings as GuanceChartSettings,
10
- } from '../generated/dashboardCharts'
1
+ import type { DashboardData as GuanceDashboardType } from '../generated/dashboardCharts'
11
2
  import type {
12
3
  DashboardData as GrafanaDashboardType,
13
4
  VariableModel,
@@ -15,323 +6,18 @@ import type {
15
6
  RowPanel,
16
7
  } from './grafana-dashbord'
17
8
 
18
- const grafanaPanelTypeToGuanceChartMap: { [key: string]: GuanceChartType } = {
19
- stat: 'singlestat',
20
- singlestat: 'singlestat',
21
- barchart: 'bar',
22
- timeseries: 'sequence',
23
- graph: 'sequence',
24
- piechart: 'pie',
25
- histogram: 'histogram',
26
- bargauge: 'toplist',
27
- gauge: 'gauge',
28
- table: 'table',
29
- text: 'text',
30
- heatmap: 'heatmap',
31
- treemap: 'treemap',
32
- }
33
-
34
- const GRAFANA_KEYWORKD = ['__interval']
35
-
36
- const VARIABLE_MAP = {
37
- query: 'PROMQL_QUERY',
38
- custom: 'CUSTOM_LIST',
39
- } as const
40
-
41
- const VARIABLE_DATASOURCE_MAP = {
42
- query: 'dataflux',
43
- custom: 'custom',
44
- } as const
45
-
46
- function isSupportedVariableType(type: string): type is keyof typeof VARIABLE_MAP {
47
- return Object.prototype.hasOwnProperty.call(VARIABLE_MAP, type)
48
- }
49
-
50
- function replaceVariableStr(grafanaExpr: string): string {
51
- return grafanaExpr.replace(/\$\{?([\d_\w]+)\}?/g, function (match, variable) {
52
- if (GRAFANA_KEYWORKD.indexOf(variable) > -1) return match
53
- return `#{${variable}}`
54
- })
55
- }
56
-
57
- function sortPanelItemsByRowCol(panels: Panel[]): Panel[] {
58
- return panels.slice(0).sort(function (panelA, panelB) {
59
- const { gridPos: posA } = panelA
60
- const { gridPos: posB } = panelB
61
- if (!posA || !posB) return -1
62
- if (posA.y === posB.y && posA.x === posB.x && posA.w > posB.w) {
63
- return -1
64
- }
65
- if (posA.y === posB.y && posA.x === posB.x) {
66
- return 0
67
- }
68
-
69
- if (posA.y > posB.y || (posA.y === posB.y && posA.x > posB.x)) {
70
- return 1
71
- }
72
-
73
- return -1
74
- })
75
- }
76
-
77
- function tenToTweenty(source: number = 1): string {
78
- const numArr: number[] = []
79
- source--
80
- do {
81
- numArr.push(source % 26)
82
- source = Math.floor(source / 26)
83
- } while (source > 0)
84
- return numArr
85
- .reverse()
86
- .map((item: number, index: number) => {
87
- return String.fromCharCode(item + 97 + (index === numArr.length - 1 ? 0 : -1))
88
- })
89
- .join('')
90
- .toLowerCase()
91
- }
92
-
93
- function getGridH(h: number, rowHeight: number, margin: number) {
94
- return Math.round(h * rowHeight + Math.max(0, 2 * (h - 1)) * margin)
95
- }
96
-
97
- function getGuanceHByGrafanaH(granfanH: number) {
98
- return (getGridH(granfanH, 30, 4) + 10) / 20
99
- }
100
-
101
- function covertPanelToGuanceChart(grafanaPanel: Panel, rowPanel: RowPanel | undefined): GuanceChartData {
102
- const { gridPos, title, type, targets, options } = grafanaPanel
103
- const chartType: GuanceChartType = grafanaPanelTypeToGuanceChartMap[type]
104
- let pos = {
105
- x: gridPos!.x,
106
- w: gridPos!.w,
107
- y: gridPos!.y,
108
- h: gridPos!.h,
109
- }
110
-
111
- if (rowPanel) {
112
- const { gridPos: rowGridPos } = rowPanel
113
- if (rowGridPos && gridPos && !rowPanel.collapsed) {
114
- pos = {
115
- x: gridPos.x,
116
- w: gridPos.w,
117
- y: gridPos.y - rowGridPos.y,
118
- h: gridPos.h,
119
- }
120
- }
121
- }
122
-
123
- const queries: GuanceChartQueries = []
124
- if (targets && targets.length) {
125
- let currentIndex = 0
126
- targets.forEach((_target) => {
127
- const queryStr: string | unknown = _target.expr || _target.query || _target.queryText
128
- if (!queryStr) return
129
-
130
- currentIndex++
131
- const queryItem: GuanceChartQueryItem = {
132
- datasource: 'dataflux',
133
- qtype: 'promql',
134
- type: chartType,
135
- query: {
136
- q: replaceVariableStr(queryStr as string),
137
- type: 'promql',
138
- code: tenToTweenty(currentIndex),
139
- promqlCode: currentIndex,
140
- },
141
- }
142
- queries.push(queryItem)
143
- })
144
- }
145
-
146
- let settings: GuanceChartSettings = {}
147
- if (options) {
148
- switch (chartType) {
149
- case 'text':
150
- queries.push({
151
- query: {
152
- content: options.content,
153
- },
154
- })
155
- break
156
- case 'toplist':
157
- settings = {
158
- showTopSize: true,
159
- chartType: 'bar',
160
- }
161
- break
162
- default:
163
- break
164
- }
165
- }
166
-
167
- return {
168
- extend: {
169
- settings: settings,
170
- },
171
- group: {
172
- name: rowPanel ? rowPanel.title : null,
173
- },
174
- pos: {
175
- x: pos.x,
176
- y: getGuanceHByGrafanaH(pos.y),
177
- h: getGuanceHByGrafanaH(pos.h),
178
- w: pos.w,
179
- },
180
- name: replaceVariableStr(title || ''),
181
- queries: queries,
182
- type: chartType,
183
- }
184
- }
185
-
186
- function covertPanelsToCharts(grafanaPanelData: Panel[], rowPanel: RowPanel | undefined): GuanceChartData[] {
187
- const guanceCharts: GuanceChartData[] = []
188
- grafanaPanelData.forEach((grafanaPanel) => {
189
- if (!grafanaPanel.gridPos) return
190
- guanceCharts.push(covertPanelToGuanceChart(grafanaPanel, rowPanel))
191
- })
192
- return guanceCharts
193
- }
9
+ // This script is the shared conversion source for the published API and CLI.
10
+ // Keep it thin and delegate to the maintained converter implementation.
11
+ // @ts-ignore
12
+ import { convertDashboard } from '../../skills/grafana-to-guance-dashboard/scripts/convert-grafana-dashboard.mjs'
194
13
 
195
14
  export function covert(grafanaData: GrafanaDashboardType): GuanceDashboardType {
196
- const covertGuanceResult: GuanceDashboardType = {}
197
- covertGuanceResult.title = grafanaData.title
198
-
199
- const guanceVars: ChartVarsSettings = []
200
- grafanaData.templating?.list?.forEach((_variable: VariableModel, index: number) => {
201
- const { current, type, allValue } = _variable
202
- const variableType = String(type)
203
- if (!isSupportedVariableType(variableType)) return
204
-
205
- let defaultVal = {
206
- label: '',
207
- value: '',
208
- }
209
-
210
- if (current) {
211
- let labels: string[] = []
212
- let values: string[] = []
213
- if (Array.isArray(current.text)) {
214
- labels = current.text
215
- } else if (typeof current.text === 'string') {
216
- labels = [current.text]
217
- }
218
- if (Array.isArray(current.value)) {
219
- values = current.value
220
- } else if (typeof current.value === 'string') {
221
- values = [current.value]
222
- }
223
-
224
- labels = labels.map((label) => {
225
- if (label === 'All') {
226
- if (allValue === '.*') {
227
- return '*'
228
- }
229
- return 'all values'
230
- }
231
- return label
232
- })
233
-
234
- values = values.map((value) => {
235
- if (value === '$__all') {
236
- if (allValue === '.*') {
237
- return '*'
238
- }
239
- return '__all__'
240
- }
241
- return value
242
- })
243
-
244
- defaultVal = {
245
- label: labels.join(','),
246
- value: values.join(','),
247
- }
248
- }
249
-
250
- let value = _variable.query
251
- if (value && typeof value === 'object' && value.query) {
252
- value = replaceVariableStr(value.query as string)
253
- } else if (value && typeof value === 'string') {
254
- value = replaceVariableStr(_variable.query as string)
255
- } else {
256
- return
257
- }
258
-
259
- const guanceVariableItem: ChartVarsItem = {
260
- type: VARIABLE_MAP[variableType],
261
- datasource: VARIABLE_DATASOURCE_MAP[variableType],
262
- name: _variable.label || _variable.name || '',
263
- seq: index,
264
- hide: _variable.hide ? 1 : 0,
265
- multiple: _variable.multi !== undefined ? _variable.multi : true,
266
- includeStar: _variable.includeAll !== undefined ? _variable.includeAll : true,
267
- valueSort: 'desc',
268
- code: _variable.name,
269
- definition: {
270
- value: value,
271
- defaultVal: defaultVal,
272
- },
273
- }
274
- guanceVars.push(guanceVariableItem)
275
- })
276
-
277
- const guanceGroups: Array<{ name?: string }> = []
278
- const guanceExpand: { [key: string]: boolean } = {}
279
- const guanceCharts: GuanceChartData[] = []
280
-
281
- let lastRowPanel: RowPanel | undefined
282
- let lastPanels: Panel[] = []
283
- let grafanaCharts =
284
- grafanaData.panels?.filter(
285
- (_panel: Panel | RowPanel) => _panel.type === 'row' || grafanaPanelTypeToGuanceChartMap[_panel.type]
286
- ) || []
287
-
288
- grafanaCharts = sortPanelItemsByRowCol(grafanaCharts)
289
- grafanaCharts.forEach((_panel) => {
290
- if (_panel.type === 'row') {
291
- const _rowPanel = _panel as RowPanel
292
-
293
- if (_rowPanel.title) {
294
- guanceGroups.push({
295
- name: _rowPanel.title,
296
- })
297
- guanceExpand[_rowPanel.title] = !_rowPanel.collapsed
298
- }
299
-
300
- if (lastPanels.length) {
301
- guanceCharts.push(...covertPanelsToCharts(lastPanels, lastRowPanel))
302
- lastPanels = []
303
- lastRowPanel = undefined
304
- }
305
-
306
- if (_rowPanel.collapsed) {
307
- const subPanels =
308
- _rowPanel.panels?.filter(
309
- (_childPanel: Panel | RowPanel) =>
310
- _childPanel.type === 'row' || grafanaPanelTypeToGuanceChartMap[_childPanel.type]
311
- ) || []
312
- guanceCharts.push(...covertPanelsToCharts(subPanels, _rowPanel))
313
- } else {
314
- lastRowPanel = _rowPanel
315
- }
316
- } else {
317
- lastPanels.push(_panel)
318
- }
319
- })
320
-
321
- if (lastPanels.length) {
322
- guanceCharts.push(...covertPanelsToCharts(lastPanels, lastRowPanel))
323
- }
324
-
325
- covertGuanceResult.dashboardExtend = {
326
- groupUnfoldStatus: guanceExpand,
327
- }
328
- covertGuanceResult.main = {
329
- vars: guanceVars,
330
- charts: guanceCharts,
331
- groups: guanceGroups,
332
- }
333
-
334
- return covertGuanceResult
15
+ return convertDashboard(grafanaData) as GuanceDashboardType
335
16
  }
336
17
 
337
- export type { GrafanaDashboardType, Panel as GrafanaPanel, RowPanel as GrafanaRowPanel, VariableModel as GrafanaVariableModel }
18
+ export type {
19
+ GrafanaDashboardType,
20
+ Panel as GrafanaPanel,
21
+ RowPanel as GrafanaRowPanel,
22
+ VariableModel as GrafanaVariableModel,
23
+ }
@@ -7,43 +7,66 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import * as fs from 'fs';
11
- import * as path from 'path';
10
+ import fs from 'fs';
11
+ import path from 'path';
12
12
  import yargs from 'yargs';
13
- import { covert } from './grafana-covert-to-guance-core.js';
13
+ // @ts-ignore
14
+ import { convertDashboard, validateDashboardFile, } from '../../skills/grafana-to-guance-dashboard/scripts/convert-grafana-dashboard.mjs';
14
15
  export function run(args) {
15
16
  return __awaiter(this, void 0, void 0, function* () {
16
17
  const { argv } = yargs(args)
17
18
  .usage('Convert grafana dashboard json template to guance dashboard json template.')
18
- .demand('d')
19
- .alias('d', 'input')
20
- .describe('d', 'path to grafana dashboard json file path')
21
- .coerce('d', (d) => {
22
- const resolved = d && path.resolve(d);
23
- if (fs.existsSync(resolved) && /\.json$/.test(resolved)) {
24
- return resolved;
25
- }
26
- throw new Error(`Input Grafana JSON File "${d}" is not a JSON!`);
19
+ .option('d', {
20
+ alias: 'input',
21
+ type: 'string',
22
+ demandOption: true,
23
+ describe: 'path to grafana dashboard json file path',
24
+ coerce: (value) => {
25
+ const resolved = value && path.resolve(value);
26
+ if (fs.existsSync(resolved) && /\.json$/.test(resolved)) {
27
+ return resolved;
28
+ }
29
+ throw new Error(`Input Grafana JSON File "${value}" is not a JSON!`);
30
+ },
27
31
  })
28
- .alias('o', 'out')
29
- .describe('o', 'path to output json file path')
30
- .default('o', path.resolve(path.join('.', 'guance-dashboard.json')))
31
- .coerce('o', (o) => path.resolve(o));
32
+ .option('o', {
33
+ alias: 'out',
34
+ type: 'string',
35
+ default: path.resolve(path.join('.', 'guance-dashboard.json')),
36
+ describe: 'path to output json file path',
37
+ coerce: (value) => path.resolve(value),
38
+ })
39
+ .option('validate', {
40
+ type: 'boolean',
41
+ default: false,
42
+ describe: 'validate generated dashboard against schema',
43
+ })
44
+ .option('schema', {
45
+ type: 'string',
46
+ default: 'dashboard-schema.json',
47
+ describe: 'schema file name under schemas/',
48
+ })
49
+ .option('guance-promql-compatible', {
50
+ type: 'boolean',
51
+ default: false,
52
+ describe: 'rewrite PromQL metric names to Guance compatible measurement:field form',
53
+ })
54
+ .option('keep-grafana-meta', {
55
+ type: 'boolean',
56
+ default: false,
57
+ describe: 'keep source grafana metadata under extend.grafana',
58
+ });
32
59
  const grafanaJsonPath = argv.d;
33
60
  const outGuanceJsonPath = argv.o;
34
- try {
35
- const grafanaJSONData = JSON.parse(fs.readFileSync(grafanaJsonPath, 'utf-8'));
36
- const covertResult = covert(grafanaJSONData);
37
- // 确保目录存在
38
- const dir = path.dirname(outGuanceJsonPath);
39
- if (!fs.existsSync(dir)) {
40
- fs.mkdirSync(dir, { recursive: true }); // recursive: true 确保递归创建目录
41
- }
42
- fs.writeFileSync(outGuanceJsonPath, JSON.stringify(covertResult), 'utf-8');
43
- }
44
- catch (err) {
45
- throw new Error(err);
61
+ const grafanaJSONData = JSON.parse(fs.readFileSync(grafanaJsonPath, 'utf-8'));
62
+ const convertResult = convertDashboard(grafanaJSONData, {
63
+ guancePromqlCompatible: Boolean(argv.guancePromqlCompatible),
64
+ keepGrafanaMeta: Boolean(argv.keepGrafanaMeta),
65
+ });
66
+ fs.mkdirSync(path.dirname(outGuanceJsonPath), { recursive: true });
67
+ fs.writeFileSync(outGuanceJsonPath, `${JSON.stringify(convertResult, null, 2)}\n`, 'utf-8');
68
+ if (argv.validate) {
69
+ validateDashboardFile(outGuanceJsonPath, String(argv.schema));
46
70
  }
47
71
  });
48
72
  }
49
- // console.log(JSON.stringify(result, null, 2))
@@ -1,41 +1,69 @@
1
- import * as fs from 'fs'
2
- import * as path from 'path'
1
+ import fs from 'fs'
2
+ import path from 'path'
3
3
  import yargs from 'yargs'
4
- import { covert } from './grafana-covert-to-guance-core.js'
4
+ // @ts-ignore
5
+ import {
6
+ convertDashboard,
7
+ validateDashboardFile,
8
+ } from '../../skills/grafana-to-guance-dashboard/scripts/convert-grafana-dashboard.mjs'
5
9
 
6
- export async function run(args) {
10
+ export async function run(args: string[]) {
7
11
  const { argv } = yargs(args)
8
12
  .usage('Convert grafana dashboard json template to guance dashboard json template.')
9
-
10
- .demand('d')
11
- .alias('d', 'input')
12
- .describe('d', 'path to grafana dashboard json file path')
13
- .coerce('d', (d) => {
14
- const resolved = d && path.resolve(d)
15
- if (fs.existsSync(resolved) && /\.json$/.test(resolved)) {
16
- return resolved
17
- }
18
- throw new Error(`Input Grafana JSON File "${d}" is not a JSON!`)
13
+ .option('d', {
14
+ alias: 'input',
15
+ type: 'string',
16
+ demandOption: true,
17
+ describe: 'path to grafana dashboard json file path',
18
+ coerce: (value: string) => {
19
+ const resolved = value && path.resolve(value)
20
+ if (fs.existsSync(resolved) && /\.json$/.test(resolved)) {
21
+ return resolved
22
+ }
23
+ throw new Error(`Input Grafana JSON File "${value}" is not a JSON!`)
24
+ },
25
+ })
26
+ .option('o', {
27
+ alias: 'out',
28
+ type: 'string',
29
+ default: path.resolve(path.join('.', 'guance-dashboard.json')),
30
+ describe: 'path to output json file path',
31
+ coerce: (value: string) => path.resolve(value),
32
+ })
33
+ .option('validate', {
34
+ type: 'boolean',
35
+ default: false,
36
+ describe: 'validate generated dashboard against schema',
37
+ })
38
+ .option('schema', {
39
+ type: 'string',
40
+ default: 'dashboard-schema.json',
41
+ describe: 'schema file name under schemas/',
19
42
  })
43
+ .option('guance-promql-compatible', {
44
+ type: 'boolean',
45
+ default: false,
46
+ describe: 'rewrite PromQL metric names to Guance compatible measurement:field form',
47
+ })
48
+ .option('keep-grafana-meta', {
49
+ type: 'boolean',
50
+ default: false,
51
+ describe: 'keep source grafana metadata under extend.grafana',
52
+ })
53
+
54
+ const grafanaJsonPath = argv.d as string
55
+ const outGuanceJsonPath = argv.o as string
56
+
57
+ const grafanaJSONData = JSON.parse(fs.readFileSync(grafanaJsonPath, 'utf-8'))
58
+ const convertResult = convertDashboard(grafanaJSONData, {
59
+ guancePromqlCompatible: Boolean(argv.guancePromqlCompatible),
60
+ keepGrafanaMeta: Boolean(argv.keepGrafanaMeta),
61
+ })
20
62
 
21
- .alias('o', 'out')
22
- .describe('o', 'path to output json file path')
23
- .default('o', path.resolve(path.join('.', 'guance-dashboard.json')))
24
- .coerce('o', (o) => path.resolve(o))
25
- const grafanaJsonPath = argv.d
26
- const outGuanceJsonPath = argv.o
63
+ fs.mkdirSync(path.dirname(outGuanceJsonPath), { recursive: true })
64
+ fs.writeFileSync(outGuanceJsonPath, `${JSON.stringify(convertResult, null, 2)}\n`, 'utf-8')
27
65
 
28
- try {
29
- const grafanaJSONData = JSON.parse(fs.readFileSync(grafanaJsonPath, 'utf-8'))
30
- const covertResult = covert(grafanaJSONData)
31
- // 确保目录存在
32
- const dir = path.dirname(outGuanceJsonPath)
33
- if (!fs.existsSync(dir)) {
34
- fs.mkdirSync(dir, { recursive: true }) // recursive: true 确保递归创建目录
35
- }
36
- fs.writeFileSync(outGuanceJsonPath, JSON.stringify(covertResult), 'utf-8')
37
- } catch (err) {
38
- throw new Error(err)
66
+ if (argv.validate) {
67
+ validateDashboardFile(outGuanceJsonPath, String(argv.schema))
39
68
  }
40
69
  }
41
- // console.log(JSON.stringify(result, null, 2))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudcare/guance-front-tools",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -24,7 +24,8 @@
24
24
  "generate": "node scripts/generate.mjs",
25
25
  "test": "node --test test/*.test.mjs",
26
26
  "format": "prettier -c .",
27
- "validate": "node scripts/validate.mjs",
27
+ "validate": "node scripts/validate.mjs && npm run validate:dashboard",
28
+ "validate:dashboard": "node scripts/validate-file.mjs guance-dashboard.json guance-all-charts.json",
28
29
  "prepare": "npm run build"
29
30
  },
30
31
  "devDependencies": {
@@ -37,7 +38,7 @@
37
38
  "@types/node": "^12.20.55"
38
39
  },
39
40
  "engines": {
40
- "node": ">=12.7.0"
41
+ "node": ">=18.0.0"
41
42
  },
42
43
  "author": "",
43
44
  "license": "ISC",
@@ -16,6 +16,9 @@
16
16
  "type": "object",
17
17
  "additionalProperties": true,
18
18
  "properties": {
19
+ "links": {
20
+ "$ref": "common/chart-links-schema.json"
21
+ },
19
22
  "settings": {
20
23
  "$ref": "settings/settings-schema.json"
21
24
  }
@@ -54,18 +57,18 @@
54
57
  "properties": {
55
58
  "h": {
56
59
  "description": "图表高度,每行的高度默认为10像素,比如 h 为12, 则实际高度为 12 * 10",
57
- "type": "integer"
60
+ "type": "number"
58
61
  },
59
62
  "w": {
60
- "type": "integer",
63
+ "type": "number",
61
64
  "description": "图表宽度,栅格系统的最大列数为 24, 比如 w为12,则显示宽度则为容器宽度的 1/2 倍 "
62
65
  },
63
66
  "x": {
64
- "type": "integer",
67
+ "type": "number",
65
68
  "description": "图表距离容器的水平距离,栅格系统的最大列数为 24, 比如 x为12,则图表距离容器左边的水平距离为容器宽度 1/2 倍 "
66
69
  },
67
70
  "y": {
68
- "type": "integer",
71
+ "type": "number",
69
72
  "description": "图表距离容器垂直距离,每行的高度默认为10像素,比如 y为12, 则实际高度为 12 * 10"
70
73
  }
71
74
  }
@@ -78,4 +81,4 @@
78
81
  "$ref": "query/queries-schema.json"
79
82
  }
80
83
  }
81
- }
84
+ }
@@ -0,0 +1,48 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "charts/common/chart-link-item-schema.json",
4
+ "type": "object",
5
+ "description": "图表联动跳转项",
6
+ "required": [
7
+ "url",
8
+ "open",
9
+ "show",
10
+ "type",
11
+ "showChanged"
12
+ ],
13
+ "properties": {
14
+ "url": {
15
+ "type": "string",
16
+ "description": "跳转地址"
17
+ },
18
+ "open": {
19
+ "type": "string",
20
+ "description": "打开方式",
21
+ "enum": [
22
+ "newWin",
23
+ "curWin",
24
+ "drawerWin"
25
+ ]
26
+ },
27
+ "show": {
28
+ "type": "boolean",
29
+ "description": "是否展示"
30
+ },
31
+ "type": {
32
+ "type": "string",
33
+ "description": "跳转类型",
34
+ "enum": [
35
+ "logging",
36
+ "container",
37
+ "processes",
38
+ "tracing",
39
+ "host",
40
+ "custom"
41
+ ]
42
+ },
43
+ "showChanged": {
44
+ "type": "boolean",
45
+ "description": "是否修改过显示状态"
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "charts/common/chart-links-schema.json",
4
+ "type": "array",
5
+ "description": "图表跳转链接列表",
6
+ "items": {
7
+ "$ref": "chart-link-item-schema.json"
8
+ }
9
+ }