You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@devlake.apache.org by ab...@apache.org on 2023/05/17 13:19:23 UTC

[incubator-devlake] branch main updated: feat: improve the UX of DORA dashboards (#5220)

This is an automated email from the ASF dual-hosted git repository.

abeizn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-devlake.git


The following commit(s) were added to refs/heads/main by this push:
     new 3222db16b feat: improve the UX of DORA dashboards (#5220)
3222db16b is described below

commit 3222db16b5a404cf2aabd577786ddd1f6f2a77e9
Author: Louis.z <lo...@gmail.com>
AuthorDate: Wed May 17 21:19:19 2023 +0800

    feat: improve the UX of DORA dashboards (#5220)
    
    * feat: improve the UX of DORA dashboards
    
    * fix: SQL to check pr-deployment mapping
    
    ---------
    
    Co-authored-by: Startrekzky <ka...@merico.dev>
---
 grafana/dashboards/DORA.json      |   49 +-
 grafana/dashboards/DORADebug.json | 1172 ++++++++++++++++++++++---------------
 2 files changed, 743 insertions(+), 478 deletions(-)

diff --git a/grafana/dashboards/DORA.json b/grafana/dashboards/DORA.json
index c705b03f9..7cc119dae 100644
--- a/grafana/dashboards/DORA.json
+++ b/grafana/dashboards/DORA.json
@@ -16,9 +16,32 @@
   "gnetId": null,
   "graphTooltip": 0,
   "id": 21,
-  "iteration": 1683877262059,
+  "iteration": 1684326672244,
   "links": [],
   "panels": [
+    {
+      "datasource": null,
+      "gridPos": {
+        "h": 6,
+        "w": 24,
+        "x": 0,
+        "y": 0
+      },
+      "id": 16,
+      "options": {
+        "content": "- See [how to config](https://devlake.apache.org/docs/DORA) this dashboard\n- Data Sources Required: \n  - `Deployments` from Jenkins, GitLab CI, GitHub Action, webhook, etc. \n  - `Pull Requests` from GitHub PRs, GitLab MRs, BitBucket PRs, Azure DevOps PRs, etc.\n  - `Incidents` from Jira issues, GitHub issues, TAPD issues, PagerDuty Incidents, etc. \n- Transformation Required: Define `deployments` and `incidents` in [data transformations](https://devlake.apache.org/ [...]
+        "mode": "markdown"
+      },
+      "pluginVersion": "8.0.6",
+      "targets": [
+        {
+          "queryType": "randomWalk",
+          "refId": "A"
+        }
+      ],
+      "title": "Dashboard Introduction",
+      "type": "text"
+    },
     {
       "datasource": "mysql",
       "description": "",
@@ -128,7 +151,7 @@
         "h": 6,
         "w": 24,
         "x": 0,
-        "y": 0
+        "y": 6
       },
       "id": 8,
       "options": {
@@ -216,7 +239,7 @@
         "h": 5,
         "w": 6,
         "x": 0,
-        "y": 6
+        "y": 12
       },
       "id": 11,
       "options": {
@@ -315,7 +338,7 @@
         "h": 5,
         "w": 6,
         "x": 6,
-        "y": 6
+        "y": 12
       },
       "id": 12,
       "options": {
@@ -418,7 +441,7 @@
         "h": 5,
         "w": 6,
         "x": 12,
-        "y": 6
+        "y": 12
       },
       "id": 13,
       "options": {
@@ -517,7 +540,7 @@
         "h": 5,
         "w": 6,
         "x": 18,
-        "y": 6
+        "y": 12
       },
       "id": 14,
       "options": {
@@ -611,7 +634,7 @@
         "h": 8,
         "w": 12,
         "x": 0,
-        "y": 11
+        "y": 17
       },
       "id": 2,
       "options": {
@@ -701,7 +724,7 @@
         "h": 8,
         "w": 12,
         "x": 12,
-        "y": 11
+        "y": 17
       },
       "id": 6,
       "options": {
@@ -815,7 +838,7 @@
         "h": 8,
         "w": 12,
         "x": 0,
-        "y": 19
+        "y": 25
       },
       "id": 9,
       "options": {
@@ -927,7 +950,7 @@
         "h": 8,
         "w": 12,
         "x": 12,
-        "y": 19
+        "y": 25
       },
       "id": 5,
       "options": {
@@ -940,7 +963,9 @@
         },
         "orientation": "auto",
         "showValue": "auto",
-        "text": {},
+        "text": {
+          "valueSize": 12
+        },
         "tooltip": {
           "mode": "single"
         }
@@ -1027,5 +1052,5 @@
   "timezone": "",
   "title": "DORA",
   "uid": "qNo8_0M4z",
-  "version": 2
+  "version": 11
 }
\ No newline at end of file
diff --git a/grafana/dashboards/DORADebug.json b/grafana/dashboards/DORADebug.json
index 26e76a981..1d331cdba 100644
--- a/grafana/dashboards/DORADebug.json
+++ b/grafana/dashboards/DORADebug.json
@@ -16,173 +16,31 @@
   "gnetId": null,
   "graphTooltip": 0,
   "id": 11,
-  "iteration": 1683808440856,
+  "iteration": 1684326676771,
   "links": [],
   "panels": [
     {
-      "collapsed": false,
       "datasource": null,
       "gridPos": {
-        "h": 1,
+        "h": 2,
         "w": 24,
         "x": 0,
         "y": 0
       },
-      "id": 22,
-      "panels": [],
-      "title": "Overall DORA Metrics",
-      "type": "row"
-    },
-    {
-      "datasource": "mysql",
-      "description": "",
-      "fieldConfig": {
-        "defaults": {
-          "color": {
-            "fixedColor": "blue",
-            "mode": "thresholds"
-          },
-          "custom": {
-            "align": "auto",
-            "displayMode": "auto",
-            "filterable": false
-          },
-          "mappings": [],
-          "noValue": "-",
-          "thresholds": {
-            "mode": "absolute",
-            "steps": [
-              {
-                "color": "text",
-                "value": null
-              }
-            ]
-          }
-        },
-        "overrides": [
-          {
-            "matcher": {
-              "id": "byName",
-              "options": "low"
-            },
-            "properties": [
-              {
-                "id": "custom.displayMode",
-                "value": "color-text"
-              },
-              {
-                "id": "color",
-                "value": {
-                  "fixedColor": "red",
-                  "mode": "fixed"
-                }
-              }
-            ]
-          },
-          {
-            "matcher": {
-              "id": "byName",
-              "options": "medium"
-            },
-            "properties": [
-              {
-                "id": "custom.displayMode",
-                "value": "color-text"
-              },
-              {
-                "id": "color",
-                "value": {
-                  "fixedColor": "yellow",
-                  "mode": "fixed"
-                }
-              }
-            ]
-          },
-          {
-            "matcher": {
-              "id": "byName",
-              "options": "high"
-            },
-            "properties": [
-              {
-                "id": "custom.displayMode",
-                "value": "color-text"
-              },
-              {
-                "id": "color",
-                "value": {
-                  "fixedColor": "green",
-                  "mode": "fixed"
-                }
-              }
-            ]
-          },
-          {
-            "matcher": {
-              "id": "byName",
-              "options": "elite"
-            },
-            "properties": [
-              {
-                "id": "custom.displayMode",
-                "value": "color-text"
-              },
-              {
-                "id": "color",
-                "value": {
-                  "fixedColor": "purple",
-                  "mode": "fixed"
-                }
-              }
-            ]
-          }
-        ]
-      },
-      "gridPos": {
-        "h": 6,
-        "w": 24,
-        "x": 0,
-        "y": 1
-      },
-      "id": 36,
+      "id": 63,
       "options": {
-        "showHeader": true,
-        "sortBy": []
+        "content": "This dashboard is designed to validate the [DORA dashboard](/grafana/d/qNo8_0M4z/dora?orgId=1).",
+        "mode": "markdown"
       },
       "pluginVersion": "8.0.6",
       "targets": [
         {
-          "format": "table",
-          "group": [],
-          "metricColumn": "none",
           "queryType": "randomWalk",
-          "rawQuery": true,
-          "rawSql": "-- Metric 1: Deployment Frequency\nwith last_few_calendar_months as(\n-- construct the last few calendar months within the selected time period in the top-right corner\n\tSELECT CAST((SYSDATE()-INTERVAL (H+T+U) DAY) AS date) day\n\tFROM ( SELECT 0 H\n\t\t\tUNION ALL SELECT 100 UNION ALL SELECT 200 UNION ALL SELECT 300\n\t\t) H CROSS JOIN ( SELECT 0 T\n\t\t\tUNION ALL SELECT  10 UNION ALL SELECT  20 UNION ALL SELECT  30\n\t\t\tUNION ALL SELECT  40 UNION ALL SELECT  50 [...]
-          "refId": "A",
-          "select": [
-            [
-              {
-                "params": [
-                  "id"
-                ],
-                "type": "column"
-              }
-            ]
-          ],
-          "table": "_devlake_blueprints",
-          "timeColumn": "created_at",
-          "timeColumnType": "timestamp",
-          "where": [
-            {
-              "name": "$__timeFilter",
-              "params": [],
-              "type": "macro"
-            }
-          ]
+          "refId": "A"
         }
       ],
-      "title": "Overall DORA Metrics",
-      "type": "table"
+      "title": "Dashboard Introduction",
+      "type": "text"
     },
     {
       "collapsed": false,
@@ -191,13 +49,35 @@
         "h": 1,
         "w": 24,
         "x": 0,
-        "y": 7
+        "y": 2
       },
       "id": 20,
       "panels": [],
-      "title": "Check Deployment Frequency",
+      "title": "Check \"Deployment Frequency\"",
       "type": "row"
     },
+    {
+      "datasource": null,
+      "gridPos": {
+        "h": 3,
+        "w": 24,
+        "x": 0,
+        "y": 3
+      },
+      "id": 64,
+      "options": {
+        "content": "- See the definition and calculation logic of [Deployment Frequency](https://devlake.apache.org/docs/Metrics/DeploymentFrequency)\n- Data Sources Required: \n  - `Deployments` from Jenkins, GitLab CI, GitHub Action, BitBucket Pipelines, or Webhook, etc. \n- Transformation Required: Define `deployments` in [data transformations](https://devlake.apache.org/docs/Configuration/Tutorial#step-3---add-transformations-optional) while configuring the blueprint of a project.",
+        "mode": "markdown"
+      },
+      "pluginVersion": "8.0.6",
+      "targets": [
+        {
+          "queryType": "randomWalk",
+          "refId": "A"
+        }
+      ],
+      "type": "text"
+    },
     {
       "datasource": "mysql",
       "description": "",
@@ -250,7 +130,7 @@
         "h": 5,
         "w": 16,
         "x": 0,
-        "y": 8
+        "y": 6
       },
       "id": 16,
       "options": {
@@ -338,7 +218,7 @@
         "h": 9,
         "w": 8,
         "x": 16,
-        "y": 8
+        "y": 6
       },
       "id": 15,
       "options": {
@@ -443,7 +323,7 @@
         "h": 5,
         "w": 16,
         "x": 0,
-        "y": 13
+        "y": 11
       },
       "id": 29,
       "options": {
@@ -526,7 +406,7 @@
         "h": 11,
         "w": 8,
         "x": 16,
-        "y": 17
+        "y": 15
       },
       "id": 34,
       "options": {
@@ -551,7 +431,7 @@
           "metricColumn": "none",
           "queryType": "randomWalk",
           "rawQuery": true,
-          "rawSql": "-- Metric 1: Number of deployments per month\nwith _deployments as(\n-- When deploying multiple commits in one pipeline, GitLab and BitBucket may generate more than one deployment. However, DevLake consider these deployments as ONE production deployment and use the last one's finished_date as the finished date.\n\tSELECT \n\t\tdate_format(deployment_finished_date,'%y/%m') as month,\n\t\tcount(cicd_deployment_id) as deployment_count\n\tFROM (\n\t\tSELECT\n\t\t\tcdc.ci [...]
+          "rawSql": "-- Metric 1: Number of deployments per month\nwith _deployments as(\n-- When deploying multiple commits in one pipeline, GitLab and BitBucket may generate more than one deployment. However, DevLake consider these deployments as ONE production deployment and use the last one's finished_date as the finished date.\n\tSELECT \n\t\tdate_format(deployment_finished_date,'%y/%m') as month,\n\t\tcount(cicd_deployment_id) as deployment_count\n\tFROM (\n\t\tSELECT\n\t\t\tcdc.ci [...]
           "refId": "A",
           "select": [
             [
@@ -639,7 +519,7 @@
         "h": 5,
         "w": 16,
         "x": 0,
-        "y": 18
+        "y": 16
       },
       "id": 49,
       "options": {
@@ -744,7 +624,7 @@
         "h": 5,
         "w": 8,
         "x": 0,
-        "y": 23
+        "y": 21
       },
       "id": 11,
       "options": {
@@ -849,7 +729,7 @@
         "h": 5,
         "w": 8,
         "x": 8,
-        "y": 23
+        "y": 21
       },
       "id": 50,
       "options": {
@@ -898,108 +778,68 @@
         "h": 1,
         "w": 24,
         "x": 0,
-        "y": 28
+        "y": 26
       },
       "id": 28,
       "panels": [],
       "title": "Check \"Median Lead Time for Changes\"",
       "type": "row"
     },
+    {
+      "datasource": null,
+      "gridPos": {
+        "h": 4,
+        "w": 24,
+        "x": 0,
+        "y": 27
+      },
+      "id": 65,
+      "options": {
+        "content": "- See the definition and calculation logic of [Median Lead Time for Changes](https://devlake.apache.org/docs/Metrics/LeadTimeForChanges)\n- Data Sources Required: \n  - `Deployments` from Jenkins, GitLab CI, GitHub Action, BitBucket Pipelines, or Webhook, etc. \n  - `Pull Requests` from GitHub PRs, GitLab MRs, BitBucket PRs, Azure DevOps PRs, etc.\n- Transformation Required: Define `deployments` in [data transformations](https://devlake.apache.org/docs/Configuration/T [...]
+        "mode": "markdown"
+      },
+      "pluginVersion": "8.0.6",
+      "targets": [
+        {
+          "queryType": "randomWalk",
+          "refId": "A"
+        }
+      ],
+      "type": "text"
+    },
     {
       "datasource": "mysql",
+      "description": "",
       "fieldConfig": {
         "defaults": {
           "color": {
-            "fixedColor": "rgba(255, 255, 255, 1)",
+            "fixedColor": "rgba(255, 254, 254, 1)",
             "mode": "fixed"
           },
           "custom": {
             "align": "auto",
-            "displayMode": "color-background-solid",
-            "filterable": false
+            "displayMode": "color-background"
           },
-          "mappings": [
-            {
-              "options": {
-                "This Project": {
-                  "color": "green",
-                  "index": 0
-                }
-              },
-              "type": "value"
-            }
-          ],
+          "mappings": [],
           "thresholds": {
             "mode": "absolute",
             "steps": [
               {
-                "color": "red",
+                "color": "green",
                 "value": null
               }
             ]
           }
         },
-        "overrides": [
-          {
-            "matcher": {
-              "id": "byName",
-              "options": "merged_date"
-            },
-            "properties": [
-              {
-                "id": "color"
-              },
-              {
-                "id": "custom.displayMode",
-                "value": "color-background-solid"
-              }
-            ]
-          },
-          {
-            "matcher": {
-              "id": "byType",
-              "options": "time"
-            },
-            "properties": [
-              {
-                "id": "thresholds",
-                "value": {
-                  "mode": "absolute",
-                  "steps": [
-                    {
-                      "color": "red",
-                      "value": null
-                    },
-                    {
-                      "color": "green",
-                      "value": 0
-                    }
-                  ]
-                }
-              }
-            ]
-          },
-          {
-            "matcher": {
-              "id": "byName",
-              "options": "project_name"
-            },
-            "properties": [
-              {
-                "id": "custom.displayMode",
-                "value": "color-background-solid"
-              }
-            ]
-          }
-        ]
+        "overrides": []
       },
       "gridPos": {
-        "h": 3,
-        "w": 8,
+        "h": 5,
+        "w": 16,
         "x": 0,
-        "y": 29
+        "y": 31
       },
-      "id": 53,
+      "id": 18,
       "options": {
         "showHeader": true
       },
@@ -1011,7 +851,7 @@
           "metricColumn": "none",
           "queryType": "randomWalk",
           "rawQuery": true,
-          "rawSql": "SELECT\n  IF(pm.project_name in ($project),'This project',pm.project_name) as project_name,\n\t-- pr.status,\n\tpr.title,\n\tpr.author_name,\n\tpr.url,\n\tpr.merged_date,\n\tpr.created_date\nFROM\n\tpull_requests pr \n\tjoin project_mapping pm on pr.base_repo_id = pm.row_id AND pm.`table`='repos'\nWHERE\n  -- pm.project_name in ($project)\n\tpr.id = '$pr_id'\n\tand $__timeFilter(pr.created_date)\n",
+          "rawSql": "SELECT\n\tpm.project_name,pr._raw_data_table,count(*) as total_number_of_PRs\nFROM\n\tpull_requests pr \n-- \tjoin project_pr_metrics prm on prm.id = pr.id\n\tjoin project_mapping pm on pr.base_repo_id = pm.row_id AND pm.`table`='repos'\nWHERE\n  pm.project_name in ($project)\n-- \tand pr.merged_date is not null\n-- \tand prm.pr_cycle_time is not null\n\tand $__timeFilter(pr.created_date)\nGROUP BY 1,2\n",
           "refId": "A",
           "select": [
             [
@@ -1035,21 +875,341 @@
           ]
         }
       ],
-      "title": "Details of the selected pull request (ONLY Adopt the Pull Request URL filter above)",
+      "title": "Step 1-1. Check if the total PR number in the selected project(s) is correct",
       "type": "table"
     },
     {
       "datasource": "mysql",
-      "description": "",
       "fieldConfig": {
         "defaults": {
           "color": {
-            "fixedColor": "rgba(255, 254, 254, 1)",
-            "mode": "fixed"
+            "mode": "thresholds"
+          },
+          "mappings": [
+            {
+              "options": {
+                "Between one week and six months": {
+                  "color": "yellow",
+                  "index": 1
+                },
+                "Less than one hour": {
+                  "color": "purple",
+                  "index": 3
+                },
+                "Less than one week": {
+                  "color": "green",
+                  "index": 2
+                },
+                "More than six months": {
+                  "color": "red",
+                  "index": 0
+                }
+              },
+              "type": "value"
+            }
+          ],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              }
+            ]
+          }
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 6,
+        "w": 8,
+        "x": 16,
+        "y": 31
+      },
+      "id": 40,
+      "options": {
+        "colorMode": "value",
+        "graphMode": "area",
+        "justifyMode": "auto",
+        "orientation": "auto",
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "/^median_change_lead_time$/",
+          "values": false
+        },
+        "text": {},
+        "textMode": "auto"
+      },
+      "pluginVersion": "8.0.6",
+      "targets": [
+        {
+          "format": "table",
+          "group": [],
+          "metricColumn": "none",
+          "queryType": "randomWalk",
+          "rawQuery": true,
+          "rawSql": "-- Metric 2: median lead time for changes\nwith _pr_stats as (\n-- get the cycle time of PRs deployed by the deployments finished in the selected period\n\tSELECT\n\t\tdistinct pr.id,\n\t\tppm.pr_cycle_time\n\tFROM\n\t\tpull_requests pr \n\t\tjoin project_pr_metrics ppm on ppm.id = pr.id\n\t\tjoin project_mapping pm on pr.base_repo_id = pm.row_id and pm.`table` = 'repos'\n\t\tjoin cicd_deployment_commits cdc on ppm.deployment_commit_id = cdc.id\n\tWHERE\n\t  pm.proje [...]
+          "refId": "A",
+          "select": [
+            [
+              {
+                "params": [
+                  "id"
+                ],
+                "type": "column"
+              }
+            ]
+          ],
+          "table": "_devlake_tasks",
+          "timeColumn": "created_at",
+          "timeColumnType": "timestamp",
+          "where": [
+            {
+              "name": "$__timeFilter",
+              "params": [],
+              "type": "macro"
+            }
+          ]
+        }
+      ],
+      "title": "Figure 3 - Median Lead Time for Changes",
+      "type": "stat"
+    },
+    {
+      "datasource": "mysql",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "fixedColor": "rgba(255, 255, 255, 1)",
+            "mode": "fixed"
           },
           "custom": {
             "align": "auto",
-            "displayMode": "color-background"
+            "displayMode": "color-background-solid",
+            "filterable": false
+          },
+          "mappings": [
+            {
+              "options": {
+                "This Project": {
+                  "color": "green",
+                  "index": 0
+                }
+              },
+              "type": "value"
+            }
+          ],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "red",
+                "value": null
+              }
+            ]
+          }
+        },
+        "overrides": [
+          {
+            "matcher": {
+              "id": "byName",
+              "options": "merged_date"
+            },
+            "properties": [
+              {
+                "id": "color"
+              },
+              {
+                "id": "custom.displayMode",
+                "value": "color-background-solid"
+              }
+            ]
+          },
+          {
+            "matcher": {
+              "id": "byType",
+              "options": "time"
+            },
+            "properties": [
+              {
+                "id": "thresholds",
+                "value": {
+                  "mode": "absolute",
+                  "steps": [
+                    {
+                      "color": "red",
+                      "value": null
+                    },
+                    {
+                      "color": "green",
+                      "value": 0
+                    }
+                  ]
+                }
+              }
+            ]
+          },
+          {
+            "matcher": {
+              "id": "byName",
+              "options": "project_name"
+            },
+            "properties": [
+              {
+                "id": "custom.displayMode",
+                "value": "color-background-solid"
+              }
+            ]
+          }
+        ]
+      },
+      "gridPos": {
+        "h": 3,
+        "w": 16,
+        "x": 0,
+        "y": 36
+      },
+      "id": 53,
+      "options": {
+        "showHeader": true
+      },
+      "pluginVersion": "8.0.6",
+      "targets": [
+        {
+          "format": "table",
+          "group": [],
+          "metricColumn": "none",
+          "queryType": "randomWalk",
+          "rawQuery": true,
+          "rawSql": "SELECT\n  pm.project_name,\n\t-- pr.status,\n\tpr.title,\n\tpr.author_name,\n\tpr.url,\n\tpr.merged_date,\n\tpr.created_date\nFROM\n\tpull_requests pr \n\tjoin project_mapping pm on pr.base_repo_id = pm.row_id AND pm.`table`='repos'\nWHERE\n  -- pm.project_name in ($project)\n\tpr.id = '$pr_id'\n\tand $__timeFilter(pr.created_date)\n",
+          "refId": "A",
+          "select": [
+            [
+              {
+                "params": [
+                  "id"
+                ],
+                "type": "column"
+              }
+            ]
+          ],
+          "table": "_devlake_tasks",
+          "timeColumn": "created_at",
+          "timeColumnType": "timestamp",
+          "where": [
+            {
+              "name": "$__timeFilter",
+              "params": [],
+              "type": "macro"
+            }
+          ]
+        }
+      ],
+      "title": "Step 1-2. Check if the attributes of the selected pull request is correct (Use the Pull Request URL filter above)",
+      "type": "table"
+    },
+    {
+      "datasource": "mysql",
+      "description": "",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "mode": "palette-classic"
+          },
+          "custom": {
+            "axisLabel": "Hours",
+            "axisPlacement": "auto",
+            "axisSoftMin": 0,
+            "fillOpacity": 80,
+            "gradientMode": "none",
+            "hideFrom": {
+              "legend": false,
+              "tooltip": false,
+              "viz": false
+            },
+            "lineWidth": 1
+          },
+          "mappings": [],
+          "thresholds": {
+            "mode": "absolute",
+            "steps": [
+              {
+                "color": "green",
+                "value": null
+              }
+            ]
+          }
+        },
+        "overrides": []
+      },
+      "gridPos": {
+        "h": 7,
+        "w": 8,
+        "x": 16,
+        "y": 37
+      },
+      "id": 38,
+      "options": {
+        "barWidth": 0.7,
+        "groupWidth": 0.7,
+        "legend": {
+          "calcs": [],
+          "displayMode": "list",
+          "placement": "bottom"
+        },
+        "orientation": "auto",
+        "showValue": "auto",
+        "text": {},
+        "tooltip": {
+          "mode": "single"
+        }
+      },
+      "pluginVersion": "8.0.6",
+      "targets": [
+        {
+          "format": "table",
+          "group": [],
+          "hide": false,
+          "metricColumn": "none",
+          "rawQuery": true,
+          "rawSql": "-- Metric 2: median change lead time per month\nwith _pr_stats as (\n-- get the cycle time of PRs deployed by the deployments finished each month\n\tSELECT\n\t\tdistinct pr.id,\n\t\tdate_format(cdc.finished_date,'%y/%m') as month,\n\t\tppm.pr_cycle_time\n\tFROM\n\t\tpull_requests pr\n\t\tjoin project_pr_metrics ppm on ppm.id = pr.id\n\t\tjoin project_mapping pm on pr.base_repo_id = pm.row_id and pm.`table` = 'repos'\n\t\tjoin cicd_deployment_commits cdc on ppm.deploy [...]
+          "refId": "A",
+          "select": [
+            [
+              {
+                "params": [
+                  "id"
+                ],
+                "type": "column"
+              }
+            ]
+          ],
+          "table": "ae_projects",
+          "timeColumn": "ae_create_time",
+          "timeColumnType": "timestamp",
+          "where": [
+            {
+              "name": "$__timeFilter",
+              "params": [],
+              "type": "macro"
+            }
+          ]
+        }
+      ],
+      "timeFrom": null,
+      "timeShift": null,
+      "title": "Figure 4 - Median Lead Time for Changes",
+      "type": "barchart"
+    },
+    {
+      "datasource": "mysql",
+      "fieldConfig": {
+        "defaults": {
+          "color": {
+            "fixedColor": "rgba(255, 254, 254, 1)",
+            "mode": "fixed"
           },
           "mappings": [
             {
@@ -1077,14 +1237,23 @@
         "overrides": []
       },
       "gridPos": {
-        "h": 3,
-        "w": 8,
-        "x": 8,
-        "y": 29
+        "h": 4,
+        "w": 16,
+        "x": 0,
+        "y": 39
       },
-      "id": 18,
+      "id": 12,
       "options": {
-        "showHeader": true
+        "reduceOptions": {
+          "calcs": [
+            "lastNotNull"
+          ],
+          "fields": "",
+          "values": false
+        },
+        "showThresholdLabels": false,
+        "showThresholdMarkers": true,
+        "text": {}
       },
       "pluginVersion": "8.0.6",
       "targets": [
@@ -1094,7 +1263,7 @@
           "metricColumn": "none",
           "queryType": "randomWalk",
           "rawQuery": true,
-          "rawSql": "SELECT\n\tpr._raw_data_table,count(1) as total_number_of_PRs\nFROM\n\tpull_requests pr \n-- \tjoin project_pr_metrics prm on prm.id = pr.id\n\tjoin project_mapping pm on pr.base_repo_id = pm.row_id AND pm.`table`='repos'\nWHERE\n  pm.project_name in ($project)\n-- \tand pr.merged_date is not null\n-- \tand prm.pr_cycle_time is not null\n\tand $__timeFilter(pr.created_date)\nGROUP BY pr._raw_data_table\n",
+          "rawSql": "select \n    count(distinct pr.id) as 'No. of merged PRs in table.pull_requests'\nfrom \n    pull_requests pr\n    join project_mapping pm on pr.base_repo_id = pm.row_id and pm.`table` = 'repos'\nwhere \n    pm.project_name in ($project)\n    and pr.merged_date is not null\n",
           "refId": "A",
           "select": [
             [
@@ -1116,36 +1285,71 @@
               "type": "macro"
             }
           ]
+        },
+        {
+          "format": "table",
+          "group": [],
+          "hide": false,
+          "metricColumn": "none",
+          "rawQuery": true,
+          "rawSql": "select \n    count(distinct id) as 'No. of PRs in table.project_pr_metrics'\nfrom \n    project_pr_metrics \nwhere \n    project_name in ($project)",
+          "refId": "B",
+          "select": [
+            [
+              {
+                "params": [
+                  "blueprint_id"
+                ],
+                "type": "column"
+              }
+            ]
+          ],
+          "table": "_devlake_blueprint_labels",
+          "timeColumn": "created_at",
+          "timeColumnType": "timestamp",
+          "where": [
+            {
+              "name": "$__timeFilter",
+              "params": [],
+              "type": "macro"
+            }
+          ]
         }
       ],
-      "title": "Step 1. Check if the total PR number in this project is correct",
-      "type": "table"
+      "title": "Step 1-3. Check if the No. of records in proejct_pr_metrics is the same as the No. of MERGED PRs in pull_requests",
+      "type": "gauge"
     },
     {
       "datasource": "mysql",
+      "description": "",
       "fieldConfig": {
         "defaults": {
           "color": {
-            "mode": "thresholds"
+            "fixedColor": "rgba(255, 255, 255, 1)",
+            "mode": "fixed"
+          },
+          "custom": {
+            "align": "left",
+            "displayMode": "color-background-solid"
           },
           "mappings": [
             {
               "options": {
-                "Between one week and six months": {
-                  "color": "yellow",
+                "DEPLOYMENT": {
+                  "color": "green",
                   "index": 1
                 },
-                "Less than one hour": {
-                  "color": "purple",
-                  "index": 3
+                "PRODUCTION": {
+                  "color": "green",
+                  "index": 0
                 },
-                "Less than one week": {
+                "SUCCESS": {
                   "color": "green",
                   "index": 2
                 },
-                "More than six months": {
-                  "color": "red",
-                  "index": 0
+                "This project is selected": {
+                  "color": "green",
+                  "index": 3
                 }
               },
               "type": "value"
@@ -1164,26 +1368,15 @@
         "overrides": []
       },
       "gridPos": {
-        "h": 13,
-        "w": 8,
-        "x": 16,
-        "y": 29
+        "h": 4,
+        "w": 16,
+        "x": 0,
+        "y": 43
       },
-      "id": 40,
+      "id": 68,
       "options": {
-        "colorMode": "value",
-        "graphMode": "area",
-        "justifyMode": "auto",
-        "orientation": "auto",
-        "reduceOptions": {
-          "calcs": [
-            "lastNotNull"
-          ],
-          "fields": "/^median_change_lead_time$/",
-          "values": false
-        },
-        "text": {},
-        "textMode": "auto"
+        "showHeader": true,
+        "sortBy": []
       },
       "pluginVersion": "8.0.6",
       "targets": [
@@ -1193,7 +1386,7 @@
           "metricColumn": "none",
           "queryType": "randomWalk",
           "rawQuery": true,
-          "rawSql": "-- Metric 2: median lead time for changes\nwith _pr_stats as (\n-- get the cycle time of PRs deployed by the deployments finished in the selected period\n\tSELECT\n\t\tdistinct pr.id,\n\t\tppm.pr_cycle_time\n\tFROM\n\t\tpull_requests pr \n\t\tjoin project_pr_metrics ppm on ppm.id = pr.id\n\t\tjoin project_mapping pm on pr.base_repo_id = pm.row_id and pm.`table` = 'repos'\n\t\tjoin cicd_deployment_commits cdc on ppm.deployment_commit_id = cdc.id\n\tWHERE\n\t  pm.proje [...]
+          "rawSql": "SELECT\n\tpm.project_name,\n\tIF(pm.project_name in ($project),'This project is selected','Not Selected') as select_status,\n\tIF(cdc._raw_data_table != '', cdc._raw_data_table, cdc.cicd_scope_id) as _raw_data_table,\n\tresult,\n\tenvironment,\n\tcount(distinct cdc.id) as deployment_commit_count, \n\tcount(distinct cdc.cicd_deployment_id) as deployment_count\nFROM cicd_deployment_commits cdc\njoin project_mapping pm on cdc.cicd_scope_id = pm.row_id and pm.`table` = ' [...]
           "refId": "A",
           "select": [
             [
@@ -1217,8 +1410,8 @@
           ]
         }
       ],
-      "title": "Figure 3 - Median Lead Time for Changes",
-      "type": "stat"
+      "title": "Step 2. Check if the number of successful  production deployments in the selected project(s) is correct",
+      "type": "table"
     },
     {
       "datasource": "mysql",
@@ -1315,10 +1508,10 @@
         ]
       },
       "gridPos": {
-        "h": 20,
+        "h": 7,
         "w": 8,
-        "x": 0,
-        "y": 32
+        "x": 16,
+        "y": 44
       },
       "id": 51,
       "options": {
@@ -1356,28 +1549,35 @@
           ]
         }
       ],
-      "title": "All PRs in this project (Only the rows with 2 green columns should appear in project_pr_metrics)",
+      "title": "Appendix 1 - All PRs in this project (Only the rows with 2 green columns should appear in project_pr_metrics)",
       "type": "table"
     },
     {
       "datasource": "mysql",
+      "description": "",
       "fieldConfig": {
         "defaults": {
           "color": {
-            "fixedColor": "rgba(255, 254, 254, 1)",
+            "fixedColor": "rgba(255, 255, 255, 1)",
             "mode": "fixed"
           },
+          "custom": {
+            "align": "left",
+            "displayMode": "color-background-solid"
+          },
           "mappings": [
             {
               "options": {
-                "from": 1,
-                "result": {
+                "NO": {
+                  "color": "red",
+                  "index": 1
+                },
+                "YES": {
                   "color": "green",
                   "index": 0
-                },
-                "to": 10000000
+                }
               },
-              "type": "range"
+              "type": "value"
             }
           ],
           "thresholds": {
@@ -1393,23 +1593,15 @@
         "overrides": []
       },
       "gridPos": {
-        "h": 5,
-        "w": 8,
-        "x": 8,
-        "y": 32
+        "h": 4,
+        "w": 16,
+        "x": 0,
+        "y": 47
       },
-      "id": 12,
+      "id": 69,
       "options": {
-        "reduceOptions": {
-          "calcs": [
-            "lastNotNull"
-          ],
-          "fields": "",
-          "values": false
-        },
-        "showThresholdLabels": false,
-        "showThresholdMarkers": true,
-        "text": {}
+        "showHeader": true,
+        "sortBy": []
       },
       "pluginVersion": "8.0.6",
       "targets": [
@@ -1419,7 +1611,7 @@
           "metricColumn": "none",
           "queryType": "randomWalk",
           "rawQuery": true,
-          "rawSql": "select \n    count(distinct pr.id) as 'No. of merged PRs in table.pull_requests'\nfrom \n    pull_requests pr\n    join project_mapping pm on pr.base_repo_id = pm.row_id and pm.`table` = 'repos'\nwhere \n    pm.project_name in ($project)\n    and pr.merged_date is not null\n",
+          "rawSql": "-- This query can be used to test if the column `deployment_commit_id` is associated with the correct PR\nWITH pr_merge_commits AS (\n\tSELECT\n\t\tppm.id AS pr_id,\n\t\tppm.deployment_commit_id AS id_1,\n\t\tpr.merge_commit_sha,\n\t\tppm.project_name \n\tFROM\n\t\tproject_pr_metrics ppm\n\t\tLEFT JOIN pull_requests pr ON ppm.id = pr.id \n\tWHERE\n\t\tppm.project_name in ($project) \n\t\tAND ppm.id = '$pr_id'\n\t),\n\t_deployment_commits AS (\n\tSELECT DISTINCT\n\t\t [...]
           "refId": "A",
           "select": [
             [
@@ -1441,39 +1633,10 @@
               "type": "macro"
             }
           ]
-        },
-        {
-          "format": "table",
-          "group": [],
-          "hide": false,
-          "metricColumn": "none",
-          "rawQuery": true,
-          "rawSql": "select \n    count(distinct id) as 'No. of PRs in table.project_pr_metrics'\nfrom \n    project_pr_metrics \nwhere \n    project_name in ($project)",
-          "refId": "B",
-          "select": [
-            [
-              {
-                "params": [
-                  "blueprint_id"
-                ],
-                "type": "column"
-              }
-            ]
-          ],
-          "table": "_devlake_blueprint_labels",
-          "timeColumn": "created_at",
-          "timeColumnType": "timestamp",
-          "where": [
-            {
-              "name": "$__timeFilter",
-              "params": [],
-              "type": "macro"
-            }
-          ]
         }
       ],
-      "title": "Step 2. Check if the number of MERGED PRs of this project are the same between table pull_requests and proejct_pr_metrics",
-      "type": "gauge"
+      "title": "Step 3. Check if the mapping logic between `pull requests` and `depoloyment commits` is correct",
+      "type": "table"
     },
     {
       "datasource": "mysql",
@@ -1500,10 +1663,10 @@
         "overrides": []
       },
       "gridPos": {
-        "h": 5,
-        "w": 8,
-        "x": 8,
-        "y": 37
+        "h": 4,
+        "w": 12,
+        "x": 0,
+        "y": 51
       },
       "id": 52,
       "options": {
@@ -1579,7 +1742,7 @@
           ]
         }
       ],
-      "title": "Step 3. Check if PR coding time in table.project_pr_metrics is accurate (Adopt the Pull Request filter above)",
+      "title": "Step 4-1. Check if PR coding time in project_pr_metrics is correct (Adopt the Pull Request filter above)",
       "type": "gauge"
     },
     {
@@ -1603,10 +1766,10 @@
         "overrides": []
       },
       "gridPos": {
-        "h": 5,
-        "w": 8,
-        "x": 8,
-        "y": 42
+        "h": 4,
+        "w": 12,
+        "x": 12,
+        "y": 51
       },
       "id": 54,
       "options": {
@@ -1682,29 +1845,15 @@
           ]
         }
       ],
-      "title": "Step 4. Check if PR pickup time in table.project_pr_metrics is accurate (Adopt the Pull Request filter above)",
+      "title": "Step 4-2. Check if PR pickup time in project_pr_metrics is correct (Adopt the Pull Request filter above)",
       "type": "gauge"
     },
     {
       "datasource": "mysql",
-      "description": "",
       "fieldConfig": {
         "defaults": {
           "color": {
-            "mode": "palette-classic"
-          },
-          "custom": {
-            "axisLabel": "Hours",
-            "axisPlacement": "auto",
-            "axisSoftMin": 0,
-            "fillOpacity": 80,
-            "gradientMode": "none",
-            "hideFrom": {
-              "legend": false,
-              "tooltip": false,
-              "viz": false
-            },
-            "lineWidth": 1
+            "mode": "thresholds"
           },
           "mappings": [],
           "thresholds": {
@@ -1720,36 +1869,33 @@
         "overrides": []
       },
       "gridPos": {
-        "h": 15,
-        "w": 8,
-        "x": 16,
-        "y": 42
+        "h": 4,
+        "w": 12,
+        "x": 0,
+        "y": 55
       },
-      "id": 38,
+      "id": 55,
       "options": {
-        "barWidth": 0.7,
-        "groupWidth": 0.7,
-        "legend": {
-          "calcs": [],
-          "displayMode": "list",
-          "placement": "bottom"
+        "reduceOptions": {
+          "calcs": [
+            "last"
+          ],
+          "fields": "",
+          "values": false
         },
-        "orientation": "auto",
-        "showValue": "auto",
-        "text": {},
-        "tooltip": {
-          "mode": "single"
-        }
+        "showThresholdLabels": false,
+        "showThresholdMarkers": true,
+        "text": {}
       },
       "pluginVersion": "8.0.6",
       "targets": [
         {
           "format": "table",
           "group": [],
-          "hide": false,
           "metricColumn": "none",
+          "queryType": "randomWalk",
           "rawQuery": true,
-          "rawSql": "-- Metric 2: median change lead time per month\nwith _pr_stats as (\n-- get the cycle time of PRs deployed by the deployments finished each month\n\tSELECT\n\t\tdistinct pr.id,\n\t\tdate_format(cdc.finished_date,'%y/%m') as month,\n\t\tppm.pr_cycle_time\n\tFROM\n\t\tpull_requests pr\n\t\tjoin project_pr_metrics ppm on ppm.id = pr.id\n\t\tjoin project_mapping pm on pr.base_repo_id = pm.row_id and pm.`table` = 'repos'\n\t\tjoin cicd_deployment_commits cdc on ppm.deploy [...]
+          "rawSql": "with _pr_comment_ranks as(\n    select \n        pr.id as pr_id,\n        pr.merged_date as pr_merged_date,\n        prc.id as review_id,\n        prc.created_date as review_created_date,\n        row_number() over(partition by pr.id order by prc.created_date asc) as comment_rank_asc\n    from \n        pull_requests pr\n        left join pull_request_comments prc on pr.id = prc.pull_request_id\n    where \n        pr.id = '$pr_id'\n        and prc.account_id!=pr.aut [...]
           "refId": "A",
           "select": [
             [
@@ -1761,8 +1907,37 @@
               }
             ]
           ],
-          "table": "ae_projects",
-          "timeColumn": "ae_create_time",
+          "table": "_devlake_tasks",
+          "timeColumn": "created_at",
+          "timeColumnType": "timestamp",
+          "where": [
+            {
+              "name": "$__timeFilter",
+              "params": [],
+              "type": "macro"
+            }
+          ]
+        },
+        {
+          "format": "table",
+          "group": [],
+          "hide": false,
+          "metricColumn": "none",
+          "rawQuery": true,
+          "rawSql": "select \n    id, \n    -- first_review_id,\n    pr_review_time as 'PR review time from project_pr_metrics'\nfrom project_pr_metrics\nwhere \n    id = '$pr_id'\n    and project_name in ($project)\n",
+          "refId": "B",
+          "select": [
+            [
+              {
+                "params": [
+                  "blueprint_id"
+                ],
+                "type": "column"
+              }
+            ]
+          ],
+          "table": "_devlake_blueprint_labels",
+          "timeColumn": "created_at",
           "timeColumnType": "timestamp",
           "where": [
             {
@@ -1773,10 +1948,8 @@
           ]
         }
       ],
-      "timeFrom": null,
-      "timeShift": null,
-      "title": "Figure 4 - Median Lead Time for Changes",
-      "type": "barchart"
+      "title": "Step 4-3. Check if PR review time in project_pr_metrics is correct (Adopt the Pull Request filter above)",
+      "type": "gauge"
     },
     {
       "datasource": "mysql",
@@ -1799,12 +1972,12 @@
         "overrides": []
       },
       "gridPos": {
-        "h": 5,
-        "w": 8,
-        "x": 8,
-        "y": 47
+        "h": 4,
+        "w": 12,
+        "x": 12,
+        "y": 55
       },
-      "id": 55,
+      "id": 56,
       "options": {
         "reduceOptions": {
           "calcs": [
@@ -1825,7 +1998,7 @@
           "metricColumn": "none",
           "queryType": "randomWalk",
           "rawQuery": true,
-          "rawSql": "with _pr_comment_ranks as(\n    select \n        pr.id as pr_id,\n        pr.merged_date as pr_merged_date,\n        prc.id as review_id,\n        prc.created_date as review_created_date,\n        row_number() over(partition by pr.id order by prc.created_date asc) as comment_rank_asc\n    from \n        pull_requests pr\n        left join pull_request_comments prc on pr.id = prc.pull_request_id\n    where \n        pr.id = '$pr_id'\n        and prc.account_id!=pr.aut [...]
+          "rawSql": "select  \n    ppm.id as pr_id,\n    ppm.deployment_commit_id,\n    CEILING(TIMESTAMPDIFF(second,pr.merged_date,cdc.finished_date)/60) as 'PR deploy time from cicd_deployment_commits'\nfrom \n    project_pr_metrics ppm\n    left join cicd_deployment_commits cdc on ppm.deployment_commit_id = cdc.id\n    left join pull_requests pr on ppm.id = pr.id\nwhere \n   project_name in ($project)\n   and cdc.result = 'SUCCESS'\n   and cdc.`environment` = 'PRODUCTION'\n   and ppm. [...]
           "refId": "A",
           "select": [
             [
@@ -1854,7 +2027,7 @@
           "hide": false,
           "metricColumn": "none",
           "rawQuery": true,
-          "rawSql": "select \n    id, \n    -- first_review_id,\n    pr_review_time as 'PR review time from project_pr_metrics'\nfrom project_pr_metrics\nwhere \n    id = '$pr_id'\n    and project_name in ($project)\n",
+          "rawSql": "select \n    id, \n    pr_deploy_time as 'PR deploy time from project_pr_metrics'\nfrom project_pr_metrics\nwhere \n    id = '$pr_id'\n    and project_name in ($project)\n",
           "refId": "B",
           "select": [
             [
@@ -1878,7 +2051,7 @@
           ]
         }
       ],
-      "title": "Step 5. Check if PR review time in table.project_pr_metrics is accurate (Adopt the Pull Request filter above)",
+      "title": "Step 4-4. Check if PR deploy time in project_pr_metrics is correct (Adopt the Pull Request filter above)",
       "type": "gauge"
     },
     {
@@ -1902,12 +2075,12 @@
         "overrides": []
       },
       "gridPos": {
-        "h": 5,
-        "w": 8,
+        "h": 4,
+        "w": 12,
         "x": 0,
-        "y": 52
+        "y": 59
       },
-      "id": 56,
+      "id": 57,
       "options": {
         "reduceOptions": {
           "calcs": [
@@ -1928,7 +2101,7 @@
           "metricColumn": "none",
           "queryType": "randomWalk",
           "rawQuery": true,
-          "rawSql": "select  \n    ppm.id as pr_id,\n    ppm.deployment_commit_id,\n    CEILING(TIMESTAMPDIFF(second,pr.merged_date,cdc.finished_date)/60) as 'PR deploy time from cicd_deployment_commits'\nfrom \n    project_pr_metrics ppm\n    left join cicd_deployment_commits cdc on ppm.deployment_commit_id = cdc.id\n    left join pull_requests pr on ppm.id = pr.id\nwhere \n   project_name in ($project)\n   and cdc.result = 'SUCCESS'\n   and cdc.`environment` = 'PRODUCTION'\n   and ppm. [...]
+          "rawSql": "select \n     ppm.id,\n    (pr_coding_time + CEILING(TIMESTAMPDIFF(second,pr.created_date,pr.merged_date)/60) + pr_deploy_time) as 'PR cycle time from lower-level metrics',\n    ppm.`pr_cycle_time` as 'PR cycle time from project_pr_metrics'\nfrom project_pr_metrics ppm\nleft join pull_requests pr on ppm.id = pr.id\nwhere \n    project_name in ($project)\n    and pr.id = '$pr_id'",
           "refId": "A",
           "select": [
             [
@@ -1950,47 +2123,23 @@
               "type": "macro"
             }
           ]
-        },
-        {
-          "format": "table",
-          "group": [],
-          "hide": false,
-          "metricColumn": "none",
-          "rawQuery": true,
-          "rawSql": "select \n    id, \n    pr_deploy_time as 'PR deploy time from project_pr_metrics'\nfrom project_pr_metrics\nwhere \n    id = '$pr_id'\n    and project_name in ($project)\n",
-          "refId": "B",
-          "select": [
-            [
-              {
-                "params": [
-                  "blueprint_id"
-                ],
-                "type": "column"
-              }
-            ]
-          ],
-          "table": "_devlake_blueprint_labels",
-          "timeColumn": "created_at",
-          "timeColumnType": "timestamp",
-          "where": [
-            {
-              "name": "$__timeFilter",
-              "params": [],
-              "type": "macro"
-            }
-          ]
         }
       ],
-      "title": "Step 6. Check if PR deploy time in table.project_pr_metrics is accurate (Adopt the Pull Request filter above)",
+      "title": "Step 4-5. Check if PR cycle time in project_pr_metrics is correct (Adopt the Pull Request filter above)",
       "type": "gauge"
     },
     {
       "datasource": "mysql",
+      "description": "",
       "fieldConfig": {
         "defaults": {
           "color": {
             "mode": "thresholds"
           },
+          "custom": {
+            "align": "auto",
+            "displayMode": "auto"
+          },
           "mappings": [],
           "thresholds": {
             "mode": "absolute",
@@ -2002,36 +2151,79 @@
             ]
           }
         },
-        "overrides": []
+        "overrides": [
+          {
+            "matcher": {
+              "id": "byName",
+              "options": "ranks"
+            },
+            "properties": [
+              {
+                "id": "mappings",
+                "value": [
+                  {
+                    "options": {
+                      "from": 0,
+                      "result": {
+                        "color": "green",
+                        "index": 0
+                      },
+                      "to": 0.5
+                    },
+                    "type": "range"
+                  },
+                  {
+                    "options": {
+                      "from": 0.5,
+                      "result": {
+                        "color": "orange",
+                        "index": 1
+                      },
+                      "to": 1
+                    },
+                    "type": "range"
+                  }
+                ]
+              },
+              {
+                "id": "custom.displayMode",
+                "value": "color-text"
+              }
+            ]
+          },
+          {
+            "matcher": {
+              "id": "byName",
+              "options": "month"
+            },
+            "properties": [
+              {
+                "id": "custom.filterable",
+                "value": true
+              }
+            ]
+          }
+        ]
       },
       "gridPos": {
-        "h": 5,
-        "w": 8,
-        "x": 8,
-        "y": 52
+        "h": 8,
+        "w": 24,
+        "x": 0,
+        "y": 63
       },
-      "id": 57,
+      "id": 70,
       "options": {
-        "reduceOptions": {
-          "calcs": [
-            "last"
-          ],
-          "fields": "",
-          "values": false
-        },
-        "showThresholdLabels": false,
-        "showThresholdMarkers": true,
-        "text": {}
+        "showHeader": true
       },
       "pluginVersion": "8.0.6",
       "targets": [
         {
           "format": "table",
           "group": [],
+          "hide": false,
           "metricColumn": "none",
-          "queryType": "randomWalk",
           "rawQuery": true,
-          "rawSql": "select \n     ppm.id,\n    (pr_coding_time + CEILING(TIMESTAMPDIFF(second,pr.created_date,pr.merged_date)/60) + pr_deploy_time) as 'PR cycle time from lower-level metrics',\n    ppm.`pr_cycle_time` as 'PR cycle time from project_pr_metrics'\nfrom project_pr_metrics ppm\nleft join pull_requests pr on ppm.id = pr.id\nwhere \n    project_name in ($project)\n    and pr.id = '$pr_id'",
+          "rawSql": "with _pr_stats as (\n-- get the cycle time of PRs deployed by the deployments finished each month\n\tSELECT\n\t\tdistinct\n\t\tdate_format(cdc.finished_date,'%y/%m') as month,\n\t\tpr.id,\n\t\tppm.pr_cycle_time\n\tFROM\n\t\tpull_requests pr\n\t\tjoin project_pr_metrics ppm on ppm.id = pr.id\n\t\tjoin project_mapping pm on pr.base_repo_id = pm.row_id and pm.`table` = 'repos'\n\t\tjoin cicd_deployment_commits cdc on ppm.deployment_commit_id = cdc.id\n\tWHERE\n\t\tpm.pr [...]
           "refId": "A",
           "select": [
             [
@@ -2043,8 +2235,8 @@
               }
             ]
           ],
-          "table": "_devlake_tasks",
-          "timeColumn": "created_at",
+          "table": "ae_projects",
+          "timeColumn": "ae_create_time",
           "timeColumnType": "timestamp",
           "where": [
             {
@@ -2055,8 +2247,10 @@
           ]
         }
       ],
-      "title": "Step 7. Check if PR cycle time in table.project_pr_metrics is accurate (Adopt the Pull Request filter above)",
-      "type": "gauge"
+      "timeFrom": null,
+      "timeShift": null,
+      "title": "Step 5 - check the median change lead time for each month in Figure 4 (Compare the change_lead_time with the max ranks in GREEN before the first occurence of ORANGE in each month)",
+      "type": "table"
     },
     {
       "collapsed": false,
@@ -2065,13 +2259,57 @@
         "h": 1,
         "w": 24,
         "x": 0,
-        "y": 57
+        "y": 71
       },
       "id": 26,
       "panels": [],
-      "title": "Change Failure Rate & Median Time to Restore Service",
+      "title": "Check \"Change Failure Rate\" & \"Median Time to Restore Service\"",
       "type": "row"
     },
+    {
+      "datasource": null,
+      "gridPos": {
+        "h": 4,
+        "w": 24,
+        "x": 0,
+        "y": 72
+      },
+      "id": 66,
+      "options": {
+        "content": "- See the definition and calculation logic of [Median Time to Restore Service](https://devlake.apache.org/docs/Metrics/MTTR)\n- Data Sources Required: \n  - `Deployments` from Jenkins, GitLab CI, GitHub Action, BitBucket Pipelines, or Webhook, etc. \n  - `Incidents` from Jira issues, GitHub issues, TAPD issues, PagerDuty Incidents, etc. \n- Transformation Required: Define `deployments` and `incidents` in [data transformations](https://devlake.apache.org/docs/Configura [...]
+        "mode": "markdown"
+      },
+      "pluginVersion": "8.0.6",
+      "targets": [
+        {
+          "queryType": "randomWalk",
+          "refId": "A"
+        }
+      ],
+      "type": "text"
+    },
+    {
+      "datasource": null,
+      "gridPos": {
+        "h": 4,
+        "w": 24,
+        "x": 0,
+        "y": 76
+      },
+      "id": 67,
+      "options": {
+        "content": "- See the definition and calculation logic of [Change Failure Rate](https://devlake.apache.org/docs/Metrics/CFR)\n- Data Sources Required: \n  - `Deployments` from Jenkins, GitLab CI, GitHub Action, BitBucket Pipelines, or Webhook, etc. \n  - `Incidents` from Jira issues, GitHub issues, TAPD issues, PagerDuty Incidents, etc. \n- Transformation Required: Define `deployments` and `incidents` in [data transformations](https://devlake.apache.org/docs/Configuration/Tutoria [...]
+        "mode": "markdown"
+      },
+      "pluginVersion": "8.0.6",
+      "targets": [
+        {
+          "queryType": "randomWalk",
+          "refId": "A"
+        }
+      ],
+      "type": "text"
+    },
     {
       "datasource": "mysql",
       "fieldConfig": {
@@ -2115,7 +2353,7 @@
         "h": 6,
         "w": 16,
         "x": 0,
-        "y": 58
+        "y": 80
       },
       "id": 31,
       "options": {
@@ -2207,7 +2445,7 @@
         "h": 10,
         "w": 8,
         "x": 16,
-        "y": 58
+        "y": 80
       },
       "id": 42,
       "options": {
@@ -2303,7 +2541,7 @@
         "h": 4,
         "w": 16,
         "x": 0,
-        "y": 64
+        "y": 86
       },
       "id": 14,
       "options": {
@@ -2351,7 +2589,7 @@
         "h": 15,
         "w": 16,
         "x": 0,
-        "y": 68
+        "y": 90
       },
       "id": 61,
       "options": {
@@ -2427,7 +2665,7 @@
         "h": 10,
         "w": 8,
         "x": 16,
-        "y": 68
+        "y": 90
       },
       "id": 46,
       "options": {
@@ -2453,7 +2691,7 @@
           "hide": false,
           "metricColumn": "none",
           "rawQuery": true,
-          "rawSql": "-- Metric 3: median time to restore service - MTTR\nwith _incidents as (\n-- get the number of incidents created each month\n\tSELECT\n\t  distinct i.id,\n\t\tdate_format(i.created_date,'%y/%m') as month,\n\t\tcast(lead_time_minutes as signed) as lead_time_minutes\n\tFROM\n\t\tissues i\n\t  join board_issues bi on i.id = bi.issue_id\n\t  join boards b on bi.board_id = b.id\n\t  join project_mapping pm on b.id = pm.row_id and pm.`table` = 'boards'\n\tWHERE\n\t  pm.pro [...]
+          "rawSql": "-- Metric 3: median time to restore service - MTTR\nwith _incidents as (\n-- get the number of incidents created each month\n\tSELECT\n\t  distinct i.id,\n\t\tdate_format(i.created_date,'%y/%m') as month,\n\t\tcast(lead_time_minutes as signed) as lead_time_minutes\n\tFROM\n\t\tissues i\n\t  join board_issues bi on i.id = bi.issue_id\n\t  join boards b on bi.board_id = b.id\n\t  join project_mapping pm on b.id = pm.row_id and pm.`table` = 'boards'\n\tWHERE\n\t  pm.pro [...]
           "refId": "A",
           "select": [
             [
@@ -2528,7 +2766,7 @@
         "h": 8,
         "w": 8,
         "x": 16,
-        "y": 78
+        "y": 100
       },
       "id": 44,
       "options": {
@@ -2625,7 +2863,7 @@
         "h": 13,
         "w": 8,
         "x": 0,
-        "y": 83
+        "y": 105
       },
       "id": 58,
       "options": {
@@ -2711,7 +2949,7 @@
         "h": 13,
         "w": 8,
         "x": 8,
-        "y": 83
+        "y": 105
       },
       "id": 59,
       "options": {
@@ -2810,7 +3048,7 @@
         "h": 10,
         "w": 8,
         "x": 16,
-        "y": 86
+        "y": 108
       },
       "id": 48,
       "options": {
@@ -2823,7 +3061,9 @@
         },
         "orientation": "auto",
         "showValue": "auto",
-        "text": {},
+        "text": {
+          "valueSize": 12
+        },
         "tooltip": {
           "mode": "single"
         }
@@ -2836,7 +3076,7 @@
           "hide": false,
           "metricColumn": "none",
           "rawQuery": true,
-          "rawSql": "-- Metric 4: change failure rate per month\nwith _deployments as (\n-- When deploying multiple commits in one pipeline, GitLab and BitBucket may generate more than one deployment. However, DevLake consider these deployments as ONE production deployment and use the last one's finished_date as the finished date.\n\tSELECT\n\t\tcdc.cicd_deployment_id as deployment_id,\n\t\tmax(cdc.finished_date) as deployment_finished_date\n\tFROM \n\t\tcicd_deployment_commits cdc\n\t\t [...]
+          "rawSql": "-- Metric 4: change failure rate per month\nwith _deployments as (\n-- When deploying multiple commits in one pipeline, GitLab and BitBucket may generate more than one deployment. However, DevLake consider these deployments as ONE production deployment and use the last one's finished_date as the finished date.\n\tSELECT\n\t\tcdc.cicd_deployment_id as deployment_id,\n\t\tmax(cdc.finished_date) as deployment_finished_date\n\tFROM \n\t\tcicd_deployment_commits cdc\n\t\t [...]
           "refId": "A",
           "select": [
             [
@@ -2930,5 +3170,5 @@
   "timezone": "",
   "title": "DORA Dashboard Validation",
   "uid": "KGkUnV-Vz",
-  "version": 45
+  "version": 75
 }
\ No newline at end of file