From 711d73e1b01d0bc89cf058884b9035db2bf810a8 Mon Sep 17 00:00:00 2001 From: ahinvinith Date: Sat, 6 Apr 2024 08:44:51 +0530 Subject: [PATCH] apache echart fix --- charts/client/Chart.yaml | 2 +- .../templates/configmap-azure-dashboard.yaml | 53 ++++++++++--- .../configmap-bitbucket-dashboard.yaml | 42 ++++++++--- .../templates/configmap-gitea-dashboard.yaml | 55 ++++++++++---- .../templates/configmap-github-dashboard.yaml | 62 ++++++++++++--- .../templates/configmap-gitlab-dashboard.yaml | 41 ++++++++-- .../configmap-kubedata-dashboard.yaml | 71 +++++++++++++++--- .../configmap-kuberhealthy-dashboard.yaml | 7 +- .../templates/configmap-kubviz-dashboard.yaml | 44 ++++++----- .../templates/configmap-trivy-dashboard.yaml | 74 +++++++++--------- grafana/azure-dashboard.json | 54 ++++++++++--- grafana/bitBucket-dashboard.json | 43 ++++++++--- grafana/giTea-dashboard.json | 56 ++++++++++---- grafana/gitHub-dashboard.json | 63 +++++++++++++--- grafana/gitLab-dashboard.json | 42 ++++++++--- grafana/kubeData-dashboard.json | 70 ++++++++++++++--- grafana/kuberhealthy-dashboard.json | 6 +- grafana/kubvizDsahboard.json | 45 ++++++----- grafana/trivy-dashboard.json | 75 ++++++++++--------- 19 files changed, 659 insertions(+), 246 deletions(-) diff --git a/charts/client/Chart.yaml b/charts/client/Chart.yaml index 76896324..9a650535 100644 --- a/charts/client/Chart.yaml +++ b/charts/client/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 1.1.23 +version: 1.1.24 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/charts/client/templates/configmap-azure-dashboard.yaml b/charts/client/templates/configmap-azure-dashboard.yaml index ea290c78..98739e6a 100644 --- a/charts/client/templates/configmap-azure-dashboard.yaml +++ b/charts/client/templates/configmap-azure-dashboard.yaml @@ -26,7 +26,7 @@ data: "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 33, + "id": 53, "links": [], "liveNow": false, "panels": [ @@ -51,11 +51,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "// Check if data.series exists\nif (data.series && data.series.length > 0) {\n const eventTypes = data.series[0].fields[0].values;\n const authors = data.series[0].fields[1].values;\n const repoNames = data.series[0].fields[2].values;\n const total = data.series[0].fields[3].values; // Assuming you have a field named \"Total\"\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n authors.forEach((author, index) => {\n const sourceNode = {\n name: author,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const eventTypeNode = {\n name: eventTypes[index],\n category: 1, // Category for eventType nodes\n symbolSize: 40, // Size for eventType nodes\n };\n\n const repoNode = {\n name: repoNames[index],\n category: 2, // Category for repo nodes\n symbolSize: 30, // Size for repo nodes\n };\n\n const totalNode = {\n name: `Total: ${total[index]}`, // Assuming you have an array \"total\"\n category: 3, // Category for total nodes\n symbolSize: 20, // Size for total nodes\n };\n\n // Ensure source, eventType, repo, and total nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === eventTypeNode.name)) {\n nodes.push(eventTypeNode);\n }\n\n if (!nodes.some((node) => node.name === repoNode.name)) {\n nodes.push(repoNode);\n }\n\n if (!nodes.some((node) => node.name === totalNode.name)) {\n nodes.push(totalNode);\n }\n\n // Create links between author, eventType, repo, and total nodes\n links.push({\n source: author,\n target: eventTypes[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: repoNames[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: totalNode.name,\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Authors',\n },\n {\n name: 'Event Type',\n },\n {\n name: 'Repo Names',\n },\n {\n name: 'Total', // Add a category for \"Total\" nodes\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Authors', 'Event Types', 'Repo Names', 'Total'], // Add \"Total\" to legend data\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: { // Add textStyle property to configure text style\n color: '#000', // Set the text color to a brighter color, such as white (#FFF)\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n\n // Increase the size of arrow marks\n edgeSymbolSize: [12, 12], // Set the arrow size here\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Display a custom message when data is not available\n const option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n\n return option;\n}", + "getOption": "// Check if data.series exists\nif (context.panel.data.series && context.panel.data.series.length > 0) {\n const eventTypes = context.panel.data.series[0].fields[0].values;\n const authors = context.panel.data.series[0].fields[1].values;\n const repoNames = context.panel.data.series[0].fields[2].values;\n const total = context.panel.data.series[0].fields[3].values; // Assuming you have a field named \"Total\"\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n authors.forEach((author, index) => {\n const sourceNode = {\n name: author,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const eventTypeNode = {\n name: eventTypes[index],\n category: 1, // Category for eventType nodes\n symbolSize: 40, // Size for eventType nodes\n };\n\n const repoNode = {\n name: repoNames[index],\n category: 2, // Category for repo nodes\n symbolSize: 30, // Size for repo nodes\n };\n\n const totalNode = {\n name: `Total: ${total[index]}`, // Assuming you have an array \"total\"\n category: 3, // Category for total nodes\n symbolSize: 20, // Size for total nodes\n };\n\n // Ensure source, eventType, repo, and total nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === eventTypeNode.name)) {\n nodes.push(eventTypeNode);\n }\n\n if (!nodes.some((node) => node.name === repoNode.name)) {\n nodes.push(repoNode);\n }\n\n if (!nodes.some((node) => node.name === totalNode.name)) {\n nodes.push(totalNode);\n }\n\n // Create links between author, eventType, repo, and total nodes\n links.push({\n source: author,\n target: eventTypes[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: repoNames[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: totalNode.name,\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Authors',\n },\n {\n name: 'Event Type',\n },\n {\n name: 'Repo Names',\n },\n {\n name: 'Total', // Add a category for \"Total\" nodes\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Authors', 'Event Types', 'Repo Names', 'Total'], // Add \"Total\" to legend data\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: { // Add textStyle property to configure text style\n color: '#000', // Set the text color to a brighter color, such as white (#FFF)\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n\n // Increase the size of arrow marks\n edgeSymbolSize: [12, 12], // Set the arrow size here\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Display a custom message when data is not available\n const option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n\n return option;\n}", "google": { "callback": "gmapReady", "key": "" @@ -66,8 +67,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -110,11 +117,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let options; // Initialize the options variable\n\nif (!data || !data.series || data.series.length === 0 || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n options = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract Author and Push_Events data from the series\n const categories = data.series[0].fields.find((f) => f.name === 'Author').values;\n const pushEvents = data.series[0].fields.find((f) => f.name === 'Push_Events').values;\n\n // Create the ECharts options\n options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Push_Events'],\n orient: 'vertical', // Change the orientation to vertical\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: pushEvents,\n type: 'line',\n areaStyle: {\n color: 'rgba(0, 128, 255, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'blue', // Set the line color\n },\n name: 'Push_Events',\n },\n ],\n };\n}\n\nreturn options;\n", + "getOption": "let options; // Initialize the options variable\n\nif (!context.panel.data || !context.panel.data.series || context.panel.data.series.length === 0 || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n options = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract Author and Push_Events data from the series\n const categories = context.panel.data.series[0].fields.find((f) => f.name === 'Author').values;\n const pushEvents = context.panel.data.series[0].fields.find((f) => f.name === 'Push_Events').values;\n\n // Create the ECharts options\n options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Push_Events'],\n orient: 'vertical', // Change the orientation to vertical\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: pushEvents,\n type: 'line',\n areaStyle: {\n color: 'rgba(0, 128, 255, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'blue', // Set the line color\n },\n name: 'Push_Events',\n },\n ],\n };\n}\n\nreturn options;\n", "google": { "callback": "gmapReady", "key": "" @@ -125,8 +133,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -169,11 +183,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\n// Define a default options object\nconst defaultOptions = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n};\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = defaultOptions;\n} else {\n // Extract Author and Merge_Events data from the series\n const categories = data.series[0].fields.find((f) => f.name === 'Author').values;\n const mergeEvents = data.series[0].fields.find((f) => f.name === 'Merge_Events').values;\n\n // Create the ECharts options\n const options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Merge_Events'],\n orient: 'vertical',\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: mergeEvents,\n type: 'line',\n name: 'Merge_Events',\n areaStyle: {\n color: 'rgba(255, 0, 0, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'red', // Set the line color\n },\n },\n ],\n };\n\n option = options; // Assign the options to the outer variable\n}\n\nreturn option;\n", + "getOption": "let option; // Initialize the option variable\n\n// Define a default options object\nconst defaultOptions = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n};\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = defaultOptions;\n} else {\n // Extract Author and Merge_Events data from the series\n const categories = context.panel.data.series[0].fields.find((f) => f.name === 'Author').values;\n const mergeEvents = context.panel.data.series[0].fields.find((f) => f.name === 'Merge_Events').values;\n\n // Create the ECharts options\n const options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Merge_Events'],\n orient: 'vertical',\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: mergeEvents,\n type: 'line',\n name: 'Merge_Events',\n areaStyle: {\n color: 'rgba(255, 0, 0, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'red', // Set the line color\n },\n },\n ],\n };\n\n option = options; // Assign the options to the outer variable\n}\n\nreturn option;\n", "google": { "callback": "gmapReady", "key": "" @@ -184,8 +199,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -223,7 +244,8 @@ data: "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -293,7 +315,8 @@ data: "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -370,7 +393,8 @@ data: "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null } ] } @@ -426,7 +450,11 @@ data: "templating": { "list": [ { - "current": {}, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, "datasource": { "type": "vertamedia-clickhouse-datasource", "uid": "{{ .Values.datasources.uid }}" @@ -445,7 +473,11 @@ data: "type": "query" }, { - "current": {}, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, "datasource": { "type": "vertamedia-clickhouse-datasource", "uid": "{{ .Values.datasources.uid }}" @@ -473,7 +505,8 @@ data: "timezone": "", "title": "Azure", "uid": "dd66838a-ffda-4de2-944f-1828d1671fc9", - "version": 1, + "version": 2, "weekStart": "" } + {{- end }} \ No newline at end of file diff --git a/charts/client/templates/configmap-bitbucket-dashboard.yaml b/charts/client/templates/configmap-bitbucket-dashboard.yaml index fde60b9f..3b2722db 100644 --- a/charts/client/templates/configmap-bitbucket-dashboard.yaml +++ b/charts/client/templates/configmap-bitbucket-dashboard.yaml @@ -26,7 +26,7 @@ data: "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 34, + "id": 60, "links": [], "liveNow": false, "panels": [ @@ -51,11 +51,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "// Check if data.series exists\nif (data.series && data.series.length > 0) {\n const eventTypes = data.series[0].fields[0].values;\n const authors = data.series[0].fields[1].values;\n const repoNames = data.series[0].fields[2].values;\n const total = data.series[0].fields[3].values; // Assuming you have a field named \"Total\"\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n authors.forEach((author, index) => {\n const sourceNode = {\n name: author,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const eventTypeNode = {\n name: eventTypes[index],\n category: 1, // Category for eventType nodes\n symbolSize: 40, // Size for eventType nodes\n };\n\n const repoNode = {\n name: repoNames[index],\n category: 2, // Category for repo nodes\n symbolSize: 30, // Size for repo nodes\n };\n\n const totalNode = {\n name: `Total: ${total[index]}`, // Assuming you have an array \"total\"\n category: 3, // Category for total nodes\n symbolSize: 20, // Size for total nodes\n };\n\n // Ensure source, eventType, repo, and total nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === eventTypeNode.name)) {\n nodes.push(eventTypeNode);\n }\n\n if (!nodes.some((node) => node.name === repoNode.name)) {\n nodes.push(repoNode);\n }\n\n if (!nodes.some((node) => node.name === totalNode.name)) {\n nodes.push(totalNode);\n }\n\n // Create links between author, eventType, repo, and total nodes\n links.push({\n source: author,\n target: eventTypes[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: repoNames[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: totalNode.name,\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Authors',\n },\n {\n name: 'Event Type',\n },\n {\n name: 'Repo Names',\n },\n {\n name: 'Total', // Add a category for \"Total\" nodes\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Authors', 'Event Types', 'Repo Names', 'Total'], // Add \"Total\" to legend data\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: { // Add textStyle property to configure text style\n color: '#000', // Set the text color to a brighter color, such as white (#FFF)\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n\n // Increase the size of arrow marks\n edgeSymbolSize: [12, 12], // Set the arrow size here\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Display a custom message when data is not available\n const option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n\n return option;\n}", + "getOption": "// Check if data.series exists\nif (context.panel.data.series && context.panel.data.series.length > 0) {\n const eventTypes = context.panel.data.series[0].fields[0].values;\n const authors = context.panel.data.series[0].fields[1].values;\n const repoNames = context.panel.data.series[0].fields[2].values;\n const total = context.panel.data.series[0].fields[3].values; // Assuming you have a field named \"Total\"\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n authors.forEach((author, index) => {\n const sourceNode = {\n name: author,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const eventTypeNode = {\n name: eventTypes[index],\n category: 1, // Category for eventType nodes\n symbolSize: 40, // Size for eventType nodes\n };\n\n const repoNode = {\n name: repoNames[index],\n category: 2, // Category for repo nodes\n symbolSize: 30, // Size for repo nodes\n };\n\n const totalNode = {\n name: `Total: ${total[index]}`, // Assuming you have an array \"total\"\n category: 3, // Category for total nodes\n symbolSize: 20, // Size for total nodes\n };\n\n // Ensure source, eventType, repo, and total nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === eventTypeNode.name)) {\n nodes.push(eventTypeNode);\n }\n\n if (!nodes.some((node) => node.name === repoNode.name)) {\n nodes.push(repoNode);\n }\n\n if (!nodes.some((node) => node.name === totalNode.name)) {\n nodes.push(totalNode);\n }\n\n // Create links between author, eventType, repo, and total nodes\n links.push({\n source: author,\n target: eventTypes[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: repoNames[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: totalNode.name,\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Authors',\n },\n {\n name: 'Event Type',\n },\n {\n name: 'Repo Names',\n },\n {\n name: 'Total', // Add a category for \"Total\" nodes\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Authors', 'Event Types', 'Repo Names', 'Total'], // Add \"Total\" to legend data\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: { // Add textStyle property to configure text style\n color: '#000', // Set the text color to a brighter color, such as white (#FFF)\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n\n // Increase the size of arrow marks\n edgeSymbolSize: [12, 12], // Set the arrow size here\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Display a custom message when data is not available\n const option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n\n return option;\n}", "google": { "callback": "gmapReady", "key": "" @@ -66,8 +67,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -110,11 +117,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let options; // Initialize the options variable\n\nif (!data || !data.series || data.series.length === 0 || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n options = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract Author and Push_Events data from the series\n const categories = data.series[0].fields.find((f) => f.name === 'Author').values;\n const pushEvents = data.series[0].fields.find((f) => f.name === 'Push_Events').values;\n\n // Create the ECharts options\n options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Push_Events'],\n orient: 'vertical', // Change the orientation to vertical\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: pushEvents,\n type: 'line',\n areaStyle: {\n color: 'rgba(0, 128, 255, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'blue', // Set the line color\n },\n name: 'Push_Events',\n },\n ],\n };\n}\n\nreturn options;\n", + "getOption": "let options; // Initialize the options variable\n\nif (!context.panel.data || !context.panel.data.series || context.panel.data.series.length === 0 || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n options = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract Author and Push_Events data from the series\n const categories = context.panel.data.series[0].fields.find((f) => f.name === 'Author').values;\n const pushEvents = context.panel.data.series[0].fields.find((f) => f.name === 'Push_Events').values;\n\n // Create the ECharts options\n options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Push_Events'],\n orient: 'vertical', // Change the orientation to vertical\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: pushEvents,\n type: 'line',\n areaStyle: {\n color: 'rgba(0, 128, 255, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'blue', // Set the line color\n },\n name: 'Push_Events',\n },\n ],\n };\n}\n\nreturn options;\n", "google": { "callback": "gmapReady", "key": "" @@ -125,8 +133,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -169,11 +183,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\n// Define a default options object\nconst defaultOptions = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n};\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = defaultOptions;\n} else {\n // Extract Author and Merge_Events data from the series\n const categories = data.series[0].fields.find((f) => f.name === 'Author').values;\n const mergeEvents = data.series[0].fields.find((f) => f.name === 'Merge_Events').values;\n\n // Create the ECharts options\n const options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Merge_Events'],\n orient: 'vertical',\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: mergeEvents,\n type: 'line',\n name: 'Merge_Events',\n areaStyle: {\n color: 'rgba(255, 0, 0, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'red', // Set the line color\n },\n },\n ],\n };\n\n option = options; // Assign the options to the outer variable\n}\n\nreturn option;\n", + "getOption": "let option; // Initialize the option variable\n\n// Define a default options object\nconst defaultOptions = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n};\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = defaultOptions;\n} else {\n // Extract Author and Merge_Events data from the series\n const categories = context.panel.data.series[0].fields.find((f) => f.name === 'Author').values;\n const mergeEvents = context.panel.data.series[0].fields.find((f) => f.name === 'Merge_Events').values;\n\n // Create the ECharts options\n const options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Merge_Events'],\n orient: 'vertical',\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: mergeEvents,\n type: 'line',\n name: 'Merge_Events',\n areaStyle: {\n color: 'rgba(255, 0, 0, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'red', // Set the line color\n },\n },\n ],\n };\n\n option = options; // Assign the options to the outer variable\n}\n\nreturn option;\n", "google": { "callback": "gmapReady", "key": "" @@ -184,8 +199,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -223,7 +244,8 @@ data: "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -293,7 +315,8 @@ data: "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -451,8 +474,8 @@ data: { "current": { "selected": false, - "text": "", - "value": "" + "text": "All", + "value": "$__all" }, "datasource": { "type": "vertamedia-clickhouse-datasource", @@ -481,7 +504,8 @@ data: "timezone": "", "title": "BitBucket", "uid": "a7772dd5-76c7-48f3-8462-b39fbc20941c", - "version": 1, + "version": 2, "weekStart": "" } + {{- end }} \ No newline at end of file diff --git a/charts/client/templates/configmap-gitea-dashboard.yaml b/charts/client/templates/configmap-gitea-dashboard.yaml index 3c1a663f..5d53ed2b 100644 --- a/charts/client/templates/configmap-gitea-dashboard.yaml +++ b/charts/client/templates/configmap-gitea-dashboard.yaml @@ -26,7 +26,7 @@ data: "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 35, + "id": 61, "links": [], "liveNow": false, "panels": [ @@ -51,11 +51,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "// Check if data.series exists\nif (data.series && data.series.length > 0) {\n const eventTypes = data.series[0].fields[0].values;\n const authors = data.series[0].fields[1].values;\n const repoNames = data.series[0].fields[2].values;\n const total = data.series[0].fields[3].values; // Assuming you have a field named \"Total\"\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n authors.forEach((author, index) => {\n const sourceNode = {\n name: author,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const eventTypeNode = {\n name: eventTypes[index],\n category: 1, // Category for eventType nodes\n symbolSize: 40, // Size for eventType nodes\n };\n\n const repoNode = {\n name: repoNames[index],\n category: 2, // Category for repo nodes\n symbolSize: 30, // Size for repo nodes\n };\n\n const totalNode = {\n name: `Total: ${total[index]}`, // Assuming you have an array \"total\"\n category: 3, // Category for total nodes\n symbolSize: 20, // Size for total nodes\n };\n\n // Ensure source, eventType, repo, and total nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === eventTypeNode.name)) {\n nodes.push(eventTypeNode);\n }\n\n if (!nodes.some((node) => node.name === repoNode.name)) {\n nodes.push(repoNode);\n }\n\n if (!nodes.some((node) => node.name === totalNode.name)) {\n nodes.push(totalNode);\n }\n\n // Create links between author, eventType, repo, and total nodes\n links.push({\n source: author,\n target: eventTypes[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: repoNames[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: totalNode.name,\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Authors',\n },\n {\n name: 'Event Type',\n },\n {\n name: 'Repo Names',\n },\n {\n name: 'Total', // Add a category for \"Total\" nodes\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Authors', 'Event Types', 'Repo Names', 'Total'], // Add \"Total\" to legend data\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: { // Add textStyle property to configure text style\n color: '#000', // Set the text color to a brighter color, such as white (#FFF)\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n\n // Increase the size of arrow marks\n edgeSymbolSize: [12, 12], // Set the arrow size here\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Display a custom message when data is not available\n const option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n\n return option;\n}", + "getOption": "// Check if data.series exists\nif (context.panel.data.series && context.panel.data.series.length > 0) {\n const eventTypes = context.panel.data.series[0].fields[0].values;\n const authors = context.panel.data.series[0].fields[1].values;\n const repoNames = context.panel.data.series[0].fields[2].values;\n const total = context.panel.data.series[0].fields[3].values; // Assuming you have a field named \"Total\"\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n authors.forEach((author, index) => {\n const sourceNode = {\n name: author,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const eventTypeNode = {\n name: eventTypes[index],\n category: 1, // Category for eventType nodes\n symbolSize: 40, // Size for eventType nodes\n };\n\n const repoNode = {\n name: repoNames[index],\n category: 2, // Category for repo nodes\n symbolSize: 30, // Size for repo nodes\n };\n\n const totalNode = {\n name: `Total: ${total[index]}`, // Assuming you have an array \"total\"\n category: 3, // Category for total nodes\n symbolSize: 20, // Size for total nodes\n };\n\n // Ensure source, eventType, repo, and total nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === eventTypeNode.name)) {\n nodes.push(eventTypeNode);\n }\n\n if (!nodes.some((node) => node.name === repoNode.name)) {\n nodes.push(repoNode);\n }\n\n if (!nodes.some((node) => node.name === totalNode.name)) {\n nodes.push(totalNode);\n }\n\n // Create links between author, eventType, repo, and total nodes\n links.push({\n source: author,\n target: eventTypes[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: repoNames[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: totalNode.name,\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Authors',\n },\n {\n name: 'Event Type',\n },\n {\n name: 'Repo Names',\n },\n {\n name: 'Total', // Add a category for \"Total\" nodes\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Authors', 'Event Types', 'Repo Names', 'Total'], // Add \"Total\" to legend data\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: { // Add textStyle property to configure text style\n color: '#000', // Set the text color to a brighter color, such as white (#FFF)\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n\n // Increase the size of arrow marks\n edgeSymbolSize: [12, 12], // Set the arrow size here\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Display a custom message when data is not available\n const option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n\n return option;\n}", "google": { "callback": "gmapReady", "key": "" @@ -66,8 +67,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -110,11 +117,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let options; // Initialize the options variable\n\nif (!data || !data.series || data.series.length === 0 || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n options = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract Author and Push_Events data from the series\n const categories = data.series[0].fields.find((f) => f.name === 'Author').values;\n const pushEvents = data.series[0].fields.find((f) => f.name === 'Push_Events').values;\n\n // Create the ECharts options\n options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Push_Events'],\n orient: 'vertical', // Change the orientation to vertical\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: pushEvents,\n type: 'line',\n areaStyle: {\n color: 'rgba(0, 128, 255, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'blue', // Set the line color\n },\n name: 'Push_Events',\n },\n ],\n };\n}\n\nreturn options;\n", + "getOption": "let options; // Initialize the options variable\n\nif (!context.panel.data || !context.panel.data.series || context.panel.data.series.length === 0 || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n options = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract Author and Push_Events data from the series\n const categories = context.panel.data.series[0].fields.find((f) => f.name === 'Author').values;\n const pushEvents = context.panel.data.series[0].fields.find((f) => f.name === 'Push_Events').values;\n\n // Create the ECharts options\n options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Push_Events'],\n orient: 'vertical', // Change the orientation to vertical\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: pushEvents,\n type: 'line',\n areaStyle: {\n color: 'rgba(0, 128, 255, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'blue', // Set the line color\n },\n name: 'Push_Events',\n },\n ],\n };\n}\n\nreturn options;\n", "google": { "callback": "gmapReady", "key": "" @@ -125,8 +133,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -169,11 +183,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\n// Define a default options object\nconst defaultOptions = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n};\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = defaultOptions;\n} else {\n // Extract Author and Merge_Events data from the series\n const categories = data.series[0].fields.find((f) => f.name === 'Author').values;\n const mergeEvents = data.series[0].fields.find((f) => f.name === 'Merge_Events').values;\n\n // Create the ECharts options\n const options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Merge_Events'],\n orient: 'vertical',\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: mergeEvents,\n type: 'line',\n name: 'Merge_Events',\n areaStyle: {\n color: 'rgba(255, 0, 0, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'red', // Set the line color\n },\n },\n ],\n };\n\n option = options; // Assign the options to the outer variable\n}\n\nreturn option;\n", + "getOption": "let option; // Initialize the option variable\n\n// Define a default options object\nconst defaultOptions = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n};\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = defaultOptions;\n} else {\n // Extract Author and Merge_Events data from the series\n const categories = context.panel.data.series[0].fields.find((f) => f.name === 'Author').values;\n const mergeEvents = context.panel.data.series[0].fields.find((f) => f.name === 'Merge_Events').values;\n\n // Create the ECharts options\n const options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Merge_Events'],\n orient: 'vertical',\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: mergeEvents,\n type: 'line',\n name: 'Merge_Events',\n areaStyle: {\n color: 'rgba(255, 0, 0, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'red', // Set the line color\n },\n },\n ],\n };\n\n option = options; // Assign the options to the outer variable\n}\n\nreturn option;\n", "google": { "callback": "gmapReady", "key": "" @@ -184,8 +199,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -223,7 +244,8 @@ data: "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -293,7 +315,8 @@ data: "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -370,7 +393,8 @@ data: "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null } ] } @@ -427,9 +451,13 @@ data: "list": [ { "current": { - "selected": false, - "text": "All", - "value": "$__all" + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] }, "datasource": { "type": "vertamedia-clickhouse-datasource", @@ -451,8 +479,8 @@ data: { "current": { "selected": false, - "text": "", - "value": "" + "text": "All", + "value": "$__all" }, "datasource": { "type": "vertamedia-clickhouse-datasource", @@ -481,7 +509,8 @@ data: "timezone": "", "title": "GiTea", "uid": "a1c6d705-91b0-4718-99b2-d93b0221bca9", - "version": 1, + "version": 2, "weekStart": "" } + {{- end }} \ No newline at end of file diff --git a/charts/client/templates/configmap-github-dashboard.yaml b/charts/client/templates/configmap-github-dashboard.yaml index 860f77a1..38a98a43 100644 --- a/charts/client/templates/configmap-github-dashboard.yaml +++ b/charts/client/templates/configmap-github-dashboard.yaml @@ -26,7 +26,7 @@ data: "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 37, + "id": 57, "links": [], "liveNow": false, "panels": [ @@ -51,11 +51,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "// Check if data.series exists\nif (data.series && data.series.length > 0) {\n const eventTypes = data.series[0].fields[0].values;\n const authors = data.series[0].fields[1].values;\n const repoNames = data.series[0].fields[2].values;\n const total = data.series[0].fields[3].values; // Assuming you have a field named \"Total\"\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n authors.forEach((author, index) => {\n const sourceNode = {\n name: author,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const eventTypeNode = {\n name: eventTypes[index],\n category: 1, // Category for eventType nodes\n symbolSize: 40, // Size for eventType nodes\n };\n\n const repoNode = {\n name: repoNames[index],\n category: 2, // Category for repo nodes\n symbolSize: 30, // Size for repo nodes\n };\n\n const totalNode = {\n name: `Total: ${total[index]}`, // Assuming you have an array \"total\"\n category: 3, // Category for total nodes\n symbolSize: 20, // Size for total nodes\n };\n\n // Ensure source, eventType, repo, and total nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === eventTypeNode.name)) {\n nodes.push(eventTypeNode);\n }\n\n if (!nodes.some((node) => node.name === repoNode.name)) {\n nodes.push(repoNode);\n }\n\n if (!nodes.some((node) => node.name === totalNode.name)) {\n nodes.push(totalNode);\n }\n\n // Create links between author, eventType, repo, and total nodes\n links.push({\n source: author,\n target: eventTypes[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: repoNames[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: totalNode.name,\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Authors',\n },\n {\n name: 'Event Type',\n },\n {\n name: 'Repo Names',\n },\n {\n name: 'Total', // Add a category for \"Total\" nodes\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Authors', 'Event Types', 'Repo Names', 'Total'], // Add \"Total\" to legend data\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: { // Add textStyle property to configure text style\n color: '#000', // Set the text color to a brighter color, such as white (#FFF)\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n\n // Increase the size of arrow marks\n edgeSymbolSize: [12, 12], // Set the arrow size here\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Handle the case when data.series does not exist\n return {};\n}", + "getOption": "// Check if data.series exists\nif (context.panel.data.series && context.panel.data.series.length > 0) {\n const eventTypes = context.panel.data.series[0].fields[0].values;\n const authors = context.panel.data.series[0].fields[1].values;\n const repoNames = context.panel.data.series[0].fields[2].values;\n const total = context.panel.data.series[0].fields[3].values; // Assuming you have a field named \"Total\"\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n authors.forEach((author, index) => {\n const sourceNode = {\n name: author,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const eventTypeNode = {\n name: eventTypes[index],\n category: 1, // Category for eventType nodes\n symbolSize: 40, // Size for eventType nodes\n };\n\n const repoNode = {\n name: repoNames[index],\n category: 2, // Category for repo nodes\n symbolSize: 30, // Size for repo nodes\n };\n\n const totalNode = {\n name: `Total: ${total[index]}`, // Assuming you have an array \"total\"\n category: 3, // Category for total nodes\n symbolSize: 20, // Size for total nodes\n };\n\n // Ensure source, eventType, repo, and total nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === eventTypeNode.name)) {\n nodes.push(eventTypeNode);\n }\n\n if (!nodes.some((node) => node.name === repoNode.name)) {\n nodes.push(repoNode);\n }\n\n if (!nodes.some((node) => node.name === totalNode.name)) {\n nodes.push(totalNode);\n }\n\n // Create links between author, eventType, repo, and total nodes\n links.push({\n source: author,\n target: eventTypes[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: repoNames[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: totalNode.name,\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Authors',\n },\n {\n name: 'Event Type',\n },\n {\n name: 'Repo Names',\n },\n {\n name: 'Total', // Add a category for \"Total\" nodes\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Authors', 'Event Types', 'Repo Names', 'Total'], // Add \"Total\" to legend data\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: { // Add textStyle property to configure text style\n color: '#000', // Set the text color to a brighter color, such as white (#FFF)\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n\n // Increase the size of arrow marks\n edgeSymbolSize: [12, 12], // Set the arrow size here\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Handle the case when data.series does not exist\n return {};\n}", "google": { "callback": "gmapReady", "key": "" @@ -66,9 +67,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, - "pluginVersion": "10.0.3", + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -111,11 +117,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let options; // Initialize the options variable\n\nif (!data || !data.series || data.series.length === 0 || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n options = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract Author and Push_Events data from the series\n const categories = data.series[0].fields.find((f) => f.name === 'Author').values;\n const pushEvents = data.series[0].fields.find((f) => f.name === 'Push_Events').values;\n\n // Create the ECharts options\n options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Push_Events'],\n orient: 'vertical', // Change the orientation to vertical\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: pushEvents,\n type: 'line',\n areaStyle: {\n color: 'rgba(0, 128, 255, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'blue', // Set the line color\n },\n name: 'Push_Events',\n },\n ],\n };\n}\n\nreturn options;\n", + "getOption": "let options; // Initialize the options variable\n\nif (!context.panel.data || !context.panel.data.series || context.panel.data.series.length === 0 || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n options = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract Author and Push_Events data from the series\n const categories = context.panel.data.series[0].fields.find((f) => f.name === 'Author').values;\n const pushEvents = context.panel.data.series[0].fields.find((f) => f.name === 'Push_Events').values;\n\n // Create the ECharts options\n options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Push_Events'],\n orient: 'vertical', // Change the orientation to vertical\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: pushEvents,\n type: 'line',\n areaStyle: {\n color: 'rgba(0, 128, 255, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'blue', // Set the line color\n },\n name: 'Push_Events',\n },\n ],\n };\n}\n\nreturn options;\n", "google": { "callback": "gmapReady", "key": "" @@ -126,8 +133,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -170,11 +183,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\n// Define a default options object\nconst defaultOptions = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n};\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = defaultOptions;\n} else {\n // Extract Author and Merge_Events data from the series\n const categories = data.series[0].fields.find((f) => f.name === 'Author').values;\n const mergeEvents = data.series[0].fields.find((f) => f.name === 'Merge_Events').values;\n\n // Create the ECharts options\n const options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Merge_Events'],\n orient: 'vertical',\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: mergeEvents,\n type: 'line',\n name: 'Merge_Events',\n areaStyle: {\n color: 'rgba(255, 0, 0, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'red', // Set the line color\n },\n },\n ],\n };\n\n option = options; // Assign the options to the outer variable\n}\n\nreturn option;\n", + "getOption": "let option; // Initialize the option variable\n\n// Define a default options object\nconst defaultOptions = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n};\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = defaultOptions;\n} else {\n // Extract Author and Merge_Events data from the series\n const categories = context.panel.data.series[0].fields.find((f) => f.name === 'Author').values;\n const mergeEvents = context.panel.data.series[0].fields.find((f) => f.name === 'Merge_Events').values;\n\n // Create the ECharts options\n const options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Merge_Events'],\n orient: 'vertical',\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: mergeEvents,\n type: 'line',\n name: 'Merge_Events',\n areaStyle: {\n color: 'rgba(255, 0, 0, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'red', // Set the line color\n },\n },\n ],\n };\n\n option = options; // Assign the options to the outer variable\n}\n\nreturn option;\n", "google": { "callback": "gmapReady", "key": "" @@ -185,8 +199,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -229,11 +249,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "const values = data.series[0].fields[0].values;\n\nreturn {\n series: [\n {\n type: 'liquidFill',\n radius: '90%',\n data: values, // Use the raw values here\n label: {\n formatter: '{a|{c}}',\n rich: {\n a: {\n color: '#000', // You can set the text color here\n },\n },\n },\n tooltip: {\n formatter: '{a}: {c}', // This formatter displays the raw values\n },\n },\n ],\n};\n", + "getOption": "const values = context.panel.data.series[0].fields[0].values;\n\nreturn {\n series: [\n {\n type: 'liquidFill',\n radius: '90%',\n data: values, // Use the raw values here\n label: {\n formatter: '{a|{c}}',\n rich: {\n a: {\n color: '#000', // You can set the text color here\n },\n },\n },\n tooltip: {\n formatter: '{a}: {c}', // This formatter displays the raw values\n },\n },\n ],\n};\n", "google": { "callback": "gmapReady", "key": "" @@ -244,8 +265,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -288,11 +315,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "const values = data.series[0].fields[0].values;\n\nreturn {\n series: [\n {\n type: 'liquidFill',\n radius: '90%',\n data: values, // Use the raw values here\n label: {\n formatter: '{a|{c}}',\n rich: {\n a: {\n color: '#000', // You can set the text color here\n },\n },\n },\n tooltip: {\n formatter: '{a}: {c}', // This formatter displays the raw values\n },\n },\n ],\n};\n", + "getOption": "const values = context.panel.data.series[0].fields[0].values;\n\nreturn {\n series: [\n {\n type: 'liquidFill',\n radius: '90%',\n data: values, // Use the raw values here\n label: {\n formatter: '{a|{c}}',\n rich: {\n a: {\n color: '#000', // You can set the text color here\n },\n },\n },\n tooltip: {\n formatter: '{a}: {c}', // This formatter displays the raw values\n },\n },\n ],\n};\n", "google": { "callback": "gmapReady", "key": "" @@ -303,8 +331,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -349,7 +383,8 @@ data: "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null } ] } @@ -406,9 +441,13 @@ data: "list": [ { "current": { - "selected": false, - "text": "", - "value": "" + "selected": true, + "text": [ + "ahinvinith" + ], + "value": [ + "ahinvinith" + ] }, "datasource": { "type": "vertamedia-clickhouse-datasource", @@ -467,4 +506,5 @@ data: "version": 2, "weekStart": "" } + {{- end }} \ No newline at end of file diff --git a/charts/client/templates/configmap-gitlab-dashboard.yaml b/charts/client/templates/configmap-gitlab-dashboard.yaml index bc1273b7..fd1840dc 100644 --- a/charts/client/templates/configmap-gitlab-dashboard.yaml +++ b/charts/client/templates/configmap-gitlab-dashboard.yaml @@ -26,7 +26,7 @@ data: "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 36, + "id": 59, "links": [], "liveNow": false, "panels": [ @@ -51,11 +51,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "// Check if data.series exists\nif (data.series && data.series.length > 0) {\n const eventTypes = data.series[0].fields[0].values;\n const authors = data.series[0].fields[1].values;\n const repoNames = data.series[0].fields[2].values;\n const total = data.series[0].fields[3].values; // Assuming you have a field named \"Total\"\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n authors.forEach((author, index) => {\n const sourceNode = {\n name: author,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const eventTypeNode = {\n name: eventTypes[index],\n category: 1, // Category for eventType nodes\n symbolSize: 40, // Size for eventType nodes\n };\n\n const repoNode = {\n name: repoNames[index],\n category: 2, // Category for repo nodes\n symbolSize: 30, // Size for repo nodes\n };\n\n const totalNode = {\n name: `Total: ${total[index]}`, // Assuming you have an array \"total\"\n category: 3, // Category for total nodes\n symbolSize: 20, // Size for total nodes\n };\n\n // Ensure source, eventType, repo, and total nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === eventTypeNode.name)) {\n nodes.push(eventTypeNode);\n }\n\n if (!nodes.some((node) => node.name === repoNode.name)) {\n nodes.push(repoNode);\n }\n\n if (!nodes.some((node) => node.name === totalNode.name)) {\n nodes.push(totalNode);\n }\n\n // Create links between author, eventType, repo, and total nodes\n links.push({\n source: author,\n target: eventTypes[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: repoNames[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: totalNode.name,\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Authors',\n },\n {\n name: 'Event Type',\n },\n {\n name: 'Repo Names',\n },\n {\n name: 'Total', // Add a category for \"Total\" nodes\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Authors', 'Event Types', 'Repo Names', 'Total'], // Add \"Total\" to legend data\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: { // Add textStyle property to configure text style\n color: '#000', // Set the text color to a brighter color, such as white (#FFF)\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n\n // Increase the size of arrow marks\n edgeSymbolSize: [12, 12], // Set the arrow size here\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Display a custom message when data is not available\n const option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n\n return option;\n}", + "getOption": "// Check if data.series exists\nif (context.panel.data.series && context.panel.data.series.length > 0) {\n const eventTypes = context.panel.data.series[0].fields[0].values;\n const authors = context.panel.data.series[0].fields[1].values;\n const repoNames = context.panel.data.series[0].fields[2].values;\n const total = context.panel.data.series[0].fields[3].values; // Assuming you have a field named \"Total\"\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n authors.forEach((author, index) => {\n const sourceNode = {\n name: author,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const eventTypeNode = {\n name: eventTypes[index],\n category: 1, // Category for eventType nodes\n symbolSize: 40, // Size for eventType nodes\n };\n\n const repoNode = {\n name: repoNames[index],\n category: 2, // Category for repo nodes\n symbolSize: 30, // Size for repo nodes\n };\n\n const totalNode = {\n name: `Total: ${total[index]}`, // Assuming you have an array \"total\"\n category: 3, // Category for total nodes\n symbolSize: 20, // Size for total nodes\n };\n\n // Ensure source, eventType, repo, and total nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === eventTypeNode.name)) {\n nodes.push(eventTypeNode);\n }\n\n if (!nodes.some((node) => node.name === repoNode.name)) {\n nodes.push(repoNode);\n }\n\n if (!nodes.some((node) => node.name === totalNode.name)) {\n nodes.push(totalNode);\n }\n\n // Create links between author, eventType, repo, and total nodes\n links.push({\n source: author,\n target: eventTypes[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: repoNames[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: totalNode.name,\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Authors',\n },\n {\n name: 'Event Type',\n },\n {\n name: 'Repo Names',\n },\n {\n name: 'Total', // Add a category for \"Total\" nodes\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Authors', 'Event Types', 'Repo Names', 'Total'], // Add \"Total\" to legend data\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: { // Add textStyle property to configure text style\n color: '#000', // Set the text color to a brighter color, such as white (#FFF)\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n\n // Increase the size of arrow marks\n edgeSymbolSize: [12, 12], // Set the arrow size here\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Display a custom message when data is not available\n const option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n\n return option;\n}", "google": { "callback": "gmapReady", "key": "" @@ -66,8 +67,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -110,11 +117,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let options; // Initialize the options variable\n\nif (!data || !data.series || data.series.length === 0 || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n options = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract Author and Push_Events data from the series\n const categories = data.series[0].fields.find((f) => f.name === 'Author').values;\n const pushEvents = data.series[0].fields.find((f) => f.name === 'Push_Events').values;\n\n // Create the ECharts options\n options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Push_Events'],\n orient: 'vertical', // Change the orientation to vertical\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: pushEvents,\n type: 'line',\n areaStyle: {\n color: 'rgba(0, 128, 255, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'blue', // Set the line color\n },\n name: 'Push_Events',\n },\n ],\n };\n}\n\nreturn options;\n", + "getOption": "let options; // Initialize the options variable\n\nif (!context.panel.data || !context.panel.data.series || context.panel.data.series.length === 0 || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n options = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract Author and Push_Events data from the series\n const categories = context.panel.data.series[0].fields.find((f) => f.name === 'Author').values;\n const pushEvents = context.panel.data.series[0].fields.find((f) => f.name === 'Push_Events').values;\n\n // Create the ECharts options\n options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Push_Events'],\n orient: 'vertical', // Change the orientation to vertical\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: pushEvents,\n type: 'line',\n areaStyle: {\n color: 'rgba(0, 128, 255, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'blue', // Set the line color\n },\n name: 'Push_Events',\n },\n ],\n };\n}\n\nreturn options;\n", "google": { "callback": "gmapReady", "key": "" @@ -125,8 +133,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -169,11 +183,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\n// Define a default options object\nconst defaultOptions = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n};\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = defaultOptions;\n} else {\n // Extract Author and Merge_Events data from the series\n const categories = data.series[0].fields.find((f) => f.name === 'Author').values;\n const mergeEvents = data.series[0].fields.find((f) => f.name === 'Merge_Events').values;\n\n // Create the ECharts options\n const options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Merge_Events'],\n orient: 'vertical',\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: mergeEvents,\n type: 'line',\n name: 'Merge_Events',\n areaStyle: {\n color: 'rgba(255, 0, 0, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'red', // Set the line color\n },\n },\n ],\n };\n\n option = options; // Assign the options to the outer variable\n}\n\nreturn option;\n", + "getOption": "let option; // Initialize the option variable\n\n// Define a default options object\nconst defaultOptions = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n};\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = defaultOptions;\n} else {\n // Extract Author and Merge_Events data from the series\n const categories = context.panel.data.series[0].fields.find((f) => f.name === 'Author').values;\n const mergeEvents = context.panel.data.series[0].fields.find((f) => f.name === 'Merge_Events').values;\n\n // Create the ECharts options\n const options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Merge_Events'],\n orient: 'vertical',\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: mergeEvents,\n type: 'line',\n name: 'Merge_Events',\n areaStyle: {\n color: 'rgba(255, 0, 0, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'red', // Set the line color\n },\n },\n ],\n };\n\n option = options; // Assign the options to the outer variable\n}\n\nreturn option;\n", "google": { "callback": "gmapReady", "key": "" @@ -184,8 +199,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -223,7 +244,8 @@ data: "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -293,7 +315,8 @@ data: "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -370,7 +393,8 @@ data: "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -485,7 +509,8 @@ data: "timezone": "", "title": "GitLab", "uid": "ec8b9cb1-f9ae-4139-b270-4824b6508eff", - "version": 1, + "version": 2, "weekStart": "" } + {{- end }} \ No newline at end of file diff --git a/charts/client/templates/configmap-kubedata-dashboard.yaml b/charts/client/templates/configmap-kubedata-dashboard.yaml index 7e275444..d479fd9b 100644 --- a/charts/client/templates/configmap-kubedata-dashboard.yaml +++ b/charts/client/templates/configmap-kubedata-dashboard.yaml @@ -32,7 +32,7 @@ data: "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 146, + "id": 56, "links": [], "liveNow": false, "panels": [ @@ -57,11 +57,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON as before\n const clusterNames = data.series[0].fields[0].values;\n const namespaces = data.series[0].fields[1].values;\n const reasons = data.series[0].fields[2].values;\n const pods = data.series[0].fields[3].values;\n\n // Create a hierarchical structure from the data without a root node\n const hierarchy = {\n name: 'root', // Use 'root' as a placeholder\n children: [],\n };\n\n const seenClusterNames = new Set();\n const seenNamespaces = new Set();\n\n for (let i = 0; i < clusterNames.length; i++) {\n const clusterName = clusterNames[i];\n const namespace = namespaces[i];\n const reason = reasons[i];\n const pod = pods[i];\n\n if (!seenClusterNames.has(clusterName)) {\n seenClusterNames.add(clusterName);\n const clusterNode = { name: clusterName, children: [] };\n hierarchy.children.push(clusterNode);\n seenNamespaces.clear(); // Reset seenNamespaces for each cluster\n }\n\n const clusterNode = hierarchy.children.find((node) => node.name === clusterName);\n\n if (!seenNamespaces.has(namespace)) {\n seenNamespaces.add(namespace);\n const namespaceNode = { name: namespace, children: [] };\n clusterNode.children.push(namespaceNode);\n }\n\n const namespaceNode = clusterNode.children.find((node) => node.name === namespace);\n const reasonNode = { name: reason, children: [{ name: `Count: ${pod}` }] };\n namespaceNode.children.push(reasonNode);\n }\n\n // Create the tree chart using ECharts\n option = {\n tooltip: {\n trigger: 'item',\n triggerOn: 'mousemove',\n formatter: function (params) {\n const node = params.data;\n let tooltip = '';\n if (node.column) {\n tooltip += `${node.column}: ${node.name}`;\n } else {\n tooltip += node.name;\n }\n return tooltip;\n },\n },\n series: [\n {\n type: 'tree',\n data: hierarchy.children, // Use the children directly\n top: '1%',\n left: '7%',\n bottom: '1%',\n right: '20%',\n symbolSize: 7,\n label: {\n position: 'left',\n verticalAlign: 'middle',\n align: 'centre',\n fontSize: 15, // Increase the text size for regular nodes\n fontWeight: 'bold', // Set the font weight to bold\n },\n leaves: {\n label: {\n position: 'right',\n verticalAlign: 'middle',\n align: 'left',\n fontSize: 15, // Increase the text size for leaves\n fontWeight: 'bold', // Set the font weight to bold\n },\n },\n emphasis: {\n focus: 'descendant',\n },\n expandAndCollapse: true,\n animationDuration: 550,\n animationDurationUpdate: 750,\n },\n ],\n };\n}\n\nreturn option;", + "getOption": "let option; // Initialize the option variable\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON as before\n const clusterNames = context.panel.data.series[0].fields[0].values;\n const namespaces = context.panel.data.series[0].fields[1].values;\n const reasons = context.panel.data.series[0].fields[2].values;\n const pods = context.panel.data.series[0].fields[3].values;\n\n // Create a hierarchical structure from the data without a root node\n const hierarchy = {\n name: 'root', // Use 'root' as a placeholder\n children: [],\n };\n\n const seenClusterNames = new Set();\n const seenNamespaces = new Set();\n\n for (let i = 0; i < clusterNames.length; i++) {\n const clusterName = clusterNames[i];\n const namespace = namespaces[i];\n const reason = reasons[i];\n const pod = pods[i];\n\n if (!seenClusterNames.has(clusterName)) {\n seenClusterNames.add(clusterName);\n const clusterNode = { name: clusterName, children: [] };\n hierarchy.children.push(clusterNode);\n seenNamespaces.clear(); // Reset seenNamespaces for each cluster\n }\n\n const clusterNode = hierarchy.children.find((node) => node.name === clusterName);\n\n if (!seenNamespaces.has(namespace)) {\n seenNamespaces.add(namespace);\n const namespaceNode = { name: namespace, children: [] };\n clusterNode.children.push(namespaceNode);\n }\n\n const namespaceNode = clusterNode.children.find((node) => node.name === namespace);\n const reasonNode = { name: reason, children: [{ name: `Count: ${pod}` }] };\n namespaceNode.children.push(reasonNode);\n }\n\n // Create the tree chart using ECharts\n option = {\n tooltip: {\n trigger: 'item',\n triggerOn: 'mousemove',\n formatter: function (params) {\n const node = params.data;\n let tooltip = '';\n if (node.column) {\n tooltip += `${node.column}: ${node.name}`;\n } else {\n tooltip += node.name;\n }\n return tooltip;\n },\n },\n series: [\n {\n type: 'tree',\n data: hierarchy.children, // Use the children directly\n top: '1%',\n left: '7%',\n bottom: '1%',\n right: '20%',\n symbolSize: 7,\n label: {\n position: 'left',\n verticalAlign: 'middle',\n align: 'centre',\n fontSize: 15, // Increase the text size for regular nodes\n fontWeight: 'bold', // Set the font weight to bold\n },\n leaves: {\n label: {\n position: 'right',\n verticalAlign: 'middle',\n align: 'left',\n fontSize: 15, // Increase the text size for leaves\n fontWeight: 'bold', // Set the font weight to bold\n },\n },\n emphasis: {\n focus: 'descendant',\n },\n expandAndCollapse: true,\n animationDuration: 550,\n animationDurationUpdate: 750,\n },\n ],\n };\n}\n\nreturn option;", "google": { "callback": "gmapReady", "key": "" @@ -72,8 +73,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -116,11 +123,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON as before\n const reasons = data.series[0].fields[0].values;\n const counts = data.series[0].fields[1].values;\n\n // Check if reasons and counts are defined and not empty\n if (!reasons || !counts || reasons.length === 0 || counts.length === 0) {\n // Display a message when no data is available\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n } else {\n // Data is available, proceed with the chart creation\n // Create an array of data items, each containing name and value\n const seriesData = reasons.map((reason, index) => ({\n name: reason,\n value: counts[index],\n }));\n\n // Define a custom color for the bars\n const customColor = 'rgb(0, 123, 255)'; // Change this to your desired color\n\n // Apache ECharts option\n option = {\n xAxis: {\n type: 'category',\n data: reasons, // Use the reasons directly for xAxis data\n axisLabel: {\n interval: 0, // Display all labels on the xAxis\n },\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Pods'], // Legend name\n left: 'left', // Position the legend on the left side\n bottom: 'bottom', // Position the legend at the bottom\n },\n series: [\n {\n name: 'Pods', // Series name for the legend\n data: seriesData,\n type: 'bar',\n label: {\n show: true,\n position: 'top',\n formatter: '{c}',\n },\n itemStyle: {\n barBorderRadius: [5, 5, 0, 0], // Adjust the values to control the curvature\n color: customColor, // Set the custom color for the bars\n },\n },\n ],\n };\n }\n}\n\nreturn option;", + "getOption": "let option; // Initialize the option variable\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON as before\n const reasons = context.panel.data.series[0].fields[0].values;\n const counts = context.panel.data.series[0].fields[1].values;\n\n // Check if reasons and counts are defined and not empty\n if (!reasons || !counts || reasons.length === 0 || counts.length === 0) {\n // Display a message when no data is available\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n } else {\n // Data is available, proceed with the chart creation\n // Create an array of data items, each containing name and value\n const seriesData = reasons.map((reason, index) => ({\n name: reason,\n value: counts[index],\n }));\n\n // Define a custom color for the bars\n const customColor = 'rgb(0, 123, 255)'; // Change this to your desired color\n\n // Apache ECharts option\n option = {\n xAxis: {\n type: 'category',\n data: reasons, // Use the reasons directly for xAxis data\n axisLabel: {\n interval: 0, // Display all labels on the xAxis\n },\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Pods'], // Legend name\n left: 'left', // Position the legend on the left side\n bottom: 'bottom', // Position the legend at the bottom\n },\n series: [\n {\n name: 'Pods', // Series name for the legend\n data: seriesData,\n type: 'bar',\n label: {\n show: true,\n position: 'top',\n formatter: '{c}',\n },\n itemStyle: {\n barBorderRadius: [5, 5, 0, 0], // Adjust the values to control the curvature\n color: customColor, // Set the custom color for the bars\n },\n },\n ],\n };\n }\n}\n\nreturn option;", "google": { "callback": "gmapReady", "key": "" @@ -131,8 +139,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -175,11 +189,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n\n // Define the data from your JSON\n const clusterNames = data.series[0].fields[0].values;\n const kinds = data.series[0].fields[1].values;\n const reasons = data.series[0].fields[2].values;\n const counts = data.series[0].fields[3].values;\n\n // Create the Sankey chart configuration\n option = {\n series: {\n type: 'sankey',\n layout: 'none',\n emphasis: {\n focus: 'adjacency',\n },\n data: [],\n links: [],\n },\n tooltip: {\n trigger: 'item',\n formatter: (params) => {\n if (params.dataType === 'node') {\n return params.name;\n }\n if (params.dataType === 'edge') {\n return `Count: ${counts[params.dataIndex]}`; // Display count values\n }\n return '';\n },\n },\n };\n\n // Create nodes for ClusterName, Kind, and Reason\n const uniqueClusterNames = Array.from(new Set(clusterNames));\n const uniqueKinds = Array.from(new Set(kinds));\n const uniqueReasons = Array.from(new Set(reasons));\n\n uniqueClusterNames.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueKinds.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueReasons.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n\n // Create links from Kind to Reason\n kinds.forEach((kind, index) => {\n const sourceIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kind);\n const targetIndex = 1 * uniqueClusterNames.length + uniqueKinds.length + uniqueReasons.indexOf(reasons[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: counts[index], // Use count values\n });\n });\n\n // Create links from ClusterName to Kind\n clusterNames.forEach((clusterName, index) => {\n const sourceIndex = uniqueClusterNames.indexOf(clusterName);\n const targetIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kinds[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: 1,\n });\n });\n}\n\n\nreturn option;\n// Render the chart\nmyChart.setOption(option);", + "getOption": "let option; // Initialize the option variable\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n\n // Define the data from your JSON\n const clusterNames = context.panel.data.series[0].fields[0].values;\n const kinds = context.panel.data.series[0].fields[1].values;\n const reasons = context.panel.data.series[0].fields[2].values;\n const counts = context.panel.data.series[0].fields[3].values;\n\n // Create the Sankey chart configuration\n option = {\n series: {\n type: 'sankey',\n layout: 'none',\n emphasis: {\n focus: 'adjacency',\n },\n data: [],\n links: [],\n },\n tooltip: {\n trigger: 'item',\n formatter: (params) => {\n if (params.dataType === 'node') {\n return params.name;\n }\n if (params.dataType === 'edge') {\n return `Count: ${counts[params.dataIndex]}`; // Display count values\n }\n return '';\n },\n },\n };\n\n // Create nodes for ClusterName, Kind, and Reason\n const uniqueClusterNames = Array.from(new Set(clusterNames));\n const uniqueKinds = Array.from(new Set(kinds));\n const uniqueReasons = Array.from(new Set(reasons));\n\n uniqueClusterNames.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueKinds.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueReasons.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n\n // Create links from Kind to Reason\n kinds.forEach((kind, index) => {\n const sourceIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kind);\n const targetIndex = 1 * uniqueClusterNames.length + uniqueKinds.length + uniqueReasons.indexOf(reasons[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: counts[index], // Use count values\n });\n });\n\n // Create links from ClusterName to Kind\n clusterNames.forEach((clusterName, index) => {\n const sourceIndex = uniqueClusterNames.indexOf(clusterName);\n const targetIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kinds[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: 1,\n });\n });\n}\n\n\nreturn option;\n// Render the chart\nmyChart.setOption(option);", "google": { "callback": "gmapReady", "key": "" @@ -190,8 +205,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -234,11 +255,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n\n // Define the data from your JSON\n const clusterNames = data.series[0].fields[0].values;\n const kinds = data.series[0].fields[1].values;\n const reasons = data.series[0].fields[2].values;\n const counts = data.series[0].fields[3].values;\n\n // Create the Sankey chart configuration\n option = {\n series: {\n type: 'sankey',\n layout: 'none',\n emphasis: {\n focus: 'adjacency',\n },\n data: [],\n links: [],\n },\n tooltip: {\n trigger: 'item',\n formatter: (params) => {\n if (params.dataType === 'node') {\n return params.name;\n }\n if (params.dataType === 'edge') {\n return `Count: ${counts[params.dataIndex]}`; // Display count values\n }\n return '';\n },\n },\n };\n\n // Create nodes for ClusterName, Kind, and Reason\n const uniqueClusterNames = Array.from(new Set(clusterNames));\n const uniqueKinds = Array.from(new Set(kinds));\n const uniqueReasons = Array.from(new Set(reasons));\n\n uniqueClusterNames.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueKinds.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueReasons.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n\n // Create links from Kind to Reason\n kinds.forEach((kind, index) => {\n const sourceIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kind);\n const targetIndex = 1 * uniqueClusterNames.length + uniqueKinds.length + uniqueReasons.indexOf(reasons[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: counts[index], // Use count values\n });\n });\n\n // Create links from ClusterName to Kind\n clusterNames.forEach((clusterName, index) => {\n const sourceIndex = uniqueClusterNames.indexOf(clusterName);\n const targetIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kinds[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: 1,\n });\n });\n}\n\n\n\nreturn option;\n// Render the chart\nmyChart.setOption(option);", + "getOption": "let option; // Initialize the option variable\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n\n // Define the data from your JSON\n const clusterNames = context.panel.data.series[0].fields[0].values;\n const kinds = context.panel.data.series[0].fields[1].values;\n const reasons = context.panel.data.series[0].fields[2].values;\n const counts = context.panel.data.series[0].fields[3].values;\n\n // Create the Sankey chart configuration\n option = {\n series: {\n type: 'sankey',\n layout: 'none',\n emphasis: {\n focus: 'adjacency',\n },\n data: [],\n links: [],\n },\n tooltip: {\n trigger: 'item',\n formatter: (params) => {\n if (params.dataType === 'node') {\n return params.name;\n }\n if (params.dataType === 'edge') {\n return `Count: ${counts[params.dataIndex]}`; // Display count values\n }\n return '';\n },\n },\n };\n\n // Create nodes for ClusterName, Kind, and Reason\n const uniqueClusterNames = Array.from(new Set(clusterNames));\n const uniqueKinds = Array.from(new Set(kinds));\n const uniqueReasons = Array.from(new Set(reasons));\n\n uniqueClusterNames.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueKinds.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueReasons.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n\n // Create links from Kind to Reason\n kinds.forEach((kind, index) => {\n const sourceIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kind);\n const targetIndex = 1 * uniqueClusterNames.length + uniqueKinds.length + uniqueReasons.indexOf(reasons[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: counts[index], // Use count values\n });\n });\n\n // Create links from ClusterName to Kind\n clusterNames.forEach((clusterName, index) => {\n const sourceIndex = uniqueClusterNames.indexOf(clusterName);\n const targetIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kinds[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: 1,\n });\n });\n}\n\n\n\nreturn option;\n// Render the chart\nmyChart.setOption(option);", "google": { "callback": "gmapReady", "key": "" @@ -249,8 +271,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -293,11 +321,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n\n // Define the data from your JSON\n const clusterNames = data.series[0].fields[0].values;\n const kinds = data.series[0].fields[1].values;\n const reasons = data.series[0].fields[2].values;\n const counts = data.series[0].fields[3].values;\n\n // Create the Sankey chart configuration\n option = {\n series: {\n type: 'sankey',\n layout: 'none',\n emphasis: {\n focus: 'adjacency',\n },\n data: [],\n links: [],\n },\n tooltip: {\n trigger: 'item',\n formatter: (params) => {\n if (params.dataType === 'node') {\n return params.name;\n }\n if (params.dataType === 'edge') {\n return `Count: ${counts[params.dataIndex]}`; // Display count values\n }\n return '';\n },\n },\n };\n\n // Create nodes for ClusterName, Kind, and Reason\n const uniqueClusterNames = Array.from(new Set(clusterNames));\n const uniqueKinds = Array.from(new Set(kinds));\n const uniqueReasons = Array.from(new Set(reasons));\n\n uniqueClusterNames.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueKinds.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueReasons.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n\n // Create links from Kind to Reason\n kinds.forEach((kind, index) => {\n const sourceIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kind);\n const targetIndex = 1 * uniqueClusterNames.length + uniqueKinds.length + uniqueReasons.indexOf(reasons[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: counts[index], // Use count values\n });\n });\n\n // Create links from ClusterName to Kind\n clusterNames.forEach((clusterName, index) => {\n const sourceIndex = uniqueClusterNames.indexOf(clusterName);\n const targetIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kinds[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: 1,\n });\n });\n}\n\n\nreturn option;\n// Render the chart\nmyChart.setOption(option);\n\n", + "getOption": "let option; // Initialize the option variable\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n\n // Define the data from your JSON\n const clusterNames = context.panel.data.series[0].fields[0].values;\n const kinds = context.panel.data.series[0].fields[1].values;\n const reasons = context.panel.data.series[0].fields[2].values;\n const counts = context.panel.data.series[0].fields[3].values;\n\n // Create the Sankey chart configuration\n option = {\n series: {\n type: 'sankey',\n layout: 'none',\n emphasis: {\n focus: 'adjacency',\n },\n data: [],\n links: [],\n },\n tooltip: {\n trigger: 'item',\n formatter: (params) => {\n if (params.dataType === 'node') {\n return params.name;\n }\n if (params.dataType === 'edge') {\n return `Count: ${counts[params.dataIndex]}`; // Display count values\n }\n return '';\n },\n },\n };\n\n // Create nodes for ClusterName, Kind, and Reason\n const uniqueClusterNames = Array.from(new Set(clusterNames));\n const uniqueKinds = Array.from(new Set(kinds));\n const uniqueReasons = Array.from(new Set(reasons));\n\n uniqueClusterNames.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueKinds.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueReasons.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n\n // Create links from Kind to Reason\n kinds.forEach((kind, index) => {\n const sourceIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kind);\n const targetIndex = 1 * uniqueClusterNames.length + uniqueKinds.length + uniqueReasons.indexOf(reasons[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: counts[index], // Use count values\n });\n });\n\n // Create links from ClusterName to Kind\n clusterNames.forEach((clusterName, index) => {\n const sourceIndex = uniqueClusterNames.indexOf(clusterName);\n const targetIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kinds[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: 1,\n });\n });\n}\n\n\nreturn option;\n// Render the chart\nmyChart.setOption(option);\n\n", "google": { "callback": "gmapReady", "key": "" @@ -308,8 +337,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -352,11 +387,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON\n const clusters = data.series[0].fields[0].values;\n const hosts = data.series[0].fields[1].values;\n const reasons = data.series[0].fields[2].values;\n const eventTimes = data.series[0].fields[3].values;\n\n // Create a hierarchical structure for the tree chart starting with ClusterName\n const hierarchy = {\n name: 'Root', // You can customize the name of the root node if needed\n children: [],\n };\n\n for (let i = 0; i < clusters.length; i++) {\n const cluster = clusters[i];\n const host = hosts[i];\n const reason = reasons[i];\n const eventTime = eventTimes[i];\n\n // Find or create the cluster node\n let clusterNode = hierarchy.children.find((node) => node.name === cluster);\n if (!clusterNode) {\n clusterNode = { name: cluster, children: [] };\n hierarchy.children.push(clusterNode);\n }\n\n // Find or create the host node under the cluster\n let hostNode = clusterNode.children.find((node) => node.name === host);\n if (!hostNode) {\n hostNode = { name: host, children: [] };\n clusterNode.children.push(hostNode);\n }\n\n // Find or create the reason node under the host\n let reasonNode = hostNode.children.find((node) => node.name === reason);\n if (!reasonNode) {\n reasonNode = { name: reason, children: [] };\n hostNode.children.push(reasonNode);\n }\n\n // Create the eventTime node under the reason\n reasonNode.children.push({ name: eventTime });\n }\n\n // Create the tree chart using ECharts\n option = {\n tooltip: {\n trigger: 'item',\n triggerOn: 'mousemove',\n },\n series: [\n {\n type: 'tree',\n data: hierarchy.children, // Use the children directly as root nodes\n top: '1%',\n left: '7%',\n bottom: '1%',\n right: '20%', // Adjust the right margin to provide more space for labels\n symbolSize: 7,\n label: {\n position: 'inside', // Position labels inside the node\n verticalAlign: 'middle',\n align: 'center', // Center-align labels\n fontSize: 15,\n fontWeight: 'bold',\n },\n leaves: {\n label: {\n position: 'right', // Position labels inside the node\n verticalAlign: 'middle',\n align: 'left', // Center-align labels\n fontSize: 15,\n fontWeight: 'bold',\n },\n },\n emphasis: {\n focus: 'descendant',\n },\n expandAndCollapse: true,\n animationDuration: 550,\n animationDurationUpdate: 750,\n },\n ],\n };\n}\n\nreturn option;\n", + "getOption": "let option; // Initialize the option variable\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON\n const clusters = context.panel.data.series[0].fields[0].values;\n const hosts = context.panel.data.series[0].fields[1].values;\n const reasons = context.panel.data.series[0].fields[2].values;\n const eventTimes = context.panel.data.series[0].fields[3].values;\n\n // Create a hierarchical structure for the tree chart starting with ClusterName\n const hierarchy = {\n name: 'Root', // You can customize the name of the root node if needed\n children: [],\n };\n\n for (let i = 0; i < clusters.length; i++) {\n const cluster = clusters[i];\n const host = hosts[i];\n const reason = reasons[i];\n const eventTime = eventTimes[i];\n\n // Find or create the cluster node\n let clusterNode = hierarchy.children.find((node) => node.name === cluster);\n if (!clusterNode) {\n clusterNode = { name: cluster, children: [] };\n hierarchy.children.push(clusterNode);\n }\n\n // Find or create the host node under the cluster\n let hostNode = clusterNode.children.find((node) => node.name === host);\n if (!hostNode) {\n hostNode = { name: host, children: [] };\n clusterNode.children.push(hostNode);\n }\n\n // Find or create the reason node under the host\n let reasonNode = hostNode.children.find((node) => node.name === reason);\n if (!reasonNode) {\n reasonNode = { name: reason, children: [] };\n hostNode.children.push(reasonNode);\n }\n\n // Create the eventTime node under the reason\n reasonNode.children.push({ name: eventTime });\n }\n\n // Create the tree chart using ECharts\n option = {\n tooltip: {\n trigger: 'item',\n triggerOn: 'mousemove',\n },\n series: [\n {\n type: 'tree',\n data: hierarchy.children, // Use the children directly as root nodes\n top: '1%',\n left: '7%',\n bottom: '1%',\n right: '20%', // Adjust the right margin to provide more space for labels\n symbolSize: 7,\n label: {\n position: 'inside', // Position labels inside the node\n verticalAlign: 'middle',\n align: 'center', // Center-align labels\n fontSize: 15,\n fontWeight: 'bold',\n },\n leaves: {\n label: {\n position: 'right', // Position labels inside the node\n verticalAlign: 'middle',\n align: 'left', // Center-align labels\n fontSize: 15,\n fontWeight: 'bold',\n },\n },\n emphasis: {\n focus: 'descendant',\n },\n expandAndCollapse: true,\n animationDuration: 550,\n animationDurationUpdate: 750,\n },\n ],\n };\n}\n\nreturn option;\n", "google": { "callback": "gmapReady", "key": "" @@ -367,8 +403,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -411,11 +453,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON as before\n const clusterNames = data.series[0].fields[0].values; // New column for ClusterName\n const namespaces = data.series[0].fields[1].values;\n const kinds = data.series[0].fields[2].values; // Adjusted index for Kind\n const counts = data.series[0].fields[3].values; // New column for Count\n\n // Create a hierarchical structure from the data without a root node\n const hierarchy = {\n name: 'root', // Use 'root' as a placeholder\n children: [],\n };\n\n const seenClusterNames = new Set();\n const seenNamespaces = new Set();\n\n for (let i = 0; i < clusterNames.length; i++) {\n const clusterName = clusterNames[i];\n const namespace = namespaces[i];\n const kind = kinds[i];\n const count = counts[i]; // Get the count value\n\n if (!seenClusterNames.has(clusterName)) {\n seenClusterNames.add(clusterName);\n const clusterNode = { name: clusterName, children: [] };\n hierarchy.children.push(clusterNode);\n seenNamespaces.clear(); // Reset seenNamespaces for each cluster\n }\n\n const clusterNode = hierarchy.children.find((node) => node.name === clusterName);\n\n if (!seenNamespaces.has(namespace)) {\n seenNamespaces.add(namespace);\n const namespaceNode = { name: namespace, children: [] };\n clusterNode.children.push(namespaceNode);\n }\n\n const namespaceNode = clusterNode.children.find((node) => node.name === namespace);\n const kindNode = { name: kind, children: [{ name: `Count: ${count}` }] }; // Include the count as a child node\n namespaceNode.children.push(kindNode);\n }\n\n // Create the tree chart using ECharts\n option = {\n tooltip: {\n trigger: 'item',\n triggerOn: 'mousemove',\n formatter: function (params) {\n const node = params.data;\n let tooltip = '';\n if (node.column) {\n tooltip += `${node.column}: ${node.name}`;\n } else {\n tooltip += node.name;\n }\n return tooltip;\n },\n },\n series: [\n {\n type: 'tree',\n data: hierarchy.children, // Use the children directly\n top: '1%',\n left: '7%',\n bottom: '1%',\n right: '20%',\n symbolSize: 7,\n label: {\n position: 'left',\n verticalAlign: 'middle',\n align: 'right',\n fontSize: 15, // Increase the text size for regular nodes\n fontWeight: 'bold', // Set the font weight to bold\n },\n leaves: {\n label: {\n position: 'right',\n verticalAlign: 'middle',\n align: 'left',\n fontSize: 15, // Increase the text size for leaves\n fontWeight: 'bold', // Set the font weight to bold\n },\n },\n emphasis: {\n focus: 'descendant',\n },\n expandAndCollapse: true,\n animationDuration: 550,\n animationDurationUpdate: 750,\n },\n ],\n };\n}\n\nreturn option;\n", + "getOption": "let option; // Initialize the option variable\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON as before\n const clusterNames = context.panel.data.series[0].fields[0].values; // New column for ClusterName\n const namespaces = context.panel.data.series[0].fields[1].values;\n const kinds = context.panel.data.series[0].fields[2].values; // Adjusted index for Kind\n const counts = context.panel.data.series[0].fields[3].values; // New column for Count\n\n // Create a hierarchical structure from the data without a root node\n const hierarchy = {\n name: 'root', // Use 'root' as a placeholder\n children: [],\n };\n\n const seenClusterNames = new Set();\n const seenNamespaces = new Set();\n\n for (let i = 0; i < clusterNames.length; i++) {\n const clusterName = clusterNames[i];\n const namespace = namespaces[i];\n const kind = kinds[i];\n const count = counts[i]; // Get the count value\n\n if (!seenClusterNames.has(clusterName)) {\n seenClusterNames.add(clusterName);\n const clusterNode = { name: clusterName, children: [] };\n hierarchy.children.push(clusterNode);\n seenNamespaces.clear(); // Reset seenNamespaces for each cluster\n }\n\n const clusterNode = hierarchy.children.find((node) => node.name === clusterName);\n\n if (!seenNamespaces.has(namespace)) {\n seenNamespaces.add(namespace);\n const namespaceNode = { name: namespace, children: [] };\n clusterNode.children.push(namespaceNode);\n }\n\n const namespaceNode = clusterNode.children.find((node) => node.name === namespace);\n const kindNode = { name: kind, children: [{ name: `Count: ${count}` }] }; // Include the count as a child node\n namespaceNode.children.push(kindNode);\n }\n\n // Create the tree chart using ECharts\n option = {\n tooltip: {\n trigger: 'item',\n triggerOn: 'mousemove',\n formatter: function (params) {\n const node = params.data;\n let tooltip = '';\n if (node.column) {\n tooltip += `${node.column}: ${node.name}`;\n } else {\n tooltip += node.name;\n }\n return tooltip;\n },\n },\n series: [\n {\n type: 'tree',\n data: hierarchy.children, // Use the children directly\n top: '1%',\n left: '7%',\n bottom: '1%',\n right: '20%',\n symbolSize: 7,\n label: {\n position: 'left',\n verticalAlign: 'middle',\n align: 'right',\n fontSize: 15, // Increase the text size for regular nodes\n fontWeight: 'bold', // Set the font weight to bold\n },\n leaves: {\n label: {\n position: 'right',\n verticalAlign: 'middle',\n align: 'left',\n fontSize: 15, // Increase the text size for leaves\n fontWeight: 'bold', // Set the font weight to bold\n },\n },\n emphasis: {\n focus: 'descendant',\n },\n expandAndCollapse: true,\n animationDuration: 550,\n animationDurationUpdate: 750,\n },\n ],\n };\n}\n\nreturn option;\n", "google": { "callback": "gmapReady", "key": "" @@ -426,8 +469,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -466,8 +515,7 @@ data: "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -706,8 +754,9 @@ data: "timezone": "", "title": "Kubedata", "uid": "Qq-FK1rVz", - "version": 2, + "version": 3, "weekStart": "" } + {{- end }} \ No newline at end of file diff --git a/charts/client/templates/configmap-kuberhealthy-dashboard.yaml b/charts/client/templates/configmap-kuberhealthy-dashboard.yaml index 6221c6ac..70e94c26 100644 --- a/charts/client/templates/configmap-kuberhealthy-dashboard.yaml +++ b/charts/client/templates/configmap-kuberhealthy-dashboard.yaml @@ -56,7 +56,7 @@ data: "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON as before\n const namespaces = data.series[0].fields[0].values;\n const counts = data.series[0].fields[1].values;\n\n // Create a hierarchical structure from the data with a default cluster node\n const hierarchy = {\n name: 'CheckName', // Default cluster node\n children: [],\n };\n\n // Create an object to store namespaces and their counts\n const namespaceCounts = {};\n\n // Populate the namespaceCounts object with namespaces and counts\n for (let i = 0; i < namespaces.length; i++) {\n const namespace = namespaces[i];\n const count = counts[i];\n\n if (!namespaceCounts[namespace]) {\n namespaceCounts[namespace] = count;\n } else {\n namespaceCounts[namespace] += count;\n }\n }\n\n // Create nodes for each namespace and add them as children of the default cluster node\n for (const namespace in namespaceCounts) {\n hierarchy.children.push({\n name: namespace,\n children: [{ name: `${namespaceCounts[namespace]}` }],\n });\n }\n\n // Create the tree chart using ECharts\n option = {\n tooltip: {\n trigger: 'item',\n triggerOn: 'mousemove',\n formatter: function (params) {\n const node = params.data;\n let tooltip = '';\n if (node.column) {\n tooltip += `${node.column}: ${node.name}`;\n } else {\n tooltip += node.name;\n }\n return tooltip;\n },\n },\n series: [\n {\n type: 'tree',\n data: [hierarchy], // Use the hierarchy object as the data\n top: '1%',\n left: '7%',\n bottom: '1%',\n right: '20%',\n symbolSize: 7,\n label: {\n position: 'left',\n verticalAlign: 'middle',\n align: 'centre',\n fontSize: 15, // Increase the text size for regular nodes\n fontWeight: 'bold', // Set the font weight to bold\n },\n leaves: {\n label: {\n position: 'right',\n verticalAlign: 'middle',\n align: 'left',\n fontSize: 15, // Increase the text size for leaves\n fontWeight: 'bold', // Set the font weight to bold\n },\n },\n emphasis: {\n focus: 'descendant',\n },\n expandAndCollapse: true,\n animationDuration: 550,\n animationDurationUpdate: 750,\n },\n ],\n };\n}\n\nreturn option;\n", + "getOption": "let option; // Initialize the option variable\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON as before\n const namespaces = context.panel.data.series[0].fields[0].values;\n const counts = context.panel.data.series[0].fields[1].values;\n\n // Create a hierarchical structure from the data with a default cluster node\n const hierarchy = {\n name: 'CheckName', // Default cluster node\n children: [],\n };\n\n // Create an object to store namespaces and their counts\n const namespaceCounts = {};\n\n // Populate the namespaceCounts object with namespaces and counts\n for (let i = 0; i < namespaces.length; i++) {\n const namespace = namespaces[i];\n const count = counts[i];\n\n if (!namespaceCounts[namespace]) {\n namespaceCounts[namespace] = count;\n } else {\n namespaceCounts[namespace] += count;\n }\n }\n\n // Create nodes for each namespace and add them as children of the default cluster node\n for (const namespace in namespaceCounts) {\n hierarchy.children.push({\n name: namespace,\n children: [{ name: `${namespaceCounts[namespace]}` }],\n });\n }\n\n // Create the tree chart using ECharts\n option = {\n tooltip: {\n trigger: 'item',\n triggerOn: 'mousemove',\n formatter: function (params) {\n const node = params.data;\n let tooltip = '';\n if (node.column) {\n tooltip += `${node.column}: ${node.name}`;\n } else {\n tooltip += node.name;\n }\n return tooltip;\n },\n },\n series: [\n {\n type: 'tree',\n data: [hierarchy], // Use the hierarchy object as the data\n top: '1%',\n left: '7%',\n bottom: '1%',\n right: '20%',\n symbolSize: 7,\n label: {\n position: 'left',\n verticalAlign: 'middle',\n align: 'centre',\n fontSize: 15, // Increase the text size for regular nodes\n fontWeight: 'bold', // Set the font weight to bold\n },\n leaves: {\n label: {\n position: 'right',\n verticalAlign: 'middle',\n align: 'left',\n fontSize: 15, // Increase the text size for leaves\n fontWeight: 'bold', // Set the font weight to bold\n },\n },\n emphasis: {\n focus: 'descendant',\n },\n expandAndCollapse: true,\n animationDuration: 550,\n animationDurationUpdate: 750,\n },\n ],\n };\n}\n\nreturn option;\n", "google": { "callback": "gmapReady", "key": "" @@ -124,7 +124,7 @@ data: "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON as before\n const namespaces = data.series[0].fields[0].values;\n const counts = data.series[0].fields[1].values;\n\n // Create a hierarchical structure from the data with a default cluster node\n const hierarchy = {\n name: 'CheckName', // Default cluster node\n children: [],\n };\n\n // Create an object to store namespaces and their counts\n const namespaceCounts = {};\n\n // Populate the namespaceCounts object with namespaces and counts\n for (let i = 0; i < namespaces.length; i++) {\n const namespace = namespaces[i];\n const count = counts[i];\n\n if (!namespaceCounts[namespace]) {\n namespaceCounts[namespace] = count;\n } else {\n namespaceCounts[namespace] += count;\n }\n }\n\n // Create nodes for each namespace and add them as children of the default cluster node\n for (const namespace in namespaceCounts) {\n hierarchy.children.push({\n name: namespace,\n children: [{ name: `${namespaceCounts[namespace]}` }],\n });\n }\n\n // Create the tree chart using ECharts\n option = {\n tooltip: {\n trigger: 'item',\n triggerOn: 'mousemove',\n formatter: function (params) {\n const node = params.data;\n let tooltip = '';\n if (node.column) {\n tooltip += `${node.column}: ${node.name}`;\n } else {\n tooltip += node.name;\n }\n return tooltip;\n },\n },\n series: [\n {\n type: 'tree',\n data: [hierarchy], // Use the hierarchy object as the data\n top: '1%',\n left: '7%',\n bottom: '1%',\n right: '20%',\n symbolSize: 7,\n label: {\n position: 'left',\n verticalAlign: 'middle',\n align: 'centre',\n fontSize: 15, // Increase the text size for regular nodes\n fontWeight: 'bold', // Set the font weight to bold\n },\n leaves: {\n label: {\n position: 'right',\n verticalAlign: 'middle',\n align: 'left',\n fontSize: 15, // Increase the text size for leaves\n fontWeight: 'bold', // Set the font weight to bold\n },\n },\n emphasis: {\n focus: 'descendant',\n },\n expandAndCollapse: true,\n animationDuration: 550,\n animationDurationUpdate: 750,\n },\n ],\n };\n}\n\nreturn option;\n", + "getOption": "let option; // Initialize the option variable\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON as before\n const namespaces = context.panel.data.series[0].fields[0].values;\n const counts = context.panel.data.series[0].fields[1].values;\n\n // Create a hierarchical structure from the data with a default cluster node\n const hierarchy = {\n name: 'CheckName', // Default cluster node\n children: [],\n };\n\n // Create an object to store namespaces and their counts\n const namespaceCounts = {};\n\n // Populate the namespaceCounts object with namespaces and counts\n for (let i = 0; i < namespaces.length; i++) {\n const namespace = namespaces[i];\n const count = counts[i];\n\n if (!namespaceCounts[namespace]) {\n namespaceCounts[namespace] = count;\n } else {\n namespaceCounts[namespace] += count;\n }\n }\n\n // Create nodes for each namespace and add them as children of the default cluster node\n for (const namespace in namespaceCounts) {\n hierarchy.children.push({\n name: namespace,\n children: [{ name: `${namespaceCounts[namespace]}` }],\n });\n }\n\n // Create the tree chart using ECharts\n option = {\n tooltip: {\n trigger: 'item',\n triggerOn: 'mousemove',\n formatter: function (params) {\n const node = params.data;\n let tooltip = '';\n if (node.column) {\n tooltip += `${node.column}: ${node.name}`;\n } else {\n tooltip += node.name;\n }\n return tooltip;\n },\n },\n series: [\n {\n type: 'tree',\n data: [hierarchy], // Use the hierarchy object as the data\n top: '1%',\n left: '7%',\n bottom: '1%',\n right: '20%',\n symbolSize: 7,\n label: {\n position: 'left',\n verticalAlign: 'middle',\n align: 'centre',\n fontSize: 15, // Increase the text size for regular nodes\n fontWeight: 'bold', // Set the font weight to bold\n },\n leaves: {\n label: {\n position: 'right',\n verticalAlign: 'middle',\n align: 'left',\n fontSize: 15, // Increase the text size for leaves\n fontWeight: 'bold', // Set the font weight to bold\n },\n },\n emphasis: {\n focus: 'descendant',\n },\n expandAndCollapse: true,\n animationDuration: 550,\n animationDurationUpdate: 750,\n },\n ],\n };\n}\n\nreturn option;\n", "google": { "callback": "gmapReady", "key": "" @@ -1210,7 +1210,8 @@ data: "timezone": "", "title": "KuberHealth", "uid": "d946c53c-8b1d-4e3c-9154-4219165342", - "version": 2, + "version": 3, "weekStart": "" } + {{- end }} \ No newline at end of file diff --git a/charts/client/templates/configmap-kubviz-dashboard.yaml b/charts/client/templates/configmap-kubviz-dashboard.yaml index 6ee2c56c..206fc3d8 100644 --- a/charts/client/templates/configmap-kubviz-dashboard.yaml +++ b/charts/client/templates/configmap-kubviz-dashboard.yaml @@ -32,7 +32,7 @@ data: "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 32, + "id": 64, "links": [], "liveNow": false, "panels": [ @@ -205,11 +205,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "// Check if data.series exists\nif (data.series && data.series.length > 0) {\n const reasons = data.series[0].fields[0].values;\n const kinds = data.series[0].fields[1].values;\n const eventTimes = data.series[0].fields[2].values;\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n reasons.forEach((reason, index) => {\n const sourceNode = {\n name: reason,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const kindNode = {\n name: kinds[index],\n category: 1, // Category for kind nodes\n symbolSize: 40, // Size for kind nodes\n };\n\n const eventTimeNode = {\n name: eventTimes[index],\n category: 2, // Category for eventTime nodes\n symbolSize: 20, // Size for eventTime nodes\n };\n\n // Ensure source, kind, and eventTime nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === kindNode.name)) {\n nodes.push(kindNode);\n }\n\n if (!nodes.some((node) => node.name === eventTimeNode.name)) {\n nodes.push(eventTimeNode);\n }\n\n // Create links between reason, kind, and eventTime nodes\n links.push({\n source: reason,\n target: kinds[index],\n });\n\n links.push({\n source: kinds[index],\n target: eventTimes[index],\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Reasons',\n },\n {\n name: 'Nodes',\n },\n {\n name: 'Event Times',\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Reasons', 'Nodes', 'Event Times'],\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: {\n color: '#000',\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n edgeSymbolSize: [12, 12],\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Handle the case when data.series does not exist\n return {};\n}", + "getOption": "// Check if context.panel.data.series exists\nif (context.panel.data.series && context.panel.data.series.length > 0) {\n const reasons = context.panel.data.series[0].fields[0].values;\n const kinds = context.panel.data.series[0].fields[1].values;\n const eventTimes = context.panel.data.series[0].fields[2].values;\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n reasons.forEach((reason, index) => {\n const sourceNode = {\n name: reason,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const kindNode = {\n name: kinds[index],\n category: 1, // Category for kind nodes\n symbolSize: 40, // Size for kind nodes\n };\n\n const eventTimeNode = {\n name: eventTimes[index],\n category: 2, // Category for eventTime nodes\n symbolSize: 20, // Size for eventTime nodes\n };\n\n // Ensure source, kind, and eventTime nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === kindNode.name)) {\n nodes.push(kindNode);\n }\n\n if (!nodes.some((node) => node.name === eventTimeNode.name)) {\n nodes.push(eventTimeNode);\n }\n\n // Create links between reason, kind, and eventTime nodes\n links.push({\n source: reason,\n target: kinds[index],\n });\n\n links.push({\n source: kinds[index],\n target: eventTimes[index],\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Reasons',\n },\n {\n name: 'Nodes',\n },\n {\n name: 'Event Times',\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Reasons', 'Nodes', 'Event Times'],\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: {\n color: '#000',\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n edgeSymbolSize: [12, 12],\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Display \"Data not available\" in the panel\n return {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n}\n", "google": { "callback": "gmapReady", "key": "" @@ -220,8 +221,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -264,11 +271,12 @@ data: "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let kind = [];\nlet resources = [];\n\ndata.series.map((s) => {\n kind = s.fields.find((f) => f.name === 'Kind').values;\n resources = s.fields.find((f) => f.name === 'Resources').values;\n});\n\n// Create an empty array to store doughnut chart data\nconst doughnutChartData = [];\n\n// Define colors for doughnut slices\nconst doughnutSliceColors = ['#235894', '#FFFF00', '#FF0000', '#00FF00', '#FFA500'];\n\n// Map severity and counts to doughnut chart data\nkind.forEach((kinddata, index) => {\n doughnutChartData.push({\n value: resources[index],\n name: kinddata,\n itemStyle: {\n borderRadius: [10, 10, 10, 10], // Add rounded corners\n color: doughnutSliceColors[index % doughnutSliceColors.length],\n borderWidth: 2,\n borderColor: '#fff',\n },\n });\n});\n\nreturn {\n backgroundColor: '#FFFFFF', // Set the background color to white\n tooltip: {\n trigger: 'item',\n },\n legend: {\n top: '5%',\n left: 'center',\n },\n series: [\n {\n name: 'Access From',\n type: 'pie',\n radius: ['40%', '70%'],\n avoidLabelOverlap: false,\n label: {\n show: false,\n position: 'center',\n },\n emphasis: {\n label: {\n show: true,\n fontSize: 40,\n fontWeight: 'bold',\n },\n },\n labelLine: {\n show: false,\n },\n data: doughnutChartData, // Use the modified doughnut chart data\n },\n ],\n};", + "getOption": "let kind = [];\nlet resources = [];\n\ncontext.panel.data.series.forEach((s) => {\n const kindField = s.fields.find((f) => f.name === 'Kind');\n const resourcesField = s.fields.find((f) => f.name === 'Resources');\n if (kindField && resourcesField) {\n kind = kindField.values;\n resources = resourcesField.values;\n }\n});\n\n// Create an empty array to store doughnut chart data\nconst doughnutChartData = [];\n\n// Define colors for doughnut slices\nconst doughnutSliceColors = ['#235894', '#FFFF00', '#FF0000', '#00FF00', '#FFA500'];\n\n// Map kind and resources counts to doughnut chart data\nkind.forEach((kinddata, index) => {\n doughnutChartData.push({\n value: resources[index],\n name: kinddata,\n clusterName: context.panel.data.series[0].fields[0].values[index], // Extract cluster name\n itemStyle: {\n borderRadius: [10, 10, 10, 10], // Add rounded corners\n color: doughnutSliceColors[index % doughnutSliceColors.length],\n borderWidth: 2,\n borderColor: '#fff',\n },\n });\n});\n\nreturn {\n backgroundColor: '#FFFFFF', // Set the background color to white\n tooltip: {\n trigger: 'item',\n formatter: function (params) {\n return `Resource From
${params.data.clusterName} ${params.value}`;\n },\n },\n legend: {\n top: '5%',\n left: 'center',\n },\n series: [\n {\n name: '',\n type: 'pie',\n radius: ['40%', '70%'],\n avoidLabelOverlap: false,\n label: {\n show: false,\n position: 'center',\n },\n emphasis: {\n label: {\n show: true,\n fontSize: 40,\n fontWeight: 'bold',\n },\n },\n labelLine: {\n show: false,\n },\n data: doughnutChartData, // Use the modified doughnut chart data\n },\n ],\n};\n", "google": { "callback": "gmapReady", "key": "" @@ -279,8 +287,14 @@ data: "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -576,8 +590,7 @@ data: "mode": "percentage", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -646,8 +659,7 @@ data: "mode": "percentage", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -716,8 +728,7 @@ data: "mode": "percentage", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -786,8 +797,7 @@ data: "mode": "percentage", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -856,8 +866,7 @@ data: "mode": "percentage", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -959,8 +968,7 @@ data: "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -1060,8 +1068,7 @@ data: "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -3112,7 +3119,8 @@ data: "timezone": "", "title": "Kubviz Dashboard", "uid": "eT4fox94z", - "version": 1, + "version": 4, "weekStart": "" } + {{- end }} \ No newline at end of file diff --git a/charts/client/templates/configmap-trivy-dashboard.yaml b/charts/client/templates/configmap-trivy-dashboard.yaml index d762bc19..93ef604e 100644 --- a/charts/client/templates/configmap-trivy-dashboard.yaml +++ b/charts/client/templates/configmap-trivy-dashboard.yaml @@ -32,7 +32,7 @@ data: "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 106, + "id": 58, "links": [], "liveNow": false, "panels": [ @@ -140,12 +140,13 @@ data: "uid": "{{ .Values.datasources.uid }}" }, "dateTimeType": "DATETIME", + "editorMode": "builder", "extrapolate": true, "format": "table", "formattedQuery": "SELECT $timeSeries as t, count() FROM $table WHERE $timeFilter GROUP BY t ORDER BY t", "intervalFactor": 1, - "query": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_severity = 'LOW'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", - "rawQuery": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_severity = 'LOW'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", + "query": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE $timeFilterByColumn(vul_last_modified_date) AND vul_severity = 'LOW'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", + "rawQuery": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_last_modified_date >= toDateTime(1712241666) AND vul_last_modified_date <= toDateTime(1712328066) AND vul_severity = 'LOW'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", "refId": "A", "round": "0s", "skip_comments": true @@ -247,12 +248,13 @@ data: "uid": "{{ .Values.datasources.uid }}" }, "dateTimeType": "DATETIME", + "editorMode": "builder", "extrapolate": true, "format": "table", "formattedQuery": "SELECT $timeSeries as t, count() FROM $table WHERE $timeFilter GROUP BY t ORDER BY t", "intervalFactor": 1, - "query": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_severity = 'HIGH'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", - "rawQuery": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_severity = 'HIGH'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", + "query": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE $timeFilterByColumn(vul_last_modified_date) AND vul_severity = 'HIGH'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", + "rawQuery": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_last_modified_date >= toDateTime(1712241678) AND vul_last_modified_date <= toDateTime(1712328078) AND vul_severity = 'HIGH'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", "refId": "A", "round": "0s", "skip_comments": true @@ -354,12 +356,13 @@ data: "uid": "{{ .Values.datasources.uid }}" }, "dateTimeType": "DATETIME", + "editorMode": "builder", "extrapolate": true, "format": "table", "formattedQuery": "SELECT $timeSeries as t, count() FROM $table WHERE $timeFilter GROUP BY t ORDER BY t", "intervalFactor": 1, - "query": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_severity = 'MEDIUM'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", - "rawQuery": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_severity = 'MEDIUM'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", + "query": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE $timeFilterByColumn(vul_last_modified_date) AND vul_severity = 'MEDIUM'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", + "rawQuery": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_last_modified_date >= toDateTime(1712241603) AND vul_last_modified_date <= toDateTime(1712328003) AND vul_severity = 'MEDIUM'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", "refId": "A", "round": "0s", "skip_comments": true @@ -461,12 +464,13 @@ data: "uid": "{{ .Values.datasources.uid }}" }, "dateTimeType": "DATETIME", + "editorMode": "builder", "extrapolate": true, "format": "table", "formattedQuery": "SELECT $timeSeries as t, count() FROM $table WHERE $timeFilter GROUP BY t ORDER BY t", "intervalFactor": 1, - "query": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_severity = 'CRITICAL'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", - "rawQuery": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_severity = 'CRITICAL'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", + "query": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE $timeFilterByColumn(vul_last_modified_date) AND vul_severity = 'CRITICAL'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", + "rawQuery": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_last_modified_date >= toDateTime(1712241618) AND vul_last_modified_date <= toDateTime(1712328018) AND vul_severity = 'CRITICAL'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", "refId": "A", "round": "0s", "skip_comments": true @@ -498,8 +502,7 @@ data: "mode": "absolute", "steps": [ { - "color": "light-blue", - "value": null + "color": "light-blue" } ] } @@ -549,12 +552,13 @@ data: "uid": "{{ .Values.datasources.uid }}" }, "dateTimeType": "DATETIME", + "editorMode": "builder", "extrapolate": true, "format": "table", "formattedQuery": "SELECT $timeSeries as t, count() FROM $table WHERE $timeFilter GROUP BY t ORDER BY t", "intervalFactor": 1, - "query": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_severity = 'LOW'", - "rawQuery": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_severity = 'LOW'", + "query": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE $timeFilterByColumn(vul_last_modified_date) AND vul_severity = 'LOW'", + "rawQuery": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_last_modified_date >= toDateTime(1712241558) AND vul_last_modified_date <= toDateTime(1712327958) AND vul_severity = 'LOW'", "refId": "A", "round": "0s", "skip_comments": true @@ -586,8 +590,7 @@ data: "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" } ] } @@ -637,12 +640,13 @@ data: "uid": "{{ .Values.datasources.uid }}" }, "dateTimeType": "DATETIME", + "editorMode": "builder", "extrapolate": true, "format": "table", "formattedQuery": "SELECT $timeSeries as t, count() FROM $table WHERE $timeFilter GROUP BY t ORDER BY t", "intervalFactor": 1, - "query": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_severity = 'MEDIUM'", - "rawQuery": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_severity = 'MEDIUM'", + "query": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE $timeFilterByColumn(vul_last_modified_date) AND vul_severity = 'MEDIUM'", + "rawQuery": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_last_modified_date >= toDateTime(1712241583) AND vul_last_modified_date <= toDateTime(1712327983) AND vul_severity = 'MEDIUM'", "refId": "A", "round": "0s", "skip_comments": true @@ -674,8 +678,7 @@ data: "mode": "absolute", "steps": [ { - "color": "super-light-orange", - "value": null + "color": "super-light-orange" } ] } @@ -725,12 +728,13 @@ data: "uid": "{{ .Values.datasources.uid }}" }, "dateTimeType": "DATETIME", + "editorMode": "builder", "extrapolate": true, "format": "table", "formattedQuery": "SELECT $timeSeries as t, count() FROM $table WHERE $timeFilter GROUP BY t ORDER BY t", "intervalFactor": 1, - "query": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_severity = 'HIGH'", - "rawQuery": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_severity = 'HIGH'", + "query": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE $timeFilterByColumn(vul_last_modified_date) AND vul_severity = 'HIGH'", + "rawQuery": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_last_modified_date >= toDateTime(1712241526) AND vul_last_modified_date <= toDateTime(1712327926) AND vul_severity = 'HIGH'", "refId": "A", "round": "0s", "skip_comments": true @@ -762,8 +766,7 @@ data: "mode": "absolute", "steps": [ { - "color": "red", - "value": null + "color": "red" } ] } @@ -813,12 +816,13 @@ data: "uid": "{{ .Values.datasources.uid }}" }, "dateTimeType": "DATETIME", + "editorMode": "builder", "extrapolate": true, "format": "table", "formattedQuery": "SELECT $timeSeries as t, count() FROM $table WHERE $timeFilter GROUP BY t ORDER BY t", "intervalFactor": 1, - "query": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_severity = 'CRITICAL'", - "rawQuery": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_severity = 'CRITICAL'", + "query": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE $timeFilterByColumn(vul_last_modified_date) AND vul_severity = 'CRITICAL'", + "rawQuery": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_last_modified_date >= toDateTime(1712241543) AND vul_last_modified_date <= toDateTime(1712327943) AND vul_severity = 'CRITICAL'", "refId": "A", "round": "0s", "skip_comments": true @@ -850,8 +854,7 @@ data: "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -923,8 +926,7 @@ data: "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -978,12 +980,13 @@ data: "uid": "{{ .Values.datasources.uid }}" }, "dateTimeType": "DATETIME", + "editorMode": "builder", "extrapolate": true, "format": "table", "formattedQuery": "SELECT $timeSeries as t, count() FROM $table WHERE $timeFilter GROUP BY t ORDER BY t", "intervalFactor": 1, - "query": "SELECT vul_id, count(artifact_name) AS images\nFROM default.trivyimage\nGROUP BY vul_id", - "rawQuery": "SELECT vul_id, count(artifact_name) AS images\nFROM default.trivyimage\nGROUP BY vul_id", + "query": "SELECT vul_id, count(artifact_name) AS images\nFROM default.trivyimage\nWHERE $timeFilterByColumn(vul_last_modified_date)\nGROUP BY vul_id", + "rawQuery": "SELECT vul_id, count(artifact_name) AS images\nFROM default.trivyimage\nWHERE vul_last_modified_date >= toDateTime(1712241498) AND vul_last_modified_date <= toDateTime(1712327898)\nGROUP BY vul_id", "refId": "A", "round": "0s", "skip_comments": true @@ -1016,8 +1019,7 @@ data: "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" } ] } @@ -1089,8 +1091,7 @@ data: "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" } ] } @@ -2407,7 +2408,8 @@ data: "timezone": "", "title": "Trivy", "uid": "f9b0a865-f419-410a-b7d9-9a3f79a70d48", - "version": 13, + "version": 2, "weekStart": "" } + {{- end }} \ No newline at end of file diff --git a/grafana/azure-dashboard.json b/grafana/azure-dashboard.json index bea62afc..b90566c4 100644 --- a/grafana/azure-dashboard.json +++ b/grafana/azure-dashboard.json @@ -15,7 +15,7 @@ "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 33, + "id": 53, "links": [], "liveNow": false, "panels": [ @@ -40,11 +40,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "// Check if data.series exists\nif (data.series && data.series.length > 0) {\n const eventTypes = data.series[0].fields[0].values;\n const authors = data.series[0].fields[1].values;\n const repoNames = data.series[0].fields[2].values;\n const total = data.series[0].fields[3].values; // Assuming you have a field named \"Total\"\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n authors.forEach((author, index) => {\n const sourceNode = {\n name: author,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const eventTypeNode = {\n name: eventTypes[index],\n category: 1, // Category for eventType nodes\n symbolSize: 40, // Size for eventType nodes\n };\n\n const repoNode = {\n name: repoNames[index],\n category: 2, // Category for repo nodes\n symbolSize: 30, // Size for repo nodes\n };\n\n const totalNode = {\n name: `Total: ${total[index]}`, // Assuming you have an array \"total\"\n category: 3, // Category for total nodes\n symbolSize: 20, // Size for total nodes\n };\n\n // Ensure source, eventType, repo, and total nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === eventTypeNode.name)) {\n nodes.push(eventTypeNode);\n }\n\n if (!nodes.some((node) => node.name === repoNode.name)) {\n nodes.push(repoNode);\n }\n\n if (!nodes.some((node) => node.name === totalNode.name)) {\n nodes.push(totalNode);\n }\n\n // Create links between author, eventType, repo, and total nodes\n links.push({\n source: author,\n target: eventTypes[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: repoNames[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: totalNode.name,\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Authors',\n },\n {\n name: 'Event Type',\n },\n {\n name: 'Repo Names',\n },\n {\n name: 'Total', // Add a category for \"Total\" nodes\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Authors', 'Event Types', 'Repo Names', 'Total'], // Add \"Total\" to legend data\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: { // Add textStyle property to configure text style\n color: '#000', // Set the text color to a brighter color, such as white (#FFF)\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n\n // Increase the size of arrow marks\n edgeSymbolSize: [12, 12], // Set the arrow size here\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Display a custom message when data is not available\n const option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n\n return option;\n}", + "getOption": "// Check if data.series exists\nif (context.panel.data.series && context.panel.data.series.length > 0) {\n const eventTypes = context.panel.data.series[0].fields[0].values;\n const authors = context.panel.data.series[0].fields[1].values;\n const repoNames = context.panel.data.series[0].fields[2].values;\n const total = context.panel.data.series[0].fields[3].values; // Assuming you have a field named \"Total\"\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n authors.forEach((author, index) => {\n const sourceNode = {\n name: author,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const eventTypeNode = {\n name: eventTypes[index],\n category: 1, // Category for eventType nodes\n symbolSize: 40, // Size for eventType nodes\n };\n\n const repoNode = {\n name: repoNames[index],\n category: 2, // Category for repo nodes\n symbolSize: 30, // Size for repo nodes\n };\n\n const totalNode = {\n name: `Total: ${total[index]}`, // Assuming you have an array \"total\"\n category: 3, // Category for total nodes\n symbolSize: 20, // Size for total nodes\n };\n\n // Ensure source, eventType, repo, and total nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === eventTypeNode.name)) {\n nodes.push(eventTypeNode);\n }\n\n if (!nodes.some((node) => node.name === repoNode.name)) {\n nodes.push(repoNode);\n }\n\n if (!nodes.some((node) => node.name === totalNode.name)) {\n nodes.push(totalNode);\n }\n\n // Create links between author, eventType, repo, and total nodes\n links.push({\n source: author,\n target: eventTypes[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: repoNames[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: totalNode.name,\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Authors',\n },\n {\n name: 'Event Type',\n },\n {\n name: 'Repo Names',\n },\n {\n name: 'Total', // Add a category for \"Total\" nodes\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Authors', 'Event Types', 'Repo Names', 'Total'], // Add \"Total\" to legend data\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: { // Add textStyle property to configure text style\n color: '#000', // Set the text color to a brighter color, such as white (#FFF)\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n\n // Increase the size of arrow marks\n edgeSymbolSize: [12, 12], // Set the arrow size here\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Display a custom message when data is not available\n const option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n\n return option;\n}", "google": { "callback": "gmapReady", "key": "" @@ -55,8 +56,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -99,11 +106,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let options; // Initialize the options variable\n\nif (!data || !data.series || data.series.length === 0 || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n options = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract Author and Push_Events data from the series\n const categories = data.series[0].fields.find((f) => f.name === 'Author').values;\n const pushEvents = data.series[0].fields.find((f) => f.name === 'Push_Events').values;\n\n // Create the ECharts options\n options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Push_Events'],\n orient: 'vertical', // Change the orientation to vertical\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: pushEvents,\n type: 'line',\n areaStyle: {\n color: 'rgba(0, 128, 255, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'blue', // Set the line color\n },\n name: 'Push_Events',\n },\n ],\n };\n}\n\nreturn options;\n", + "getOption": "let options; // Initialize the options variable\n\nif (!context.panel.data || !context.panel.data.series || context.panel.data.series.length === 0 || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n options = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract Author and Push_Events data from the series\n const categories = context.panel.data.series[0].fields.find((f) => f.name === 'Author').values;\n const pushEvents = context.panel.data.series[0].fields.find((f) => f.name === 'Push_Events').values;\n\n // Create the ECharts options\n options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Push_Events'],\n orient: 'vertical', // Change the orientation to vertical\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: pushEvents,\n type: 'line',\n areaStyle: {\n color: 'rgba(0, 128, 255, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'blue', // Set the line color\n },\n name: 'Push_Events',\n },\n ],\n };\n}\n\nreturn options;\n", "google": { "callback": "gmapReady", "key": "" @@ -114,8 +122,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -158,11 +172,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\n// Define a default options object\nconst defaultOptions = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n};\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = defaultOptions;\n} else {\n // Extract Author and Merge_Events data from the series\n const categories = data.series[0].fields.find((f) => f.name === 'Author').values;\n const mergeEvents = data.series[0].fields.find((f) => f.name === 'Merge_Events').values;\n\n // Create the ECharts options\n const options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Merge_Events'],\n orient: 'vertical',\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: mergeEvents,\n type: 'line',\n name: 'Merge_Events',\n areaStyle: {\n color: 'rgba(255, 0, 0, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'red', // Set the line color\n },\n },\n ],\n };\n\n option = options; // Assign the options to the outer variable\n}\n\nreturn option;\n", + "getOption": "let option; // Initialize the option variable\n\n// Define a default options object\nconst defaultOptions = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n};\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = defaultOptions;\n} else {\n // Extract Author and Merge_Events data from the series\n const categories = context.panel.data.series[0].fields.find((f) => f.name === 'Author').values;\n const mergeEvents = context.panel.data.series[0].fields.find((f) => f.name === 'Merge_Events').values;\n\n // Create the ECharts options\n const options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Merge_Events'],\n orient: 'vertical',\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: mergeEvents,\n type: 'line',\n name: 'Merge_Events',\n areaStyle: {\n color: 'rgba(255, 0, 0, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'red', // Set the line color\n },\n },\n ],\n };\n\n option = options; // Assign the options to the outer variable\n}\n\nreturn option;\n", "google": { "callback": "gmapReady", "key": "" @@ -173,8 +188,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -212,7 +233,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -282,7 +304,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -359,7 +382,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null } ] } @@ -415,7 +439,11 @@ "templating": { "list": [ { - "current": {}, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, "datasource": { "type": "vertamedia-clickhouse-datasource", "uid": "vertamedia-clickhouse-datasource" @@ -434,7 +462,11 @@ "type": "query" }, { - "current": {}, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, "datasource": { "type": "vertamedia-clickhouse-datasource", "uid": "vertamedia-clickhouse-datasource" @@ -462,6 +494,6 @@ "timezone": "", "title": "Azure", "uid": "dd66838a-ffda-4de2-944f-1828d1671fc9", - "version": 1, + "version": 2, "weekStart": "" -} \ No newline at end of file +} diff --git a/grafana/bitBucket-dashboard.json b/grafana/bitBucket-dashboard.json index 389c001c..63d77351 100644 --- a/grafana/bitBucket-dashboard.json +++ b/grafana/bitBucket-dashboard.json @@ -15,7 +15,7 @@ "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 34, + "id": 60, "links": [], "liveNow": false, "panels": [ @@ -40,11 +40,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "// Check if data.series exists\nif (data.series && data.series.length > 0) {\n const eventTypes = data.series[0].fields[0].values;\n const authors = data.series[0].fields[1].values;\n const repoNames = data.series[0].fields[2].values;\n const total = data.series[0].fields[3].values; // Assuming you have a field named \"Total\"\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n authors.forEach((author, index) => {\n const sourceNode = {\n name: author,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const eventTypeNode = {\n name: eventTypes[index],\n category: 1, // Category for eventType nodes\n symbolSize: 40, // Size for eventType nodes\n };\n\n const repoNode = {\n name: repoNames[index],\n category: 2, // Category for repo nodes\n symbolSize: 30, // Size for repo nodes\n };\n\n const totalNode = {\n name: `Total: ${total[index]}`, // Assuming you have an array \"total\"\n category: 3, // Category for total nodes\n symbolSize: 20, // Size for total nodes\n };\n\n // Ensure source, eventType, repo, and total nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === eventTypeNode.name)) {\n nodes.push(eventTypeNode);\n }\n\n if (!nodes.some((node) => node.name === repoNode.name)) {\n nodes.push(repoNode);\n }\n\n if (!nodes.some((node) => node.name === totalNode.name)) {\n nodes.push(totalNode);\n }\n\n // Create links between author, eventType, repo, and total nodes\n links.push({\n source: author,\n target: eventTypes[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: repoNames[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: totalNode.name,\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Authors',\n },\n {\n name: 'Event Type',\n },\n {\n name: 'Repo Names',\n },\n {\n name: 'Total', // Add a category for \"Total\" nodes\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Authors', 'Event Types', 'Repo Names', 'Total'], // Add \"Total\" to legend data\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: { // Add textStyle property to configure text style\n color: '#000', // Set the text color to a brighter color, such as white (#FFF)\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n\n // Increase the size of arrow marks\n edgeSymbolSize: [12, 12], // Set the arrow size here\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Display a custom message when data is not available\n const option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n\n return option;\n}", + "getOption": "// Check if data.series exists\nif (context.panel.data.series && context.panel.data.series.length > 0) {\n const eventTypes = context.panel.data.series[0].fields[0].values;\n const authors = context.panel.data.series[0].fields[1].values;\n const repoNames = context.panel.data.series[0].fields[2].values;\n const total = context.panel.data.series[0].fields[3].values; // Assuming you have a field named \"Total\"\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n authors.forEach((author, index) => {\n const sourceNode = {\n name: author,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const eventTypeNode = {\n name: eventTypes[index],\n category: 1, // Category for eventType nodes\n symbolSize: 40, // Size for eventType nodes\n };\n\n const repoNode = {\n name: repoNames[index],\n category: 2, // Category for repo nodes\n symbolSize: 30, // Size for repo nodes\n };\n\n const totalNode = {\n name: `Total: ${total[index]}`, // Assuming you have an array \"total\"\n category: 3, // Category for total nodes\n symbolSize: 20, // Size for total nodes\n };\n\n // Ensure source, eventType, repo, and total nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === eventTypeNode.name)) {\n nodes.push(eventTypeNode);\n }\n\n if (!nodes.some((node) => node.name === repoNode.name)) {\n nodes.push(repoNode);\n }\n\n if (!nodes.some((node) => node.name === totalNode.name)) {\n nodes.push(totalNode);\n }\n\n // Create links between author, eventType, repo, and total nodes\n links.push({\n source: author,\n target: eventTypes[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: repoNames[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: totalNode.name,\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Authors',\n },\n {\n name: 'Event Type',\n },\n {\n name: 'Repo Names',\n },\n {\n name: 'Total', // Add a category for \"Total\" nodes\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Authors', 'Event Types', 'Repo Names', 'Total'], // Add \"Total\" to legend data\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: { // Add textStyle property to configure text style\n color: '#000', // Set the text color to a brighter color, such as white (#FFF)\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n\n // Increase the size of arrow marks\n edgeSymbolSize: [12, 12], // Set the arrow size here\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Display a custom message when data is not available\n const option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n\n return option;\n}", "google": { "callback": "gmapReady", "key": "" @@ -55,8 +56,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -99,11 +106,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let options; // Initialize the options variable\n\nif (!data || !data.series || data.series.length === 0 || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n options = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract Author and Push_Events data from the series\n const categories = data.series[0].fields.find((f) => f.name === 'Author').values;\n const pushEvents = data.series[0].fields.find((f) => f.name === 'Push_Events').values;\n\n // Create the ECharts options\n options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Push_Events'],\n orient: 'vertical', // Change the orientation to vertical\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: pushEvents,\n type: 'line',\n areaStyle: {\n color: 'rgba(0, 128, 255, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'blue', // Set the line color\n },\n name: 'Push_Events',\n },\n ],\n };\n}\n\nreturn options;\n", + "getOption": "let options; // Initialize the options variable\n\nif (!context.panel.data || !context.panel.data.series || context.panel.data.series.length === 0 || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n options = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract Author and Push_Events data from the series\n const categories = context.panel.data.series[0].fields.find((f) => f.name === 'Author').values;\n const pushEvents = context.panel.data.series[0].fields.find((f) => f.name === 'Push_Events').values;\n\n // Create the ECharts options\n options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Push_Events'],\n orient: 'vertical', // Change the orientation to vertical\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: pushEvents,\n type: 'line',\n areaStyle: {\n color: 'rgba(0, 128, 255, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'blue', // Set the line color\n },\n name: 'Push_Events',\n },\n ],\n };\n}\n\nreturn options;\n", "google": { "callback": "gmapReady", "key": "" @@ -114,8 +122,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -158,11 +172,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\n// Define a default options object\nconst defaultOptions = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n};\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = defaultOptions;\n} else {\n // Extract Author and Merge_Events data from the series\n const categories = data.series[0].fields.find((f) => f.name === 'Author').values;\n const mergeEvents = data.series[0].fields.find((f) => f.name === 'Merge_Events').values;\n\n // Create the ECharts options\n const options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Merge_Events'],\n orient: 'vertical',\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: mergeEvents,\n type: 'line',\n name: 'Merge_Events',\n areaStyle: {\n color: 'rgba(255, 0, 0, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'red', // Set the line color\n },\n },\n ],\n };\n\n option = options; // Assign the options to the outer variable\n}\n\nreturn option;\n", + "getOption": "let option; // Initialize the option variable\n\n// Define a default options object\nconst defaultOptions = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n};\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = defaultOptions;\n} else {\n // Extract Author and Merge_Events data from the series\n const categories = context.panel.data.series[0].fields.find((f) => f.name === 'Author').values;\n const mergeEvents = context.panel.data.series[0].fields.find((f) => f.name === 'Merge_Events').values;\n\n // Create the ECharts options\n const options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Merge_Events'],\n orient: 'vertical',\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: mergeEvents,\n type: 'line',\n name: 'Merge_Events',\n areaStyle: {\n color: 'rgba(255, 0, 0, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'red', // Set the line color\n },\n },\n ],\n };\n\n option = options; // Assign the options to the outer variable\n}\n\nreturn option;\n", "google": { "callback": "gmapReady", "key": "" @@ -173,8 +188,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -212,7 +233,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -282,7 +304,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -440,8 +463,8 @@ { "current": { "selected": false, - "text": "", - "value": "" + "text": "All", + "value": "$__all" }, "datasource": { "type": "vertamedia-clickhouse-datasource", @@ -470,6 +493,6 @@ "timezone": "", "title": "BitBucket", "uid": "a7772dd5-76c7-48f3-8462-b39fbc20941c", - "version": 1, + "version": 2, "weekStart": "" -} \ No newline at end of file +} diff --git a/grafana/giTea-dashboard.json b/grafana/giTea-dashboard.json index da0e63a2..9dccd2af 100644 --- a/grafana/giTea-dashboard.json +++ b/grafana/giTea-dashboard.json @@ -15,7 +15,7 @@ "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 35, + "id": 61, "links": [], "liveNow": false, "panels": [ @@ -40,11 +40,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "// Check if data.series exists\nif (data.series && data.series.length > 0) {\n const eventTypes = data.series[0].fields[0].values;\n const authors = data.series[0].fields[1].values;\n const repoNames = data.series[0].fields[2].values;\n const total = data.series[0].fields[3].values; // Assuming you have a field named \"Total\"\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n authors.forEach((author, index) => {\n const sourceNode = {\n name: author,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const eventTypeNode = {\n name: eventTypes[index],\n category: 1, // Category for eventType nodes\n symbolSize: 40, // Size for eventType nodes\n };\n\n const repoNode = {\n name: repoNames[index],\n category: 2, // Category for repo nodes\n symbolSize: 30, // Size for repo nodes\n };\n\n const totalNode = {\n name: `Total: ${total[index]}`, // Assuming you have an array \"total\"\n category: 3, // Category for total nodes\n symbolSize: 20, // Size for total nodes\n };\n\n // Ensure source, eventType, repo, and total nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === eventTypeNode.name)) {\n nodes.push(eventTypeNode);\n }\n\n if (!nodes.some((node) => node.name === repoNode.name)) {\n nodes.push(repoNode);\n }\n\n if (!nodes.some((node) => node.name === totalNode.name)) {\n nodes.push(totalNode);\n }\n\n // Create links between author, eventType, repo, and total nodes\n links.push({\n source: author,\n target: eventTypes[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: repoNames[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: totalNode.name,\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Authors',\n },\n {\n name: 'Event Type',\n },\n {\n name: 'Repo Names',\n },\n {\n name: 'Total', // Add a category for \"Total\" nodes\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Authors', 'Event Types', 'Repo Names', 'Total'], // Add \"Total\" to legend data\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: { // Add textStyle property to configure text style\n color: '#000', // Set the text color to a brighter color, such as white (#FFF)\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n\n // Increase the size of arrow marks\n edgeSymbolSize: [12, 12], // Set the arrow size here\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Display a custom message when data is not available\n const option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n\n return option;\n}", + "getOption": "// Check if data.series exists\nif (context.panel.data.series && context.panel.data.series.length > 0) {\n const eventTypes = context.panel.data.series[0].fields[0].values;\n const authors = context.panel.data.series[0].fields[1].values;\n const repoNames = context.panel.data.series[0].fields[2].values;\n const total = context.panel.data.series[0].fields[3].values; // Assuming you have a field named \"Total\"\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n authors.forEach((author, index) => {\n const sourceNode = {\n name: author,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const eventTypeNode = {\n name: eventTypes[index],\n category: 1, // Category for eventType nodes\n symbolSize: 40, // Size for eventType nodes\n };\n\n const repoNode = {\n name: repoNames[index],\n category: 2, // Category for repo nodes\n symbolSize: 30, // Size for repo nodes\n };\n\n const totalNode = {\n name: `Total: ${total[index]}`, // Assuming you have an array \"total\"\n category: 3, // Category for total nodes\n symbolSize: 20, // Size for total nodes\n };\n\n // Ensure source, eventType, repo, and total nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === eventTypeNode.name)) {\n nodes.push(eventTypeNode);\n }\n\n if (!nodes.some((node) => node.name === repoNode.name)) {\n nodes.push(repoNode);\n }\n\n if (!nodes.some((node) => node.name === totalNode.name)) {\n nodes.push(totalNode);\n }\n\n // Create links between author, eventType, repo, and total nodes\n links.push({\n source: author,\n target: eventTypes[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: repoNames[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: totalNode.name,\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Authors',\n },\n {\n name: 'Event Type',\n },\n {\n name: 'Repo Names',\n },\n {\n name: 'Total', // Add a category for \"Total\" nodes\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Authors', 'Event Types', 'Repo Names', 'Total'], // Add \"Total\" to legend data\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: { // Add textStyle property to configure text style\n color: '#000', // Set the text color to a brighter color, such as white (#FFF)\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n\n // Increase the size of arrow marks\n edgeSymbolSize: [12, 12], // Set the arrow size here\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Display a custom message when data is not available\n const option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n\n return option;\n}", "google": { "callback": "gmapReady", "key": "" @@ -55,8 +56,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -99,11 +106,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let options; // Initialize the options variable\n\nif (!data || !data.series || data.series.length === 0 || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n options = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract Author and Push_Events data from the series\n const categories = data.series[0].fields.find((f) => f.name === 'Author').values;\n const pushEvents = data.series[0].fields.find((f) => f.name === 'Push_Events').values;\n\n // Create the ECharts options\n options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Push_Events'],\n orient: 'vertical', // Change the orientation to vertical\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: pushEvents,\n type: 'line',\n areaStyle: {\n color: 'rgba(0, 128, 255, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'blue', // Set the line color\n },\n name: 'Push_Events',\n },\n ],\n };\n}\n\nreturn options;\n", + "getOption": "let options; // Initialize the options variable\n\nif (!context.panel.data || !context.panel.data.series || context.panel.data.series.length === 0 || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n options = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract Author and Push_Events data from the series\n const categories = context.panel.data.series[0].fields.find((f) => f.name === 'Author').values;\n const pushEvents = context.panel.data.series[0].fields.find((f) => f.name === 'Push_Events').values;\n\n // Create the ECharts options\n options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Push_Events'],\n orient: 'vertical', // Change the orientation to vertical\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: pushEvents,\n type: 'line',\n areaStyle: {\n color: 'rgba(0, 128, 255, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'blue', // Set the line color\n },\n name: 'Push_Events',\n },\n ],\n };\n}\n\nreturn options;\n", "google": { "callback": "gmapReady", "key": "" @@ -114,8 +122,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -158,11 +172,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\n// Define a default options object\nconst defaultOptions = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n};\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = defaultOptions;\n} else {\n // Extract Author and Merge_Events data from the series\n const categories = data.series[0].fields.find((f) => f.name === 'Author').values;\n const mergeEvents = data.series[0].fields.find((f) => f.name === 'Merge_Events').values;\n\n // Create the ECharts options\n const options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Merge_Events'],\n orient: 'vertical',\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: mergeEvents,\n type: 'line',\n name: 'Merge_Events',\n areaStyle: {\n color: 'rgba(255, 0, 0, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'red', // Set the line color\n },\n },\n ],\n };\n\n option = options; // Assign the options to the outer variable\n}\n\nreturn option;\n", + "getOption": "let option; // Initialize the option variable\n\n// Define a default options object\nconst defaultOptions = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n};\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = defaultOptions;\n} else {\n // Extract Author and Merge_Events data from the series\n const categories = context.panel.data.series[0].fields.find((f) => f.name === 'Author').values;\n const mergeEvents = context.panel.data.series[0].fields.find((f) => f.name === 'Merge_Events').values;\n\n // Create the ECharts options\n const options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Merge_Events'],\n orient: 'vertical',\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: mergeEvents,\n type: 'line',\n name: 'Merge_Events',\n areaStyle: {\n color: 'rgba(255, 0, 0, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'red', // Set the line color\n },\n },\n ],\n };\n\n option = options; // Assign the options to the outer variable\n}\n\nreturn option;\n", "google": { "callback": "gmapReady", "key": "" @@ -173,8 +188,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -212,7 +233,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -282,7 +304,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -359,7 +382,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null } ] } @@ -416,9 +440,13 @@ "list": [ { "current": { - "selected": false, - "text": "All", - "value": "$__all" + "selected": true, + "text": [ + "All" + ], + "value": [ + "$__all" + ] }, "datasource": { "type": "vertamedia-clickhouse-datasource", @@ -440,8 +468,8 @@ { "current": { "selected": false, - "text": "", - "value": "" + "text": "All", + "value": "$__all" }, "datasource": { "type": "vertamedia-clickhouse-datasource", @@ -470,6 +498,6 @@ "timezone": "", "title": "GiTea", "uid": "a1c6d705-91b0-4718-99b2-d93b0221bca9", - "version": 1, + "version": 2, "weekStart": "" -} \ No newline at end of file +} diff --git a/grafana/gitHub-dashboard.json b/grafana/gitHub-dashboard.json index 8b3930db..2c3a5786 100644 --- a/grafana/gitHub-dashboard.json +++ b/grafana/gitHub-dashboard.json @@ -15,7 +15,7 @@ "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 37, + "id": 57, "links": [], "liveNow": false, "panels": [ @@ -40,11 +40,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "// Check if data.series exists\nif (data.series && data.series.length > 0) {\n const eventTypes = data.series[0].fields[0].values;\n const authors = data.series[0].fields[1].values;\n const repoNames = data.series[0].fields[2].values;\n const total = data.series[0].fields[3].values; // Assuming you have a field named \"Total\"\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n authors.forEach((author, index) => {\n const sourceNode = {\n name: author,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const eventTypeNode = {\n name: eventTypes[index],\n category: 1, // Category for eventType nodes\n symbolSize: 40, // Size for eventType nodes\n };\n\n const repoNode = {\n name: repoNames[index],\n category: 2, // Category for repo nodes\n symbolSize: 30, // Size for repo nodes\n };\n\n const totalNode = {\n name: `Total: ${total[index]}`, // Assuming you have an array \"total\"\n category: 3, // Category for total nodes\n symbolSize: 20, // Size for total nodes\n };\n\n // Ensure source, eventType, repo, and total nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === eventTypeNode.name)) {\n nodes.push(eventTypeNode);\n }\n\n if (!nodes.some((node) => node.name === repoNode.name)) {\n nodes.push(repoNode);\n }\n\n if (!nodes.some((node) => node.name === totalNode.name)) {\n nodes.push(totalNode);\n }\n\n // Create links between author, eventType, repo, and total nodes\n links.push({\n source: author,\n target: eventTypes[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: repoNames[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: totalNode.name,\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Authors',\n },\n {\n name: 'Event Type',\n },\n {\n name: 'Repo Names',\n },\n {\n name: 'Total', // Add a category for \"Total\" nodes\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Authors', 'Event Types', 'Repo Names', 'Total'], // Add \"Total\" to legend data\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: { // Add textStyle property to configure text style\n color: '#000', // Set the text color to a brighter color, such as white (#FFF)\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n\n // Increase the size of arrow marks\n edgeSymbolSize: [12, 12], // Set the arrow size here\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Handle the case when data.series does not exist\n return {};\n}", + "getOption": "// Check if data.series exists\nif (context.panel.data.series && context.panel.data.series.length > 0) {\n const eventTypes = context.panel.data.series[0].fields[0].values;\n const authors = context.panel.data.series[0].fields[1].values;\n const repoNames = context.panel.data.series[0].fields[2].values;\n const total = context.panel.data.series[0].fields[3].values; // Assuming you have a field named \"Total\"\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n authors.forEach((author, index) => {\n const sourceNode = {\n name: author,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const eventTypeNode = {\n name: eventTypes[index],\n category: 1, // Category for eventType nodes\n symbolSize: 40, // Size for eventType nodes\n };\n\n const repoNode = {\n name: repoNames[index],\n category: 2, // Category for repo nodes\n symbolSize: 30, // Size for repo nodes\n };\n\n const totalNode = {\n name: `Total: ${total[index]}`, // Assuming you have an array \"total\"\n category: 3, // Category for total nodes\n symbolSize: 20, // Size for total nodes\n };\n\n // Ensure source, eventType, repo, and total nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === eventTypeNode.name)) {\n nodes.push(eventTypeNode);\n }\n\n if (!nodes.some((node) => node.name === repoNode.name)) {\n nodes.push(repoNode);\n }\n\n if (!nodes.some((node) => node.name === totalNode.name)) {\n nodes.push(totalNode);\n }\n\n // Create links between author, eventType, repo, and total nodes\n links.push({\n source: author,\n target: eventTypes[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: repoNames[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: totalNode.name,\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Authors',\n },\n {\n name: 'Event Type',\n },\n {\n name: 'Repo Names',\n },\n {\n name: 'Total', // Add a category for \"Total\" nodes\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Authors', 'Event Types', 'Repo Names', 'Total'], // Add \"Total\" to legend data\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: { // Add textStyle property to configure text style\n color: '#000', // Set the text color to a brighter color, such as white (#FFF)\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n\n // Increase the size of arrow marks\n edgeSymbolSize: [12, 12], // Set the arrow size here\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Handle the case when data.series does not exist\n return {};\n}", "google": { "callback": "gmapReady", "key": "" @@ -55,9 +56,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, - "pluginVersion": "10.0.3", + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -100,11 +106,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let options; // Initialize the options variable\n\nif (!data || !data.series || data.series.length === 0 || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n options = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract Author and Push_Events data from the series\n const categories = data.series[0].fields.find((f) => f.name === 'Author').values;\n const pushEvents = data.series[0].fields.find((f) => f.name === 'Push_Events').values;\n\n // Create the ECharts options\n options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Push_Events'],\n orient: 'vertical', // Change the orientation to vertical\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: pushEvents,\n type: 'line',\n areaStyle: {\n color: 'rgba(0, 128, 255, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'blue', // Set the line color\n },\n name: 'Push_Events',\n },\n ],\n };\n}\n\nreturn options;\n", + "getOption": "let options; // Initialize the options variable\n\nif (!context.panel.data || !context.panel.data.series || context.panel.data.series.length === 0 || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n options = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract Author and Push_Events data from the series\n const categories = context.panel.data.series[0].fields.find((f) => f.name === 'Author').values;\n const pushEvents = context.panel.data.series[0].fields.find((f) => f.name === 'Push_Events').values;\n\n // Create the ECharts options\n options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Push_Events'],\n orient: 'vertical', // Change the orientation to vertical\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: pushEvents,\n type: 'line',\n areaStyle: {\n color: 'rgba(0, 128, 255, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'blue', // Set the line color\n },\n name: 'Push_Events',\n },\n ],\n };\n}\n\nreturn options;\n", "google": { "callback": "gmapReady", "key": "" @@ -115,8 +122,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -159,11 +172,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\n// Define a default options object\nconst defaultOptions = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n};\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = defaultOptions;\n} else {\n // Extract Author and Merge_Events data from the series\n const categories = data.series[0].fields.find((f) => f.name === 'Author').values;\n const mergeEvents = data.series[0].fields.find((f) => f.name === 'Merge_Events').values;\n\n // Create the ECharts options\n const options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Merge_Events'],\n orient: 'vertical',\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: mergeEvents,\n type: 'line',\n name: 'Merge_Events',\n areaStyle: {\n color: 'rgba(255, 0, 0, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'red', // Set the line color\n },\n },\n ],\n };\n\n option = options; // Assign the options to the outer variable\n}\n\nreturn option;\n", + "getOption": "let option; // Initialize the option variable\n\n// Define a default options object\nconst defaultOptions = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n};\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = defaultOptions;\n} else {\n // Extract Author and Merge_Events data from the series\n const categories = context.panel.data.series[0].fields.find((f) => f.name === 'Author').values;\n const mergeEvents = context.panel.data.series[0].fields.find((f) => f.name === 'Merge_Events').values;\n\n // Create the ECharts options\n const options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Merge_Events'],\n orient: 'vertical',\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: mergeEvents,\n type: 'line',\n name: 'Merge_Events',\n areaStyle: {\n color: 'rgba(255, 0, 0, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'red', // Set the line color\n },\n },\n ],\n };\n\n option = options; // Assign the options to the outer variable\n}\n\nreturn option;\n", "google": { "callback": "gmapReady", "key": "" @@ -174,8 +188,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -218,11 +238,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "const values = data.series[0].fields[0].values;\n\nreturn {\n series: [\n {\n type: 'liquidFill',\n radius: '90%',\n data: values, // Use the raw values here\n label: {\n formatter: '{a|{c}}',\n rich: {\n a: {\n color: '#000', // You can set the text color here\n },\n },\n },\n tooltip: {\n formatter: '{a}: {c}', // This formatter displays the raw values\n },\n },\n ],\n};\n", + "getOption": "const values = context.panel.data.series[0].fields[0].values;\n\nreturn {\n series: [\n {\n type: 'liquidFill',\n radius: '90%',\n data: values, // Use the raw values here\n label: {\n formatter: '{a|{c}}',\n rich: {\n a: {\n color: '#000', // You can set the text color here\n },\n },\n },\n tooltip: {\n formatter: '{a}: {c}', // This formatter displays the raw values\n },\n },\n ],\n};\n", "google": { "callback": "gmapReady", "key": "" @@ -233,8 +254,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -277,11 +304,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "const values = data.series[0].fields[0].values;\n\nreturn {\n series: [\n {\n type: 'liquidFill',\n radius: '90%',\n data: values, // Use the raw values here\n label: {\n formatter: '{a|{c}}',\n rich: {\n a: {\n color: '#000', // You can set the text color here\n },\n },\n },\n tooltip: {\n formatter: '{a}: {c}', // This formatter displays the raw values\n },\n },\n ],\n};\n", + "getOption": "const values = context.panel.data.series[0].fields[0].values;\n\nreturn {\n series: [\n {\n type: 'liquidFill',\n radius: '90%',\n data: values, // Use the raw values here\n label: {\n formatter: '{a|{c}}',\n rich: {\n a: {\n color: '#000', // You can set the text color here\n },\n },\n },\n tooltip: {\n formatter: '{a}: {c}', // This formatter displays the raw values\n },\n },\n ],\n};\n", "google": { "callback": "gmapReady", "key": "" @@ -292,8 +320,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -338,7 +372,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null } ] } @@ -395,9 +430,13 @@ "list": [ { "current": { - "selected": false, - "text": "", - "value": "" + "selected": true, + "text": [ + "ahinvinith" + ], + "value": [ + "ahinvinith" + ] }, "datasource": { "type": "vertamedia-clickhouse-datasource", @@ -455,4 +494,4 @@ "uid": "ef91218c-94cb-48b1-be1d-0bafe848b75c", "version": 2, "weekStart": "" -} \ No newline at end of file +} diff --git a/grafana/gitLab-dashboard.json b/grafana/gitLab-dashboard.json index 00c49d0b..b6517a4c 100644 --- a/grafana/gitLab-dashboard.json +++ b/grafana/gitLab-dashboard.json @@ -15,7 +15,7 @@ "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 36, + "id": 59, "links": [], "liveNow": false, "panels": [ @@ -40,11 +40,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "// Check if data.series exists\nif (data.series && data.series.length > 0) {\n const eventTypes = data.series[0].fields[0].values;\n const authors = data.series[0].fields[1].values;\n const repoNames = data.series[0].fields[2].values;\n const total = data.series[0].fields[3].values; // Assuming you have a field named \"Total\"\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n authors.forEach((author, index) => {\n const sourceNode = {\n name: author,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const eventTypeNode = {\n name: eventTypes[index],\n category: 1, // Category for eventType nodes\n symbolSize: 40, // Size for eventType nodes\n };\n\n const repoNode = {\n name: repoNames[index],\n category: 2, // Category for repo nodes\n symbolSize: 30, // Size for repo nodes\n };\n\n const totalNode = {\n name: `Total: ${total[index]}`, // Assuming you have an array \"total\"\n category: 3, // Category for total nodes\n symbolSize: 20, // Size for total nodes\n };\n\n // Ensure source, eventType, repo, and total nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === eventTypeNode.name)) {\n nodes.push(eventTypeNode);\n }\n\n if (!nodes.some((node) => node.name === repoNode.name)) {\n nodes.push(repoNode);\n }\n\n if (!nodes.some((node) => node.name === totalNode.name)) {\n nodes.push(totalNode);\n }\n\n // Create links between author, eventType, repo, and total nodes\n links.push({\n source: author,\n target: eventTypes[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: repoNames[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: totalNode.name,\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Authors',\n },\n {\n name: 'Event Type',\n },\n {\n name: 'Repo Names',\n },\n {\n name: 'Total', // Add a category for \"Total\" nodes\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Authors', 'Event Types', 'Repo Names', 'Total'], // Add \"Total\" to legend data\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: { // Add textStyle property to configure text style\n color: '#000', // Set the text color to a brighter color, such as white (#FFF)\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n\n // Increase the size of arrow marks\n edgeSymbolSize: [12, 12], // Set the arrow size here\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Display a custom message when data is not available\n const option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n\n return option;\n}", + "getOption": "// Check if data.series exists\nif (context.panel.data.series && context.panel.data.series.length > 0) {\n const eventTypes = context.panel.data.series[0].fields[0].values;\n const authors = context.panel.data.series[0].fields[1].values;\n const repoNames = context.panel.data.series[0].fields[2].values;\n const total = context.panel.data.series[0].fields[3].values; // Assuming you have a field named \"Total\"\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n authors.forEach((author, index) => {\n const sourceNode = {\n name: author,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const eventTypeNode = {\n name: eventTypes[index],\n category: 1, // Category for eventType nodes\n symbolSize: 40, // Size for eventType nodes\n };\n\n const repoNode = {\n name: repoNames[index],\n category: 2, // Category for repo nodes\n symbolSize: 30, // Size for repo nodes\n };\n\n const totalNode = {\n name: `Total: ${total[index]}`, // Assuming you have an array \"total\"\n category: 3, // Category for total nodes\n symbolSize: 20, // Size for total nodes\n };\n\n // Ensure source, eventType, repo, and total nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === eventTypeNode.name)) {\n nodes.push(eventTypeNode);\n }\n\n if (!nodes.some((node) => node.name === repoNode.name)) {\n nodes.push(repoNode);\n }\n\n if (!nodes.some((node) => node.name === totalNode.name)) {\n nodes.push(totalNode);\n }\n\n // Create links between author, eventType, repo, and total nodes\n links.push({\n source: author,\n target: eventTypes[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: repoNames[index],\n });\n\n links.push({\n source: eventTypes[index],\n target: totalNode.name,\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Authors',\n },\n {\n name: 'Event Type',\n },\n {\n name: 'Repo Names',\n },\n {\n name: 'Total', // Add a category for \"Total\" nodes\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Authors', 'Event Types', 'Repo Names', 'Total'], // Add \"Total\" to legend data\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: { // Add textStyle property to configure text style\n color: '#000', // Set the text color to a brighter color, such as white (#FFF)\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n\n // Increase the size of arrow marks\n edgeSymbolSize: [12, 12], // Set the arrow size here\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Display a custom message when data is not available\n const option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n\n return option;\n}", "google": { "callback": "gmapReady", "key": "" @@ -55,8 +56,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -99,11 +106,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let options; // Initialize the options variable\n\nif (!data || !data.series || data.series.length === 0 || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n options = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract Author and Push_Events data from the series\n const categories = data.series[0].fields.find((f) => f.name === 'Author').values;\n const pushEvents = data.series[0].fields.find((f) => f.name === 'Push_Events').values;\n\n // Create the ECharts options\n options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Push_Events'],\n orient: 'vertical', // Change the orientation to vertical\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: pushEvents,\n type: 'line',\n areaStyle: {\n color: 'rgba(0, 128, 255, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'blue', // Set the line color\n },\n name: 'Push_Events',\n },\n ],\n };\n}\n\nreturn options;\n", + "getOption": "let options; // Initialize the options variable\n\nif (!context.panel.data || !context.panel.data.series || context.panel.data.series.length === 0 || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n options = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract Author and Push_Events data from the series\n const categories = context.panel.data.series[0].fields.find((f) => f.name === 'Author').values;\n const pushEvents = context.panel.data.series[0].fields.find((f) => f.name === 'Push_Events').values;\n\n // Create the ECharts options\n options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Push_Events'],\n orient: 'vertical', // Change the orientation to vertical\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: pushEvents,\n type: 'line',\n areaStyle: {\n color: 'rgba(0, 128, 255, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'blue', // Set the line color\n },\n name: 'Push_Events',\n },\n ],\n };\n}\n\nreturn options;\n", "google": { "callback": "gmapReady", "key": "" @@ -114,8 +122,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -158,11 +172,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\n// Define a default options object\nconst defaultOptions = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n};\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = defaultOptions;\n} else {\n // Extract Author and Merge_Events data from the series\n const categories = data.series[0].fields.find((f) => f.name === 'Author').values;\n const mergeEvents = data.series[0].fields.find((f) => f.name === 'Merge_Events').values;\n\n // Create the ECharts options\n const options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Merge_Events'],\n orient: 'vertical',\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: mergeEvents,\n type: 'line',\n name: 'Merge_Events',\n areaStyle: {\n color: 'rgba(255, 0, 0, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'red', // Set the line color\n },\n },\n ],\n };\n\n option = options; // Assign the options to the outer variable\n}\n\nreturn option;\n", + "getOption": "let option; // Initialize the option variable\n\n// Define a default options object\nconst defaultOptions = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n};\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = defaultOptions;\n} else {\n // Extract Author and Merge_Events data from the series\n const categories = context.panel.data.series[0].fields.find((f) => f.name === 'Author').values;\n const mergeEvents = context.panel.data.series[0].fields.find((f) => f.name === 'Merge_Events').values;\n\n // Create the ECharts options\n const options = {\n grid: {\n bottom: '3%',\n containLabel: true,\n left: '3%',\n right: '4%',\n top: '4%',\n },\n toolbox: {\n right: '5%', // Adjust the right margin to position it on the top right\n top: '0%', // Adjust the top margin to position it on the top right\n feature: {\n dataZoom: {\n yAxisIndex: 'none',\n },\n restore: {},\n },\n },\n tooltip: {\n trigger: 'axis',\n axisPointer: {\n type: 'shadow',\n },\n },\n xAxis: {\n type: 'category',\n data: categories,\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Merge_Events'],\n orient: 'vertical',\n left: '5%',\n top: '5%',\n },\n series: [\n {\n data: mergeEvents,\n type: 'line',\n name: 'Merge_Events',\n areaStyle: {\n color: 'rgba(255, 0, 0, 0.3)', // Set the area (shadow) color\n },\n lineStyle: {\n color: 'red', // Set the line color\n },\n },\n ],\n };\n\n option = options; // Assign the options to the outer variable\n}\n\nreturn option;\n", "google": { "callback": "gmapReady", "key": "" @@ -173,8 +188,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -212,7 +233,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -282,7 +304,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -359,7 +382,8 @@ "mode": "absolute", "steps": [ { - "color": "green" + "color": "green", + "value": null }, { "color": "red", @@ -474,6 +498,6 @@ "timezone": "", "title": "GitLab", "uid": "ec8b9cb1-f9ae-4139-b270-4824b6508eff", - "version": 1, + "version": 2, "weekStart": "" -} \ No newline at end of file +} diff --git a/grafana/kubeData-dashboard.json b/grafana/kubeData-dashboard.json index 5b351bf5..998bc514 100644 --- a/grafana/kubeData-dashboard.json +++ b/grafana/kubeData-dashboard.json @@ -21,7 +21,7 @@ "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 146, + "id": 56, "links": [], "liveNow": false, "panels": [ @@ -46,11 +46,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON as before\n const clusterNames = data.series[0].fields[0].values;\n const namespaces = data.series[0].fields[1].values;\n const reasons = data.series[0].fields[2].values;\n const pods = data.series[0].fields[3].values;\n\n // Create a hierarchical structure from the data without a root node\n const hierarchy = {\n name: 'root', // Use 'root' as a placeholder\n children: [],\n };\n\n const seenClusterNames = new Set();\n const seenNamespaces = new Set();\n\n for (let i = 0; i < clusterNames.length; i++) {\n const clusterName = clusterNames[i];\n const namespace = namespaces[i];\n const reason = reasons[i];\n const pod = pods[i];\n\n if (!seenClusterNames.has(clusterName)) {\n seenClusterNames.add(clusterName);\n const clusterNode = { name: clusterName, children: [] };\n hierarchy.children.push(clusterNode);\n seenNamespaces.clear(); // Reset seenNamespaces for each cluster\n }\n\n const clusterNode = hierarchy.children.find((node) => node.name === clusterName);\n\n if (!seenNamespaces.has(namespace)) {\n seenNamespaces.add(namespace);\n const namespaceNode = { name: namespace, children: [] };\n clusterNode.children.push(namespaceNode);\n }\n\n const namespaceNode = clusterNode.children.find((node) => node.name === namespace);\n const reasonNode = { name: reason, children: [{ name: `Count: ${pod}` }] };\n namespaceNode.children.push(reasonNode);\n }\n\n // Create the tree chart using ECharts\n option = {\n tooltip: {\n trigger: 'item',\n triggerOn: 'mousemove',\n formatter: function (params) {\n const node = params.data;\n let tooltip = '';\n if (node.column) {\n tooltip += `${node.column}: ${node.name}`;\n } else {\n tooltip += node.name;\n }\n return tooltip;\n },\n },\n series: [\n {\n type: 'tree',\n data: hierarchy.children, // Use the children directly\n top: '1%',\n left: '7%',\n bottom: '1%',\n right: '20%',\n symbolSize: 7,\n label: {\n position: 'left',\n verticalAlign: 'middle',\n align: 'centre',\n fontSize: 15, // Increase the text size for regular nodes\n fontWeight: 'bold', // Set the font weight to bold\n },\n leaves: {\n label: {\n position: 'right',\n verticalAlign: 'middle',\n align: 'left',\n fontSize: 15, // Increase the text size for leaves\n fontWeight: 'bold', // Set the font weight to bold\n },\n },\n emphasis: {\n focus: 'descendant',\n },\n expandAndCollapse: true,\n animationDuration: 550,\n animationDurationUpdate: 750,\n },\n ],\n };\n}\n\nreturn option;", + "getOption": "let option; // Initialize the option variable\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON as before\n const clusterNames = context.panel.data.series[0].fields[0].values;\n const namespaces = context.panel.data.series[0].fields[1].values;\n const reasons = context.panel.data.series[0].fields[2].values;\n const pods = context.panel.data.series[0].fields[3].values;\n\n // Create a hierarchical structure from the data without a root node\n const hierarchy = {\n name: 'root', // Use 'root' as a placeholder\n children: [],\n };\n\n const seenClusterNames = new Set();\n const seenNamespaces = new Set();\n\n for (let i = 0; i < clusterNames.length; i++) {\n const clusterName = clusterNames[i];\n const namespace = namespaces[i];\n const reason = reasons[i];\n const pod = pods[i];\n\n if (!seenClusterNames.has(clusterName)) {\n seenClusterNames.add(clusterName);\n const clusterNode = { name: clusterName, children: [] };\n hierarchy.children.push(clusterNode);\n seenNamespaces.clear(); // Reset seenNamespaces for each cluster\n }\n\n const clusterNode = hierarchy.children.find((node) => node.name === clusterName);\n\n if (!seenNamespaces.has(namespace)) {\n seenNamespaces.add(namespace);\n const namespaceNode = { name: namespace, children: [] };\n clusterNode.children.push(namespaceNode);\n }\n\n const namespaceNode = clusterNode.children.find((node) => node.name === namespace);\n const reasonNode = { name: reason, children: [{ name: `Count: ${pod}` }] };\n namespaceNode.children.push(reasonNode);\n }\n\n // Create the tree chart using ECharts\n option = {\n tooltip: {\n trigger: 'item',\n triggerOn: 'mousemove',\n formatter: function (params) {\n const node = params.data;\n let tooltip = '';\n if (node.column) {\n tooltip += `${node.column}: ${node.name}`;\n } else {\n tooltip += node.name;\n }\n return tooltip;\n },\n },\n series: [\n {\n type: 'tree',\n data: hierarchy.children, // Use the children directly\n top: '1%',\n left: '7%',\n bottom: '1%',\n right: '20%',\n symbolSize: 7,\n label: {\n position: 'left',\n verticalAlign: 'middle',\n align: 'centre',\n fontSize: 15, // Increase the text size for regular nodes\n fontWeight: 'bold', // Set the font weight to bold\n },\n leaves: {\n label: {\n position: 'right',\n verticalAlign: 'middle',\n align: 'left',\n fontSize: 15, // Increase the text size for leaves\n fontWeight: 'bold', // Set the font weight to bold\n },\n },\n emphasis: {\n focus: 'descendant',\n },\n expandAndCollapse: true,\n animationDuration: 550,\n animationDurationUpdate: 750,\n },\n ],\n };\n}\n\nreturn option;", "google": { "callback": "gmapReady", "key": "" @@ -61,8 +62,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -105,11 +112,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON as before\n const reasons = data.series[0].fields[0].values;\n const counts = data.series[0].fields[1].values;\n\n // Check if reasons and counts are defined and not empty\n if (!reasons || !counts || reasons.length === 0 || counts.length === 0) {\n // Display a message when no data is available\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n } else {\n // Data is available, proceed with the chart creation\n // Create an array of data items, each containing name and value\n const seriesData = reasons.map((reason, index) => ({\n name: reason,\n value: counts[index],\n }));\n\n // Define a custom color for the bars\n const customColor = 'rgb(0, 123, 255)'; // Change this to your desired color\n\n // Apache ECharts option\n option = {\n xAxis: {\n type: 'category',\n data: reasons, // Use the reasons directly for xAxis data\n axisLabel: {\n interval: 0, // Display all labels on the xAxis\n },\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Pods'], // Legend name\n left: 'left', // Position the legend on the left side\n bottom: 'bottom', // Position the legend at the bottom\n },\n series: [\n {\n name: 'Pods', // Series name for the legend\n data: seriesData,\n type: 'bar',\n label: {\n show: true,\n position: 'top',\n formatter: '{c}',\n },\n itemStyle: {\n barBorderRadius: [5, 5, 0, 0], // Adjust the values to control the curvature\n color: customColor, // Set the custom color for the bars\n },\n },\n ],\n };\n }\n}\n\nreturn option;", + "getOption": "let option; // Initialize the option variable\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON as before\n const reasons = context.panel.data.series[0].fields[0].values;\n const counts = context.panel.data.series[0].fields[1].values;\n\n // Check if reasons and counts are defined and not empty\n if (!reasons || !counts || reasons.length === 0 || counts.length === 0) {\n // Display a message when no data is available\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n } else {\n // Data is available, proceed with the chart creation\n // Create an array of data items, each containing name and value\n const seriesData = reasons.map((reason, index) => ({\n name: reason,\n value: counts[index],\n }));\n\n // Define a custom color for the bars\n const customColor = 'rgb(0, 123, 255)'; // Change this to your desired color\n\n // Apache ECharts option\n option = {\n xAxis: {\n type: 'category',\n data: reasons, // Use the reasons directly for xAxis data\n axisLabel: {\n interval: 0, // Display all labels on the xAxis\n },\n },\n yAxis: {\n type: 'value',\n },\n legend: {\n data: ['Pods'], // Legend name\n left: 'left', // Position the legend on the left side\n bottom: 'bottom', // Position the legend at the bottom\n },\n series: [\n {\n name: 'Pods', // Series name for the legend\n data: seriesData,\n type: 'bar',\n label: {\n show: true,\n position: 'top',\n formatter: '{c}',\n },\n itemStyle: {\n barBorderRadius: [5, 5, 0, 0], // Adjust the values to control the curvature\n color: customColor, // Set the custom color for the bars\n },\n },\n ],\n };\n }\n}\n\nreturn option;", "google": { "callback": "gmapReady", "key": "" @@ -120,8 +128,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -164,11 +178,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n\n // Define the data from your JSON\n const clusterNames = data.series[0].fields[0].values;\n const kinds = data.series[0].fields[1].values;\n const reasons = data.series[0].fields[2].values;\n const counts = data.series[0].fields[3].values;\n\n // Create the Sankey chart configuration\n option = {\n series: {\n type: 'sankey',\n layout: 'none',\n emphasis: {\n focus: 'adjacency',\n },\n data: [],\n links: [],\n },\n tooltip: {\n trigger: 'item',\n formatter: (params) => {\n if (params.dataType === 'node') {\n return params.name;\n }\n if (params.dataType === 'edge') {\n return `Count: ${counts[params.dataIndex]}`; // Display count values\n }\n return '';\n },\n },\n };\n\n // Create nodes for ClusterName, Kind, and Reason\n const uniqueClusterNames = Array.from(new Set(clusterNames));\n const uniqueKinds = Array.from(new Set(kinds));\n const uniqueReasons = Array.from(new Set(reasons));\n\n uniqueClusterNames.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueKinds.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueReasons.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n\n // Create links from Kind to Reason\n kinds.forEach((kind, index) => {\n const sourceIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kind);\n const targetIndex = 1 * uniqueClusterNames.length + uniqueKinds.length + uniqueReasons.indexOf(reasons[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: counts[index], // Use count values\n });\n });\n\n // Create links from ClusterName to Kind\n clusterNames.forEach((clusterName, index) => {\n const sourceIndex = uniqueClusterNames.indexOf(clusterName);\n const targetIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kinds[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: 1,\n });\n });\n}\n\n\nreturn option;\n// Render the chart\nmyChart.setOption(option);", + "getOption": "let option; // Initialize the option variable\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n\n // Define the data from your JSON\n const clusterNames = context.panel.data.series[0].fields[0].values;\n const kinds = context.panel.data.series[0].fields[1].values;\n const reasons = context.panel.data.series[0].fields[2].values;\n const counts = context.panel.data.series[0].fields[3].values;\n\n // Create the Sankey chart configuration\n option = {\n series: {\n type: 'sankey',\n layout: 'none',\n emphasis: {\n focus: 'adjacency',\n },\n data: [],\n links: [],\n },\n tooltip: {\n trigger: 'item',\n formatter: (params) => {\n if (params.dataType === 'node') {\n return params.name;\n }\n if (params.dataType === 'edge') {\n return `Count: ${counts[params.dataIndex]}`; // Display count values\n }\n return '';\n },\n },\n };\n\n // Create nodes for ClusterName, Kind, and Reason\n const uniqueClusterNames = Array.from(new Set(clusterNames));\n const uniqueKinds = Array.from(new Set(kinds));\n const uniqueReasons = Array.from(new Set(reasons));\n\n uniqueClusterNames.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueKinds.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueReasons.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n\n // Create links from Kind to Reason\n kinds.forEach((kind, index) => {\n const sourceIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kind);\n const targetIndex = 1 * uniqueClusterNames.length + uniqueKinds.length + uniqueReasons.indexOf(reasons[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: counts[index], // Use count values\n });\n });\n\n // Create links from ClusterName to Kind\n clusterNames.forEach((clusterName, index) => {\n const sourceIndex = uniqueClusterNames.indexOf(clusterName);\n const targetIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kinds[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: 1,\n });\n });\n}\n\n\nreturn option;\n// Render the chart\nmyChart.setOption(option);", "google": { "callback": "gmapReady", "key": "" @@ -179,8 +194,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -223,11 +244,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n\n // Define the data from your JSON\n const clusterNames = data.series[0].fields[0].values;\n const kinds = data.series[0].fields[1].values;\n const reasons = data.series[0].fields[2].values;\n const counts = data.series[0].fields[3].values;\n\n // Create the Sankey chart configuration\n option = {\n series: {\n type: 'sankey',\n layout: 'none',\n emphasis: {\n focus: 'adjacency',\n },\n data: [],\n links: [],\n },\n tooltip: {\n trigger: 'item',\n formatter: (params) => {\n if (params.dataType === 'node') {\n return params.name;\n }\n if (params.dataType === 'edge') {\n return `Count: ${counts[params.dataIndex]}`; // Display count values\n }\n return '';\n },\n },\n };\n\n // Create nodes for ClusterName, Kind, and Reason\n const uniqueClusterNames = Array.from(new Set(clusterNames));\n const uniqueKinds = Array.from(new Set(kinds));\n const uniqueReasons = Array.from(new Set(reasons));\n\n uniqueClusterNames.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueKinds.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueReasons.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n\n // Create links from Kind to Reason\n kinds.forEach((kind, index) => {\n const sourceIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kind);\n const targetIndex = 1 * uniqueClusterNames.length + uniqueKinds.length + uniqueReasons.indexOf(reasons[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: counts[index], // Use count values\n });\n });\n\n // Create links from ClusterName to Kind\n clusterNames.forEach((clusterName, index) => {\n const sourceIndex = uniqueClusterNames.indexOf(clusterName);\n const targetIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kinds[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: 1,\n });\n });\n}\n\n\n\nreturn option;\n// Render the chart\nmyChart.setOption(option);", + "getOption": "let option; // Initialize the option variable\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n\n // Define the data from your JSON\n const clusterNames = context.panel.data.series[0].fields[0].values;\n const kinds = context.panel.data.series[0].fields[1].values;\n const reasons = context.panel.data.series[0].fields[2].values;\n const counts = context.panel.data.series[0].fields[3].values;\n\n // Create the Sankey chart configuration\n option = {\n series: {\n type: 'sankey',\n layout: 'none',\n emphasis: {\n focus: 'adjacency',\n },\n data: [],\n links: [],\n },\n tooltip: {\n trigger: 'item',\n formatter: (params) => {\n if (params.dataType === 'node') {\n return params.name;\n }\n if (params.dataType === 'edge') {\n return `Count: ${counts[params.dataIndex]}`; // Display count values\n }\n return '';\n },\n },\n };\n\n // Create nodes for ClusterName, Kind, and Reason\n const uniqueClusterNames = Array.from(new Set(clusterNames));\n const uniqueKinds = Array.from(new Set(kinds));\n const uniqueReasons = Array.from(new Set(reasons));\n\n uniqueClusterNames.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueKinds.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueReasons.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n\n // Create links from Kind to Reason\n kinds.forEach((kind, index) => {\n const sourceIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kind);\n const targetIndex = 1 * uniqueClusterNames.length + uniqueKinds.length + uniqueReasons.indexOf(reasons[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: counts[index], // Use count values\n });\n });\n\n // Create links from ClusterName to Kind\n clusterNames.forEach((clusterName, index) => {\n const sourceIndex = uniqueClusterNames.indexOf(clusterName);\n const targetIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kinds[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: 1,\n });\n });\n}\n\n\n\nreturn option;\n// Render the chart\nmyChart.setOption(option);", "google": { "callback": "gmapReady", "key": "" @@ -238,8 +260,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -282,11 +310,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n\n // Define the data from your JSON\n const clusterNames = data.series[0].fields[0].values;\n const kinds = data.series[0].fields[1].values;\n const reasons = data.series[0].fields[2].values;\n const counts = data.series[0].fields[3].values;\n\n // Create the Sankey chart configuration\n option = {\n series: {\n type: 'sankey',\n layout: 'none',\n emphasis: {\n focus: 'adjacency',\n },\n data: [],\n links: [],\n },\n tooltip: {\n trigger: 'item',\n formatter: (params) => {\n if (params.dataType === 'node') {\n return params.name;\n }\n if (params.dataType === 'edge') {\n return `Count: ${counts[params.dataIndex]}`; // Display count values\n }\n return '';\n },\n },\n };\n\n // Create nodes for ClusterName, Kind, and Reason\n const uniqueClusterNames = Array.from(new Set(clusterNames));\n const uniqueKinds = Array.from(new Set(kinds));\n const uniqueReasons = Array.from(new Set(reasons));\n\n uniqueClusterNames.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueKinds.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueReasons.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n\n // Create links from Kind to Reason\n kinds.forEach((kind, index) => {\n const sourceIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kind);\n const targetIndex = 1 * uniqueClusterNames.length + uniqueKinds.length + uniqueReasons.indexOf(reasons[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: counts[index], // Use count values\n });\n });\n\n // Create links from ClusterName to Kind\n clusterNames.forEach((clusterName, index) => {\n const sourceIndex = uniqueClusterNames.indexOf(clusterName);\n const targetIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kinds[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: 1,\n });\n });\n}\n\n\nreturn option;\n// Render the chart\nmyChart.setOption(option);\n\n", + "getOption": "let option; // Initialize the option variable\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n\n // Define the data from your JSON\n const clusterNames = context.panel.data.series[0].fields[0].values;\n const kinds = context.panel.data.series[0].fields[1].values;\n const reasons = context.panel.data.series[0].fields[2].values;\n const counts = context.panel.data.series[0].fields[3].values;\n\n // Create the Sankey chart configuration\n option = {\n series: {\n type: 'sankey',\n layout: 'none',\n emphasis: {\n focus: 'adjacency',\n },\n data: [],\n links: [],\n },\n tooltip: {\n trigger: 'item',\n formatter: (params) => {\n if (params.dataType === 'node') {\n return params.name;\n }\n if (params.dataType === 'edge') {\n return `Count: ${counts[params.dataIndex]}`; // Display count values\n }\n return '';\n },\n },\n };\n\n // Create nodes for ClusterName, Kind, and Reason\n const uniqueClusterNames = Array.from(new Set(clusterNames));\n const uniqueKinds = Array.from(new Set(kinds));\n const uniqueReasons = Array.from(new Set(reasons));\n\n uniqueClusterNames.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueKinds.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n uniqueReasons.forEach((name, index) => {\n option.series.data.push({\n name: name,\n });\n });\n\n\n // Create links from Kind to Reason\n kinds.forEach((kind, index) => {\n const sourceIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kind);\n const targetIndex = 1 * uniqueClusterNames.length + uniqueKinds.length + uniqueReasons.indexOf(reasons[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: counts[index], // Use count values\n });\n });\n\n // Create links from ClusterName to Kind\n clusterNames.forEach((clusterName, index) => {\n const sourceIndex = uniqueClusterNames.indexOf(clusterName);\n const targetIndex = uniqueClusterNames.length + uniqueKinds.indexOf(kinds[index]);\n option.series.links.push({\n source: sourceIndex,\n target: targetIndex,\n value: 1,\n });\n });\n}\n\n\nreturn option;\n// Render the chart\nmyChart.setOption(option);\n\n", "google": { "callback": "gmapReady", "key": "" @@ -297,8 +326,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -341,11 +376,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON\n const clusters = data.series[0].fields[0].values;\n const hosts = data.series[0].fields[1].values;\n const reasons = data.series[0].fields[2].values;\n const eventTimes = data.series[0].fields[3].values;\n\n // Create a hierarchical structure for the tree chart starting with ClusterName\n const hierarchy = {\n name: 'Root', // You can customize the name of the root node if needed\n children: [],\n };\n\n for (let i = 0; i < clusters.length; i++) {\n const cluster = clusters[i];\n const host = hosts[i];\n const reason = reasons[i];\n const eventTime = eventTimes[i];\n\n // Find or create the cluster node\n let clusterNode = hierarchy.children.find((node) => node.name === cluster);\n if (!clusterNode) {\n clusterNode = { name: cluster, children: [] };\n hierarchy.children.push(clusterNode);\n }\n\n // Find or create the host node under the cluster\n let hostNode = clusterNode.children.find((node) => node.name === host);\n if (!hostNode) {\n hostNode = { name: host, children: [] };\n clusterNode.children.push(hostNode);\n }\n\n // Find or create the reason node under the host\n let reasonNode = hostNode.children.find((node) => node.name === reason);\n if (!reasonNode) {\n reasonNode = { name: reason, children: [] };\n hostNode.children.push(reasonNode);\n }\n\n // Create the eventTime node under the reason\n reasonNode.children.push({ name: eventTime });\n }\n\n // Create the tree chart using ECharts\n option = {\n tooltip: {\n trigger: 'item',\n triggerOn: 'mousemove',\n },\n series: [\n {\n type: 'tree',\n data: hierarchy.children, // Use the children directly as root nodes\n top: '1%',\n left: '7%',\n bottom: '1%',\n right: '20%', // Adjust the right margin to provide more space for labels\n symbolSize: 7,\n label: {\n position: 'inside', // Position labels inside the node\n verticalAlign: 'middle',\n align: 'center', // Center-align labels\n fontSize: 15,\n fontWeight: 'bold',\n },\n leaves: {\n label: {\n position: 'right', // Position labels inside the node\n verticalAlign: 'middle',\n align: 'left', // Center-align labels\n fontSize: 15,\n fontWeight: 'bold',\n },\n },\n emphasis: {\n focus: 'descendant',\n },\n expandAndCollapse: true,\n animationDuration: 550,\n animationDurationUpdate: 750,\n },\n ],\n };\n}\n\nreturn option;\n", + "getOption": "let option; // Initialize the option variable\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON\n const clusters = context.panel.data.series[0].fields[0].values;\n const hosts = context.panel.data.series[0].fields[1].values;\n const reasons = context.panel.data.series[0].fields[2].values;\n const eventTimes = context.panel.data.series[0].fields[3].values;\n\n // Create a hierarchical structure for the tree chart starting with ClusterName\n const hierarchy = {\n name: 'Root', // You can customize the name of the root node if needed\n children: [],\n };\n\n for (let i = 0; i < clusters.length; i++) {\n const cluster = clusters[i];\n const host = hosts[i];\n const reason = reasons[i];\n const eventTime = eventTimes[i];\n\n // Find or create the cluster node\n let clusterNode = hierarchy.children.find((node) => node.name === cluster);\n if (!clusterNode) {\n clusterNode = { name: cluster, children: [] };\n hierarchy.children.push(clusterNode);\n }\n\n // Find or create the host node under the cluster\n let hostNode = clusterNode.children.find((node) => node.name === host);\n if (!hostNode) {\n hostNode = { name: host, children: [] };\n clusterNode.children.push(hostNode);\n }\n\n // Find or create the reason node under the host\n let reasonNode = hostNode.children.find((node) => node.name === reason);\n if (!reasonNode) {\n reasonNode = { name: reason, children: [] };\n hostNode.children.push(reasonNode);\n }\n\n // Create the eventTime node under the reason\n reasonNode.children.push({ name: eventTime });\n }\n\n // Create the tree chart using ECharts\n option = {\n tooltip: {\n trigger: 'item',\n triggerOn: 'mousemove',\n },\n series: [\n {\n type: 'tree',\n data: hierarchy.children, // Use the children directly as root nodes\n top: '1%',\n left: '7%',\n bottom: '1%',\n right: '20%', // Adjust the right margin to provide more space for labels\n symbolSize: 7,\n label: {\n position: 'inside', // Position labels inside the node\n verticalAlign: 'middle',\n align: 'center', // Center-align labels\n fontSize: 15,\n fontWeight: 'bold',\n },\n leaves: {\n label: {\n position: 'right', // Position labels inside the node\n verticalAlign: 'middle',\n align: 'left', // Center-align labels\n fontSize: 15,\n fontWeight: 'bold',\n },\n },\n emphasis: {\n focus: 'descendant',\n },\n expandAndCollapse: true,\n animationDuration: 550,\n animationDurationUpdate: 750,\n },\n ],\n };\n}\n\nreturn option;\n", "google": { "callback": "gmapReady", "key": "" @@ -356,8 +392,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -400,11 +442,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON as before\n const clusterNames = data.series[0].fields[0].values; // New column for ClusterName\n const namespaces = data.series[0].fields[1].values;\n const kinds = data.series[0].fields[2].values; // Adjusted index for Kind\n const counts = data.series[0].fields[3].values; // New column for Count\n\n // Create a hierarchical structure from the data without a root node\n const hierarchy = {\n name: 'root', // Use 'root' as a placeholder\n children: [],\n };\n\n const seenClusterNames = new Set();\n const seenNamespaces = new Set();\n\n for (let i = 0; i < clusterNames.length; i++) {\n const clusterName = clusterNames[i];\n const namespace = namespaces[i];\n const kind = kinds[i];\n const count = counts[i]; // Get the count value\n\n if (!seenClusterNames.has(clusterName)) {\n seenClusterNames.add(clusterName);\n const clusterNode = { name: clusterName, children: [] };\n hierarchy.children.push(clusterNode);\n seenNamespaces.clear(); // Reset seenNamespaces for each cluster\n }\n\n const clusterNode = hierarchy.children.find((node) => node.name === clusterName);\n\n if (!seenNamespaces.has(namespace)) {\n seenNamespaces.add(namespace);\n const namespaceNode = { name: namespace, children: [] };\n clusterNode.children.push(namespaceNode);\n }\n\n const namespaceNode = clusterNode.children.find((node) => node.name === namespace);\n const kindNode = { name: kind, children: [{ name: `Count: ${count}` }] }; // Include the count as a child node\n namespaceNode.children.push(kindNode);\n }\n\n // Create the tree chart using ECharts\n option = {\n tooltip: {\n trigger: 'item',\n triggerOn: 'mousemove',\n formatter: function (params) {\n const node = params.data;\n let tooltip = '';\n if (node.column) {\n tooltip += `${node.column}: ${node.name}`;\n } else {\n tooltip += node.name;\n }\n return tooltip;\n },\n },\n series: [\n {\n type: 'tree',\n data: hierarchy.children, // Use the children directly\n top: '1%',\n left: '7%',\n bottom: '1%',\n right: '20%',\n symbolSize: 7,\n label: {\n position: 'left',\n verticalAlign: 'middle',\n align: 'right',\n fontSize: 15, // Increase the text size for regular nodes\n fontWeight: 'bold', // Set the font weight to bold\n },\n leaves: {\n label: {\n position: 'right',\n verticalAlign: 'middle',\n align: 'left',\n fontSize: 15, // Increase the text size for leaves\n fontWeight: 'bold', // Set the font weight to bold\n },\n },\n emphasis: {\n focus: 'descendant',\n },\n expandAndCollapse: true,\n animationDuration: 550,\n animationDurationUpdate: 750,\n },\n ],\n };\n}\n\nreturn option;\n", + "getOption": "let option; // Initialize the option variable\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON as before\n const clusterNames = context.panel.data.series[0].fields[0].values; // New column for ClusterName\n const namespaces = context.panel.data.series[0].fields[1].values;\n const kinds = context.panel.data.series[0].fields[2].values; // Adjusted index for Kind\n const counts = context.panel.data.series[0].fields[3].values; // New column for Count\n\n // Create a hierarchical structure from the data without a root node\n const hierarchy = {\n name: 'root', // Use 'root' as a placeholder\n children: [],\n };\n\n const seenClusterNames = new Set();\n const seenNamespaces = new Set();\n\n for (let i = 0; i < clusterNames.length; i++) {\n const clusterName = clusterNames[i];\n const namespace = namespaces[i];\n const kind = kinds[i];\n const count = counts[i]; // Get the count value\n\n if (!seenClusterNames.has(clusterName)) {\n seenClusterNames.add(clusterName);\n const clusterNode = { name: clusterName, children: [] };\n hierarchy.children.push(clusterNode);\n seenNamespaces.clear(); // Reset seenNamespaces for each cluster\n }\n\n const clusterNode = hierarchy.children.find((node) => node.name === clusterName);\n\n if (!seenNamespaces.has(namespace)) {\n seenNamespaces.add(namespace);\n const namespaceNode = { name: namespace, children: [] };\n clusterNode.children.push(namespaceNode);\n }\n\n const namespaceNode = clusterNode.children.find((node) => node.name === namespace);\n const kindNode = { name: kind, children: [{ name: `Count: ${count}` }] }; // Include the count as a child node\n namespaceNode.children.push(kindNode);\n }\n\n // Create the tree chart using ECharts\n option = {\n tooltip: {\n trigger: 'item',\n triggerOn: 'mousemove',\n formatter: function (params) {\n const node = params.data;\n let tooltip = '';\n if (node.column) {\n tooltip += `${node.column}: ${node.name}`;\n } else {\n tooltip += node.name;\n }\n return tooltip;\n },\n },\n series: [\n {\n type: 'tree',\n data: hierarchy.children, // Use the children directly\n top: '1%',\n left: '7%',\n bottom: '1%',\n right: '20%',\n symbolSize: 7,\n label: {\n position: 'left',\n verticalAlign: 'middle',\n align: 'right',\n fontSize: 15, // Increase the text size for regular nodes\n fontWeight: 'bold', // Set the font weight to bold\n },\n leaves: {\n label: {\n position: 'right',\n verticalAlign: 'middle',\n align: 'left',\n fontSize: 15, // Increase the text size for leaves\n fontWeight: 'bold', // Set the font weight to bold\n },\n },\n emphasis: {\n focus: 'descendant',\n },\n expandAndCollapse: true,\n animationDuration: 550,\n animationDurationUpdate: 750,\n },\n ],\n };\n}\n\nreturn option;\n", "google": { "callback": "gmapReady", "key": "" @@ -415,8 +458,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -455,8 +504,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -695,6 +743,6 @@ "timezone": "", "title": "Kubedata", "uid": "Qq-FK1rVz", - "version": 2, + "version": 3, "weekStart": "" } diff --git a/grafana/kuberhealthy-dashboard.json b/grafana/kuberhealthy-dashboard.json index 915b7747..76e2c6e6 100644 --- a/grafana/kuberhealthy-dashboard.json +++ b/grafana/kuberhealthy-dashboard.json @@ -45,7 +45,7 @@ "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON as before\n const namespaces = data.series[0].fields[0].values;\n const counts = data.series[0].fields[1].values;\n\n // Create a hierarchical structure from the data with a default cluster node\n const hierarchy = {\n name: 'CheckName', // Default cluster node\n children: [],\n };\n\n // Create an object to store namespaces and their counts\n const namespaceCounts = {};\n\n // Populate the namespaceCounts object with namespaces and counts\n for (let i = 0; i < namespaces.length; i++) {\n const namespace = namespaces[i];\n const count = counts[i];\n\n if (!namespaceCounts[namespace]) {\n namespaceCounts[namespace] = count;\n } else {\n namespaceCounts[namespace] += count;\n }\n }\n\n // Create nodes for each namespace and add them as children of the default cluster node\n for (const namespace in namespaceCounts) {\n hierarchy.children.push({\n name: namespace,\n children: [{ name: `${namespaceCounts[namespace]}` }],\n });\n }\n\n // Create the tree chart using ECharts\n option = {\n tooltip: {\n trigger: 'item',\n triggerOn: 'mousemove',\n formatter: function (params) {\n const node = params.data;\n let tooltip = '';\n if (node.column) {\n tooltip += `${node.column}: ${node.name}`;\n } else {\n tooltip += node.name;\n }\n return tooltip;\n },\n },\n series: [\n {\n type: 'tree',\n data: [hierarchy], // Use the hierarchy object as the data\n top: '1%',\n left: '7%',\n bottom: '1%',\n right: '20%',\n symbolSize: 7,\n label: {\n position: 'left',\n verticalAlign: 'middle',\n align: 'centre',\n fontSize: 15, // Increase the text size for regular nodes\n fontWeight: 'bold', // Set the font weight to bold\n },\n leaves: {\n label: {\n position: 'right',\n verticalAlign: 'middle',\n align: 'left',\n fontSize: 15, // Increase the text size for leaves\n fontWeight: 'bold', // Set the font weight to bold\n },\n },\n emphasis: {\n focus: 'descendant',\n },\n expandAndCollapse: true,\n animationDuration: 550,\n animationDurationUpdate: 750,\n },\n ],\n };\n}\n\nreturn option;\n", + "getOption": "let option; // Initialize the option variable\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON as before\n const namespaces = context.panel.data.series[0].fields[0].values;\n const counts = context.panel.data.series[0].fields[1].values;\n\n // Create a hierarchical structure from the data with a default cluster node\n const hierarchy = {\n name: 'CheckName', // Default cluster node\n children: [],\n };\n\n // Create an object to store namespaces and their counts\n const namespaceCounts = {};\n\n // Populate the namespaceCounts object with namespaces and counts\n for (let i = 0; i < namespaces.length; i++) {\n const namespace = namespaces[i];\n const count = counts[i];\n\n if (!namespaceCounts[namespace]) {\n namespaceCounts[namespace] = count;\n } else {\n namespaceCounts[namespace] += count;\n }\n }\n\n // Create nodes for each namespace and add them as children of the default cluster node\n for (const namespace in namespaceCounts) {\n hierarchy.children.push({\n name: namespace,\n children: [{ name: `${namespaceCounts[namespace]}` }],\n });\n }\n\n // Create the tree chart using ECharts\n option = {\n tooltip: {\n trigger: 'item',\n triggerOn: 'mousemove',\n formatter: function (params) {\n const node = params.data;\n let tooltip = '';\n if (node.column) {\n tooltip += `${node.column}: ${node.name}`;\n } else {\n tooltip += node.name;\n }\n return tooltip;\n },\n },\n series: [\n {\n type: 'tree',\n data: [hierarchy], // Use the hierarchy object as the data\n top: '1%',\n left: '7%',\n bottom: '1%',\n right: '20%',\n symbolSize: 7,\n label: {\n position: 'left',\n verticalAlign: 'middle',\n align: 'centre',\n fontSize: 15, // Increase the text size for regular nodes\n fontWeight: 'bold', // Set the font weight to bold\n },\n leaves: {\n label: {\n position: 'right',\n verticalAlign: 'middle',\n align: 'left',\n fontSize: 15, // Increase the text size for leaves\n fontWeight: 'bold', // Set the font weight to bold\n },\n },\n emphasis: {\n focus: 'descendant',\n },\n expandAndCollapse: true,\n animationDuration: 550,\n animationDurationUpdate: 750,\n },\n ],\n };\n}\n\nreturn option;\n", "google": { "callback": "gmapReady", "key": "" @@ -113,7 +113,7 @@ "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let option; // Initialize the option variable\n\nif (typeof data === 'undefined' || !data.series || !data.series[0] || !data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON as before\n const namespaces = data.series[0].fields[0].values;\n const counts = data.series[0].fields[1].values;\n\n // Create a hierarchical structure from the data with a default cluster node\n const hierarchy = {\n name: 'CheckName', // Default cluster node\n children: [],\n };\n\n // Create an object to store namespaces and their counts\n const namespaceCounts = {};\n\n // Populate the namespaceCounts object with namespaces and counts\n for (let i = 0; i < namespaces.length; i++) {\n const namespace = namespaces[i];\n const count = counts[i];\n\n if (!namespaceCounts[namespace]) {\n namespaceCounts[namespace] = count;\n } else {\n namespaceCounts[namespace] += count;\n }\n }\n\n // Create nodes for each namespace and add them as children of the default cluster node\n for (const namespace in namespaceCounts) {\n hierarchy.children.push({\n name: namespace,\n children: [{ name: `${namespaceCounts[namespace]}` }],\n });\n }\n\n // Create the tree chart using ECharts\n option = {\n tooltip: {\n trigger: 'item',\n triggerOn: 'mousemove',\n formatter: function (params) {\n const node = params.data;\n let tooltip = '';\n if (node.column) {\n tooltip += `${node.column}: ${node.name}`;\n } else {\n tooltip += node.name;\n }\n return tooltip;\n },\n },\n series: [\n {\n type: 'tree',\n data: [hierarchy], // Use the hierarchy object as the data\n top: '1%',\n left: '7%',\n bottom: '1%',\n right: '20%',\n symbolSize: 7,\n label: {\n position: 'left',\n verticalAlign: 'middle',\n align: 'centre',\n fontSize: 15, // Increase the text size for regular nodes\n fontWeight: 'bold', // Set the font weight to bold\n },\n leaves: {\n label: {\n position: 'right',\n verticalAlign: 'middle',\n align: 'left',\n fontSize: 15, // Increase the text size for leaves\n fontWeight: 'bold', // Set the font weight to bold\n },\n },\n emphasis: {\n focus: 'descendant',\n },\n expandAndCollapse: true,\n animationDuration: 550,\n animationDurationUpdate: 750,\n },\n ],\n };\n}\n\nreturn option;\n", + "getOption": "let option; // Initialize the option variable\n\nif (typeof context.panel.data === 'undefined' || !context.panel.data.series || !context.panel.data.series[0] || !context.panel.data.series[0].fields) {\n // Data is not available or doesn't have the expected structure\n option = {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n} else {\n // Extract data from your JSON as before\n const namespaces = context.panel.data.series[0].fields[0].values;\n const counts = context.panel.data.series[0].fields[1].values;\n\n // Create a hierarchical structure from the data with a default cluster node\n const hierarchy = {\n name: 'CheckName', // Default cluster node\n children: [],\n };\n\n // Create an object to store namespaces and their counts\n const namespaceCounts = {};\n\n // Populate the namespaceCounts object with namespaces and counts\n for (let i = 0; i < namespaces.length; i++) {\n const namespace = namespaces[i];\n const count = counts[i];\n\n if (!namespaceCounts[namespace]) {\n namespaceCounts[namespace] = count;\n } else {\n namespaceCounts[namespace] += count;\n }\n }\n\n // Create nodes for each namespace and add them as children of the default cluster node\n for (const namespace in namespaceCounts) {\n hierarchy.children.push({\n name: namespace,\n children: [{ name: `${namespaceCounts[namespace]}` }],\n });\n }\n\n // Create the tree chart using ECharts\n option = {\n tooltip: {\n trigger: 'item',\n triggerOn: 'mousemove',\n formatter: function (params) {\n const node = params.data;\n let tooltip = '';\n if (node.column) {\n tooltip += `${node.column}: ${node.name}`;\n } else {\n tooltip += node.name;\n }\n return tooltip;\n },\n },\n series: [\n {\n type: 'tree',\n data: [hierarchy], // Use the hierarchy object as the data\n top: '1%',\n left: '7%',\n bottom: '1%',\n right: '20%',\n symbolSize: 7,\n label: {\n position: 'left',\n verticalAlign: 'middle',\n align: 'centre',\n fontSize: 15, // Increase the text size for regular nodes\n fontWeight: 'bold', // Set the font weight to bold\n },\n leaves: {\n label: {\n position: 'right',\n verticalAlign: 'middle',\n align: 'left',\n fontSize: 15, // Increase the text size for leaves\n fontWeight: 'bold', // Set the font weight to bold\n },\n },\n emphasis: {\n focus: 'descendant',\n },\n expandAndCollapse: true,\n animationDuration: 550,\n animationDurationUpdate: 750,\n },\n ],\n };\n}\n\nreturn option;\n", "google": { "callback": "gmapReady", "key": "" @@ -1199,6 +1199,6 @@ "timezone": "", "title": "KuberHealth", "uid": "d946c53c-8b1d-4e3c-9154-4219165342", - "version": 2, + "version": 3, "weekStart": "" } diff --git a/grafana/kubvizDsahboard.json b/grafana/kubvizDsahboard.json index 374d131b..740b4baa 100644 --- a/grafana/kubvizDsahboard.json +++ b/grafana/kubvizDsahboard.json @@ -21,7 +21,7 @@ "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 32, + "id": 64, "links": [], "liveNow": false, "panels": [ @@ -194,11 +194,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "// Check if data.series exists\nif (data.series && data.series.length > 0) {\n const reasons = data.series[0].fields[0].values;\n const kinds = data.series[0].fields[1].values;\n const eventTimes = data.series[0].fields[2].values;\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n reasons.forEach((reason, index) => {\n const sourceNode = {\n name: reason,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const kindNode = {\n name: kinds[index],\n category: 1, // Category for kind nodes\n symbolSize: 40, // Size for kind nodes\n };\n\n const eventTimeNode = {\n name: eventTimes[index],\n category: 2, // Category for eventTime nodes\n symbolSize: 20, // Size for eventTime nodes\n };\n\n // Ensure source, kind, and eventTime nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === kindNode.name)) {\n nodes.push(kindNode);\n }\n\n if (!nodes.some((node) => node.name === eventTimeNode.name)) {\n nodes.push(eventTimeNode);\n }\n\n // Create links between reason, kind, and eventTime nodes\n links.push({\n source: reason,\n target: kinds[index],\n });\n\n links.push({\n source: kinds[index],\n target: eventTimes[index],\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Reasons',\n },\n {\n name: 'Nodes',\n },\n {\n name: 'Event Times',\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Reasons', 'Nodes', 'Event Times'],\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: {\n color: '#000',\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n edgeSymbolSize: [12, 12],\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Handle the case when data.series does not exist\n return {};\n}", + "getOption": "// Check if context.panel.data.series exists\nif (context.panel.data.series && context.panel.data.series.length > 0) {\n const reasons = context.panel.data.series[0].fields[0].values;\n const kinds = context.panel.data.series[0].fields[1].values;\n const eventTimes = context.panel.data.series[0].fields[2].values;\n\n // Create nodes and links\n const nodes = [];\n const links = [];\n\n reasons.forEach((reason, index) => {\n const sourceNode = {\n name: reason,\n category: 0, // Category for source nodes\n symbolSize: 60, // Size for source nodes\n };\n\n const kindNode = {\n name: kinds[index],\n category: 1, // Category for kind nodes\n symbolSize: 40, // Size for kind nodes\n };\n\n const eventTimeNode = {\n name: eventTimes[index],\n category: 2, // Category for eventTime nodes\n symbolSize: 20, // Size for eventTime nodes\n };\n\n // Ensure source, kind, and eventTime nodes are unique before adding them\n if (!nodes.some((node) => node.name === sourceNode.name)) {\n nodes.push(sourceNode);\n }\n\n if (!nodes.some((node) => node.name === kindNode.name)) {\n nodes.push(kindNode);\n }\n\n if (!nodes.some((node) => node.name === eventTimeNode.name)) {\n nodes.push(eventTimeNode);\n }\n\n // Create links between reason, kind, and eventTime nodes\n links.push({\n source: reason,\n target: kinds[index],\n });\n\n links.push({\n source: kinds[index],\n target: eventTimes[index],\n });\n });\n\n // Create categories for nodes\n const categories = [\n {\n name: 'Reasons',\n },\n {\n name: 'Nodes',\n },\n {\n name: 'Event Times',\n },\n ];\n\n // Create ECharts option\n const option = {\n tooltip: {\n trigger: 'item',\n formatter: '{b}',\n },\n legend: {\n x: 'left',\n data: ['Reasons', 'Nodes', 'Event Times'],\n },\n series: [\n {\n type: 'graph',\n layout: 'circular',\n roam: true,\n label: {\n show: true,\n textStyle: {\n color: '#000',\n },\n },\n force: {\n repulsion: 100,\n gravity: 0.1,\n edgeLength: 150,\n },\n data: nodes,\n links: links,\n draggable: true,\n categories: categories,\n edgeSymbol: [\"none\", \"arrow\"],\n edgeSymbolSize: [12, 12],\n lineStyle: {\n color: \"#000000\",\n curveness: 0,\n opacity: 0.3,\n },\n },\n ],\n };\n\n // Return the ECharts option\n return option;\n} else {\n // Display \"Data not available\" in the panel\n return {\n title: {\n text: 'Data not available',\n textStyle: {\n fontSize: 24,\n fontWeight: 'bold',\n },\n left: 'center',\n top: 'middle',\n },\n };\n}\n", "google": { "callback": "gmapReady", "key": "" @@ -209,8 +210,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -253,11 +260,12 @@ "format": "auto", "height": 600 }, + "editorMode": "code", "gaode": { "key": "", "plugin": "AMap.Scale,AMap.ToolBar" }, - "getOption": "let kind = [];\nlet resources = [];\n\ndata.series.map((s) => {\n kind = s.fields.find((f) => f.name === 'Kind').values;\n resources = s.fields.find((f) => f.name === 'Resources').values;\n});\n\n// Create an empty array to store doughnut chart data\nconst doughnutChartData = [];\n\n// Define colors for doughnut slices\nconst doughnutSliceColors = ['#235894', '#FFFF00', '#FF0000', '#00FF00', '#FFA500'];\n\n// Map severity and counts to doughnut chart data\nkind.forEach((kinddata, index) => {\n doughnutChartData.push({\n value: resources[index],\n name: kinddata,\n itemStyle: {\n borderRadius: [10, 10, 10, 10], // Add rounded corners\n color: doughnutSliceColors[index % doughnutSliceColors.length],\n borderWidth: 2,\n borderColor: '#fff',\n },\n });\n});\n\nreturn {\n backgroundColor: '#FFFFFF', // Set the background color to white\n tooltip: {\n trigger: 'item',\n },\n legend: {\n top: '5%',\n left: 'center',\n },\n series: [\n {\n name: 'Access From',\n type: 'pie',\n radius: ['40%', '70%'],\n avoidLabelOverlap: false,\n label: {\n show: false,\n position: 'center',\n },\n emphasis: {\n label: {\n show: true,\n fontSize: 40,\n fontWeight: 'bold',\n },\n },\n labelLine: {\n show: false,\n },\n data: doughnutChartData, // Use the modified doughnut chart data\n },\n ],\n};", + "getOption": "let kind = [];\nlet resources = [];\n\ncontext.panel.data.series.forEach((s) => {\n const kindField = s.fields.find((f) => f.name === 'Kind');\n const resourcesField = s.fields.find((f) => f.name === 'Resources');\n if (kindField && resourcesField) {\n kind = kindField.values;\n resources = resourcesField.values;\n }\n});\n\n// Create an empty array to store doughnut chart data\nconst doughnutChartData = [];\n\n// Define colors for doughnut slices\nconst doughnutSliceColors = ['#235894', '#FFFF00', '#FF0000', '#00FF00', '#FFA500'];\n\n// Map kind and resources counts to doughnut chart data\nkind.forEach((kinddata, index) => {\n doughnutChartData.push({\n value: resources[index],\n name: kinddata,\n clusterName: context.panel.data.series[0].fields[0].values[index], // Extract cluster name\n itemStyle: {\n borderRadius: [10, 10, 10, 10], // Add rounded corners\n color: doughnutSliceColors[index % doughnutSliceColors.length],\n borderWidth: 2,\n borderColor: '#fff',\n },\n });\n});\n\nreturn {\n backgroundColor: '#FFFFFF', // Set the background color to white\n tooltip: {\n trigger: 'item',\n formatter: function (params) {\n return `Resource From
${params.data.clusterName} ${params.value}`;\n },\n },\n legend: {\n top: '5%',\n left: 'center',\n },\n series: [\n {\n name: '',\n type: 'pie',\n radius: ['40%', '70%'],\n avoidLabelOverlap: false,\n label: {\n show: false,\n position: 'center',\n },\n emphasis: {\n label: {\n show: true,\n fontSize: 40,\n fontWeight: 'bold',\n },\n },\n labelLine: {\n show: false,\n },\n data: doughnutChartData, // Use the modified doughnut chart data\n },\n ],\n};\n", "google": { "callback": "gmapReady", "key": "" @@ -268,8 +276,14 @@ "config": "{}", "height": 400, "name": "default" + }, + "visualEditor": { + "code": "return {\n dataset: context.editor.dataset,\n series: context.editor.series,\n xAxis: {\n type: 'time',\n },\n yAxis: {\n type: 'value',\n min: 'dataMin',\n },\n}\n", + "dataset": [], + "series": [] } }, + "pluginVersion": "6.0.0", "targets": [ { "datasource": { @@ -565,8 +579,7 @@ "mode": "percentage", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -635,8 +648,7 @@ "mode": "percentage", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -705,8 +717,7 @@ "mode": "percentage", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -775,8 +786,7 @@ "mode": "percentage", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -845,8 +855,7 @@ "mode": "percentage", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -948,8 +957,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -1049,8 +1057,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -3101,6 +3108,6 @@ "timezone": "", "title": "Kubviz Dashboard", "uid": "eT4fox94z", - "version": 1, + "version": 4, "weekStart": "" -} \ No newline at end of file +} diff --git a/grafana/trivy-dashboard.json b/grafana/trivy-dashboard.json index db35cd83..52b06fab 100644 --- a/grafana/trivy-dashboard.json +++ b/grafana/trivy-dashboard.json @@ -21,7 +21,7 @@ "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 106, + "id": 58, "links": [], "liveNow": false, "panels": [ @@ -129,12 +129,13 @@ "uid": "vertamedia-clickhouse-datasource" }, "dateTimeType": "DATETIME", + "editorMode": "builder", "extrapolate": true, "format": "table", "formattedQuery": "SELECT $timeSeries as t, count() FROM $table WHERE $timeFilter GROUP BY t ORDER BY t", "intervalFactor": 1, - "query": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_severity = 'LOW'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", - "rawQuery": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_severity = 'LOW'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", + "query": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE $timeFilterByColumn(vul_last_modified_date) AND vul_severity = 'LOW'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", + "rawQuery": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_last_modified_date >= toDateTime(1712241666) AND vul_last_modified_date <= toDateTime(1712328066) AND vul_severity = 'LOW'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", "refId": "A", "round": "0s", "skip_comments": true @@ -236,12 +237,13 @@ "uid": "vertamedia-clickhouse-datasource" }, "dateTimeType": "DATETIME", + "editorMode": "builder", "extrapolate": true, "format": "table", "formattedQuery": "SELECT $timeSeries as t, count() FROM $table WHERE $timeFilter GROUP BY t ORDER BY t", "intervalFactor": 1, - "query": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_severity = 'HIGH'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", - "rawQuery": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_severity = 'HIGH'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", + "query": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE $timeFilterByColumn(vul_last_modified_date) AND vul_severity = 'HIGH'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", + "rawQuery": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_last_modified_date >= toDateTime(1712241678) AND vul_last_modified_date <= toDateTime(1712328078) AND vul_severity = 'HIGH'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", "refId": "A", "round": "0s", "skip_comments": true @@ -343,12 +345,13 @@ "uid": "vertamedia-clickhouse-datasource" }, "dateTimeType": "DATETIME", + "editorMode": "builder", "extrapolate": true, "format": "table", "formattedQuery": "SELECT $timeSeries as t, count() FROM $table WHERE $timeFilter GROUP BY t ORDER BY t", "intervalFactor": 1, - "query": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_severity = 'MEDIUM'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", - "rawQuery": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_severity = 'MEDIUM'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", + "query": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE $timeFilterByColumn(vul_last_modified_date) AND vul_severity = 'MEDIUM'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", + "rawQuery": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_last_modified_date >= toDateTime(1712241603) AND vul_last_modified_date <= toDateTime(1712328003) AND vul_severity = 'MEDIUM'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", "refId": "A", "round": "0s", "skip_comments": true @@ -450,12 +453,13 @@ "uid": "vertamedia-clickhouse-datasource" }, "dateTimeType": "DATETIME", + "editorMode": "builder", "extrapolate": true, "format": "table", "formattedQuery": "SELECT $timeSeries as t, count() FROM $table WHERE $timeFilter GROUP BY t ORDER BY t", "intervalFactor": 1, - "query": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_severity = 'CRITICAL'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", - "rawQuery": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_severity = 'CRITICAL'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", + "query": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE $timeFilterByColumn(vul_last_modified_date) AND vul_severity = 'CRITICAL'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", + "rawQuery": "SELECT cluster_name, artifact_name, vul_pkg_name, count(vul_severity) AS Counts\nFROM default.trivyimage\nWHERE vul_last_modified_date >= toDateTime(1712241618) AND vul_last_modified_date <= toDateTime(1712328018) AND vul_severity = 'CRITICAL'\nGROUP BY cluster_name, artifact_name, vul_pkg_name\nHAVING count(vul_severity) > 1\nORDER BY count(vul_severity) DESC", "refId": "A", "round": "0s", "skip_comments": true @@ -487,8 +491,7 @@ "mode": "absolute", "steps": [ { - "color": "light-blue", - "value": null + "color": "light-blue" } ] } @@ -538,12 +541,13 @@ "uid": "vertamedia-clickhouse-datasource" }, "dateTimeType": "DATETIME", + "editorMode": "builder", "extrapolate": true, "format": "table", "formattedQuery": "SELECT $timeSeries as t, count() FROM $table WHERE $timeFilter GROUP BY t ORDER BY t", "intervalFactor": 1, - "query": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_severity = 'LOW'", - "rawQuery": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_severity = 'LOW'", + "query": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE $timeFilterByColumn(vul_last_modified_date) AND vul_severity = 'LOW'", + "rawQuery": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_last_modified_date >= toDateTime(1712241558) AND vul_last_modified_date <= toDateTime(1712327958) AND vul_severity = 'LOW'", "refId": "A", "round": "0s", "skip_comments": true @@ -575,8 +579,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" } ] } @@ -626,12 +629,13 @@ "uid": "vertamedia-clickhouse-datasource" }, "dateTimeType": "DATETIME", + "editorMode": "builder", "extrapolate": true, "format": "table", "formattedQuery": "SELECT $timeSeries as t, count() FROM $table WHERE $timeFilter GROUP BY t ORDER BY t", "intervalFactor": 1, - "query": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_severity = 'MEDIUM'", - "rawQuery": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_severity = 'MEDIUM'", + "query": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE $timeFilterByColumn(vul_last_modified_date) AND vul_severity = 'MEDIUM'", + "rawQuery": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_last_modified_date >= toDateTime(1712241583) AND vul_last_modified_date <= toDateTime(1712327983) AND vul_severity = 'MEDIUM'", "refId": "A", "round": "0s", "skip_comments": true @@ -663,8 +667,7 @@ "mode": "absolute", "steps": [ { - "color": "super-light-orange", - "value": null + "color": "super-light-orange" } ] } @@ -714,12 +717,13 @@ "uid": "vertamedia-clickhouse-datasource" }, "dateTimeType": "DATETIME", + "editorMode": "builder", "extrapolate": true, "format": "table", "formattedQuery": "SELECT $timeSeries as t, count() FROM $table WHERE $timeFilter GROUP BY t ORDER BY t", "intervalFactor": 1, - "query": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_severity = 'HIGH'", - "rawQuery": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_severity = 'HIGH'", + "query": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE $timeFilterByColumn(vul_last_modified_date) AND vul_severity = 'HIGH'", + "rawQuery": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_last_modified_date >= toDateTime(1712241526) AND vul_last_modified_date <= toDateTime(1712327926) AND vul_severity = 'HIGH'", "refId": "A", "round": "0s", "skip_comments": true @@ -751,8 +755,7 @@ "mode": "absolute", "steps": [ { - "color": "red", - "value": null + "color": "red" } ] } @@ -802,12 +805,13 @@ "uid": "vertamedia-clickhouse-datasource" }, "dateTimeType": "DATETIME", + "editorMode": "builder", "extrapolate": true, "format": "table", "formattedQuery": "SELECT $timeSeries as t, count() FROM $table WHERE $timeFilter GROUP BY t ORDER BY t", "intervalFactor": 1, - "query": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_severity = 'CRITICAL'", - "rawQuery": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_severity = 'CRITICAL'", + "query": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE $timeFilterByColumn(vul_last_modified_date) AND vul_severity = 'CRITICAL'", + "rawQuery": "SELECT cluster_name, artifact_name AS image_name, vul_id, vul_pkg_name, vul_severity\nFROM default.trivyimage\nWHERE vul_last_modified_date >= toDateTime(1712241543) AND vul_last_modified_date <= toDateTime(1712327943) AND vul_severity = 'CRITICAL'", "refId": "A", "round": "0s", "skip_comments": true @@ -839,8 +843,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -912,8 +915,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -967,12 +969,13 @@ "uid": "vertamedia-clickhouse-datasource" }, "dateTimeType": "DATETIME", + "editorMode": "builder", "extrapolate": true, "format": "table", "formattedQuery": "SELECT $timeSeries as t, count() FROM $table WHERE $timeFilter GROUP BY t ORDER BY t", "intervalFactor": 1, - "query": "SELECT vul_id, count(artifact_name) AS images\nFROM default.trivyimage\nGROUP BY vul_id", - "rawQuery": "SELECT vul_id, count(artifact_name) AS images\nFROM default.trivyimage\nGROUP BY vul_id", + "query": "SELECT vul_id, count(artifact_name) AS images\nFROM default.trivyimage\nWHERE $timeFilterByColumn(vul_last_modified_date)\nGROUP BY vul_id", + "rawQuery": "SELECT vul_id, count(artifact_name) AS images\nFROM default.trivyimage\nWHERE vul_last_modified_date >= toDateTime(1712241498) AND vul_last_modified_date <= toDateTime(1712327898)\nGROUP BY vul_id", "refId": "A", "round": "0s", "skip_comments": true @@ -1005,8 +1008,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" } ] } @@ -1078,8 +1080,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" } ] } @@ -2396,6 +2397,6 @@ "timezone": "", "title": "Trivy", "uid": "f9b0a865-f419-410a-b7d9-9a3f79a70d48", - "version": 13, + "version": 2, "weekStart": "" -} \ No newline at end of file +}