This is an automated email from the ASF dual-hosted git repository.
warren830 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/devlake.git
The following commit(s) were added to refs/heads/main by this push:
new d7ab23559 fix(kiro): align connection status and PostgreSQL dashboards
(#9082)
d7ab23559 is described below
commit d7ab23559d08e41a59d6638fc7a7f5402c126954
Author: Warren Chen <[email protected]>
AuthorDate: Tue Sep 1 22:32:32 2026 +0800
fix(kiro): align connection status and PostgreSQL dashboards (#9082)
* fix(kiro): report successful connection tests
Signed-off-by: warren <[email protected]>
* fix(grafana): repair PostgreSQL Kiro queries
Signed-off-by: warren <[email protected]>
---------
Signed-off-by: warren <[email protected]>
---
backend/plugins/kiro/api/test_connection.go | 23 ++++++---
backend/plugins/kiro/api/test_connection_test.go | 56 ++++++++++++++++++++++
grafana/dashboards/postgresql/kiro_executive.json | 10 ++--
grafana/dashboards/postgresql/kiro_logging.json | 14 +++---
.../dashboards/postgresql/kiro_user_report.json | 8 ++--
5 files changed, 89 insertions(+), 22 deletions(-)
diff --git a/backend/plugins/kiro/api/test_connection.go
b/backend/plugins/kiro/api/test_connection.go
index 8df055e58..de9fea373 100644
--- a/backend/plugins/kiro/api/test_connection.go
+++ b/backend/plugins/kiro/api/test_connection.go
@@ -95,6 +95,11 @@ func TestExistingConnection(input *plugin.ApiResourceInput)
(*plugin.ApiResource
// discovered accounts and per-stream object counts makes the difference
visible
// before any scope is created.
type ConnectionReport struct {
+ // Success and Message satisfy the shared Config UI connection-test
contract.
+ // The detailed fields below remain available to explain an empty
export.
+ Success bool `json:"success"`
+ Message string `json:"message"`
+
ReportBucket string `json:"reportBucket"`
PromptLogBucket string `json:"promptLogBucket"`
// Accounts are the AWS account ids found under the report prefix. An
empty
@@ -111,18 +116,24 @@ type ConnectionReport struct {
// verifying a path - only whether it is zero.
const connectionReportCountLimit = 500
+func newConnectionReport(connection *models.KiroConnection) *ConnectionReport {
+ return &ConnectionReport{
+ Success: true,
+ Message: "success",
+ ReportBucket: connection.Bucket,
+ PromptLogBucket: connection.GetPromptLogBucket(),
+ Accounts: []string{},
+ Streams: []tasks.StreamCount{},
+ }
+}
+
// buildConnectionReport probes the layout and summarizes what was found.
//
// Errors are folded into the report rather than returned: the connection
itself
// is already known to work at this point, and a discovery failure is more
useful
// shown as an empty result with a hint than as a failed request.
func buildConnectionReport(connection *models.KiroConnection)
*ConnectionReport {
- report := &ConnectionReport{
- ReportBucket: connection.Bucket,
- PromptLogBucket: connection.GetPromptLogBucket(),
- Accounts: []string{},
- Streams: []tasks.StreamCount{},
- }
+ report := newConnectionReport(connection)
discovery, err := tasks.NewDiscovery(connection)
if err != nil {
diff --git a/backend/plugins/kiro/api/test_connection_test.go
b/backend/plugins/kiro/api/test_connection_test.go
new file mode 100644
index 000000000..7b30ca366
--- /dev/null
+++ b/backend/plugins/kiro/api/test_connection_test.go
@@ -0,0 +1,56 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package api
+
+import (
+ "encoding/json"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/apache/incubator-devlake/plugins/kiro/models"
+)
+
+func TestNewConnectionReportSatisfiesConfigUIContract(t *testing.T) {
+ connection := &models.KiroConnection{
+ KiroConn: models.KiroConn{
+ Bucket: "report-bucket",
+ PromptLogBucket: "log-bucket",
+ },
+ }
+
+ report := newConnectionReport(connection)
+ assert.True(t, report.Success)
+ assert.Equal(t, "success", report.Message)
+ assert.Equal(t, "report-bucket", report.ReportBucket)
+ assert.Equal(t, "log-bucket", report.PromptLogBucket)
+ assert.NotNil(t, report.Accounts)
+ assert.NotNil(t, report.Streams)
+
+ body, err := json.Marshal(report)
+ require.NoError(t, err)
+ assert.JSONEq(t, `{
+ "success": true,
+ "message": "success",
+ "reportBucket": "report-bucket",
+ "promptLogBucket": "log-bucket",
+ "accounts": [],
+ "streams": []
+ }`, string(body))
+}
diff --git a/grafana/dashboards/postgresql/kiro_executive.json
b/grafana/dashboards/postgresql/kiro_executive.json
index 9a13ba801..f1a8711be 100644
--- a/grafana/dashboards/postgresql/kiro_executive.json
+++ b/grafana/dashboards/postgresql/kiro_executive.json
@@ -126,7 +126,7 @@
"editorMode": "code",
"format": "table",
"rawQuery": true,
- "rawSql": "SELECT COUNT(DISTINCT user_id) AS \"WAU\" FROM
lake._tool_kiro_chat_log WHERE timestamp >= NOW() - INTERVAL '7 DAY'",
+ "rawSql": "SELECT COUNT(DISTINCT user_id) AS \"WAU\" FROM
_tool_kiro_chat_log WHERE timestamp >= NOW() - INTERVAL '7 DAY'",
"refId": "A"
}
],
@@ -322,7 +322,7 @@
"editorMode": "code",
"format": "table",
"rawQuery": true,
- "rawSql": "SELECT ROUND(CAST(CAST(COUNT(DISTINCT CASE WHEN
has_steering = TRUE THEN user_id END) AS NUMERIC) /
NULLIF(NULLIF(COUNT(DISTINCT user_id), 0), 0) * 100 AS DECIMAL), 0) AS
\"Steering %\" FROM lake._tool_kiro_chat_log WHERE $__timeFilter(timestamp)",
+ "rawSql": "SELECT ROUND(CAST(CAST(COUNT(DISTINCT CASE WHEN
has_steering = TRUE THEN user_id END) AS NUMERIC) /
NULLIF(NULLIF(COUNT(DISTINCT user_id), 0), 0) * 100 AS DECIMAL), 0) AS
\"Steering %\" FROM _tool_kiro_chat_log WHERE $__timeFilter(timestamp)",
"refId": "A"
}
],
@@ -433,7 +433,7 @@
"editorMode": "code",
"format": "time_series",
"rawQuery": true,
- "rawSql": "SELECT TO_DATE(yw || ' Monday', 'IYYYIW FMDay') AS time,
COUNT(DISTINCT user_id) AS \"Active Users\" FROM (SELECT user_id,
(EXTRACT(ISOYEAR FROM timestamp) * 100 + EXTRACT(WEEK FROM timestamp))::int AS
yw FROM lake._tool_kiro_chat_log WHERE $__timeFilter(timestamp)) AS t GROUP BY
\"yw\" ORDER BY time NULLS FIRST",
+ "rawSql": "SELECT TO_DATE(yw || ' Monday', 'IYYYIW FMDay') AS time,
COUNT(DISTINCT user_id) AS \"Active Users\" FROM (SELECT user_id,
(EXTRACT(ISOYEAR FROM timestamp) * 100 + EXTRACT(WEEK FROM timestamp))::int AS
yw FROM _tool_kiro_chat_log WHERE $__timeFilter(timestamp)) AS t GROUP BY
\"yw\" ORDER BY time NULLS FIRST",
"refId": "A"
}
],
@@ -642,7 +642,7 @@
"editorMode": "code",
"format": "time_series",
"rawQuery": true,
- "rawSql": "SELECT date AS time, SUM(SUM(credits_used)) OVER (ORDER
BY date NULLS FIRST) AS \"Cumulative Credits\", (SELECT CAST(SUM(credits_used)
AS NUMERIC) / NULLIF(COUNT(DISTINCT date), 0) * EXTRACT(DAY FROM
CAST(CAST(DATE_TRUNC('MONTH', CURRENT_DATE) + INTERVAL '1 MONTH' - INTERVAL '1
DAY' AS DATE) AS DATE)) FROM lake._tool_kiro_user_report WHERE YEAR(CAST(date
AS DATE)) = YEAR(CAST(CURRENT_DATE AS DATE)) AND MONTH(CAST(date AS DATE)) =
MONTH(CAST(CURRENT_DATE AS DATE))) AS [...]
+ "rawSql": "SELECT date AS time, SUM(SUM(credits_used)) OVER (ORDER
BY date NULLS FIRST) AS \"Cumulative Credits\", (SELECT CAST(SUM(credits_used)
AS NUMERIC) / NULLIF(COUNT(DISTINCT date), 0) * EXTRACT(DAY FROM
CAST(CAST(DATE_TRUNC('MONTH', CURRENT_DATE) + INTERVAL '1 MONTH' - INTERVAL '1
DAY' AS DATE) AS DATE)) FROM _tool_kiro_user_report WHERE EXTRACT(YEAR FROM
date) = EXTRACT(YEAR FROM CURRENT_DATE) AND EXTRACT(MONTH FROM date) =
EXTRACT(MONTH FROM CURRENT_DATE)) AS \"Projec [...]
"refId": "A"
}
],
@@ -710,7 +710,7 @@
"editorMode": "code",
"format": "table",
"rawQuery": true,
- "rawSql": "SELECT COALESCE(MAX(display_name), user_id) AS \"User\",
MAX(subscription_tier) AS \"Tier\", ROUND(SUM(credits_used), 1) AS \"Total
Credits Used\", MAX(date) AS \"Last Activity\" FROM lake._tool_kiro_user_report
WHERE $__timeFilter(date) AND subscription_tier = 'POWER' GROUP BY \"user_id\"
HAVING MAX(date) < NOW() - INTERVAL '14 DAY' ORDER BY MAX(date) NULLS FIRST",
+ "rawSql": "SELECT COALESCE(MAX(display_name), user_id) AS \"User\",
MAX(subscription_tier) AS \"Tier\", ROUND(SUM(credits_used), 1) AS \"Total
Credits Used\", MAX(date) AS \"Last Activity\" FROM _tool_kiro_user_report
WHERE $__timeFilter(date) AND subscription_tier = 'POWER' GROUP BY \"user_id\"
HAVING MAX(date) < NOW() - INTERVAL '14 DAY' ORDER BY MAX(date) NULLS FIRST",
"refId": "A"
}
],
diff --git a/grafana/dashboards/postgresql/kiro_logging.json
b/grafana/dashboards/postgresql/kiro_logging.json
index c0b4396cf..0e3f36b0b 100644
--- a/grafana/dashboards/postgresql/kiro_logging.json
+++ b/grafana/dashboards/postgresql/kiro_logging.json
@@ -171,7 +171,7 @@
"editorMode": "code",
"format": "table",
"rawQuery": true,
- "rawSql": "SELECT LPAD(CAST(hour_of_day AS TEXT), 2, '0') AS
\"Hour\", SUM(chat_count) AS \"Chat Events\", SUM(completion_count) AS
\"Completion Events\" FROM (SELECT EXTRACT(HOUR FROM timestamp) AS hour_of_day,
COUNT(*) AS chat_count, 0 AS completion_count FROM lake._tool_kiro_chat_log
WHERE $__timeFilter(timestamp) GROUP BY EXTRACT(HOUR FROM timestamp) UNION ALL
SELECT EXTRACT(HOUR FROM timestamp) AS hour_of_day, 0 AS chat_count, COUNT(*)
AS completion_count FROM lake._tool_k [...]
+ "rawSql": "SELECT LPAD(CAST(hour_of_day AS TEXT), 2, '0') AS
\"Hour\", SUM(chat_count) AS \"Chat Events\", SUM(completion_count) AS
\"Completion Events\" FROM (SELECT EXTRACT(HOUR FROM timestamp) AS hour_of_day,
COUNT(*) AS chat_count, 0 AS completion_count FROM _tool_kiro_chat_log WHERE
$__timeFilter(timestamp) GROUP BY EXTRACT(HOUR FROM timestamp) UNION ALL SELECT
EXTRACT(HOUR FROM timestamp) AS hour_of_day, 0 AS chat_count, COUNT(*) AS
completion_count FROM _tool_kiro_comple [...]
"refId": "A"
}
],
@@ -245,7 +245,7 @@
"editorMode": "code",
"format": "table",
"rawQuery": true,
- "rawSql": "SELECT CASE WHEN chat_trigger_type = '' OR
chat_trigger_type IS NULL THEN '(unknown)' ELSE chat_trigger_type END AS
\"Trigger Type\", COUNT(*) AS \"Events\" FROM lake._tool_kiro_chat_log WHERE
$__timeFilter(timestamp) GROUP BY \"chat_trigger_type\" ORDER BY COUNT(*) DESC
NULLS LAST",
+ "rawSql": "SELECT CASE WHEN chat_trigger_type = '' OR
chat_trigger_type IS NULL THEN '(unknown)' ELSE chat_trigger_type END AS
\"Trigger Type\", COUNT(*) AS \"Events\" FROM _tool_kiro_chat_log WHERE
$__timeFilter(timestamp) GROUP BY \"chat_trigger_type\" ORDER BY COUNT(*) DESC
NULLS LAST",
"refId": "A"
}
],
@@ -393,7 +393,7 @@
"editorMode": "code",
"format": "table",
"rawQuery": true,
- "rawSql": "SELECT CASE WHEN file_extension = '' THEN '(unknown)'
ELSE file_extension END AS \"File Type\", COUNT(*) AS \"Completions\" FROM
lake._tool_kiro_completion_log WHERE $__timeFilter(timestamp) GROUP BY
\"file_extension\" ORDER BY COUNT(*) DESC NULLS LAST LIMIT 15",
+ "rawSql": "SELECT CASE WHEN file_extension = '' THEN '(unknown)'
ELSE file_extension END AS \"File Type\", COUNT(*) AS \"Completions\" FROM
_tool_kiro_completion_log WHERE $__timeFilter(timestamp) GROUP BY
\"file_extension\" ORDER BY COUNT(*) DESC NULLS LAST LIMIT 15",
"refId": "A"
}
],
@@ -589,7 +589,7 @@
"editorMode": "code",
"format": "time_series",
"rawQuery": true,
- "rawSql": "SELECT time, SUM(chat) AS \"Chat Events\",
SUM(completions) AS \"Completion Events\" FROM (SELECT CAST(timestamp AS DATE)
AS time, COUNT(*) AS chat, 0 AS completions FROM lake._tool_kiro_chat_log WHERE
$__timeFilter(timestamp) GROUP BY CAST(timestamp AS DATE) UNION ALL SELECT
CAST(timestamp AS DATE) AS time, 0 AS chat, COUNT(*) AS completions FROM
lake._tool_kiro_completion_log WHERE $__timeFilter(timestamp) GROUP BY
CAST(timestamp AS DATE)) AS combined GROUP BY time [...]
+ "rawSql": "SELECT time, SUM(chat) AS \"Chat Events\",
SUM(completions) AS \"Completion Events\" FROM (SELECT CAST(timestamp AS DATE)
AS time, COUNT(*) AS chat, 0 AS completions FROM _tool_kiro_chat_log WHERE
$__timeFilter(timestamp) GROUP BY CAST(timestamp AS DATE) UNION ALL SELECT
CAST(timestamp AS DATE) AS time, 0 AS chat, COUNT(*) AS completions FROM
_tool_kiro_completion_log WHERE $__timeFilter(timestamp) GROUP BY
CAST(timestamp AS DATE)) AS combined GROUP BY time ORDER BY [...]
"refId": "A"
}
],
@@ -731,7 +731,7 @@
"editorMode": "code",
"format": "table",
"rawQuery": true,
- "rawSql": "SELECT SUM(CASE WHEN has_steering = TRUE THEN 1 ELSE 0
END) AS \"Using Steering\", SUM(CASE WHEN is_spec_mode = TRUE THEN 1 ELSE 0
END) AS \"Using Spec Mode\", SUM(CASE WHEN has_steering = FALSE AND
is_spec_mode = FALSE THEN 1 ELSE 0 END) AS \"Plain Chat\" FROM
lake._tool_kiro_chat_log WHERE $__timeFilter(timestamp)",
+ "rawSql": "SELECT SUM(CASE WHEN has_steering = TRUE THEN 1 ELSE 0
END) AS \"Using Steering\", SUM(CASE WHEN is_spec_mode = TRUE THEN 1 ELSE 0
END) AS \"Using Spec Mode\", SUM(CASE WHEN has_steering = FALSE AND
is_spec_mode = FALSE THEN 1 ELSE 0 END) AS \"Plain Chat\" FROM
_tool_kiro_chat_log WHERE $__timeFilter(timestamp)",
"refId": "A"
}
],
@@ -977,7 +977,7 @@
"editorMode": "code",
"format": "time_series",
"rawQuery": true,
- "rawSql": "SELECT CAST(timestamp AS DATE) AS time,
AVG(prompt_length) AS \"Avg Prompt Length\", AVG(response_length) AS \"Avg
Response Length\", MAX(prompt_length) AS \"Max Prompt Length\",
MAX(response_length) AS \"Max Response Length\" FROM lake._tool_kiro_chat_log
WHERE $__timeFilter(timestamp) GROUP BY CAST(timestamp AS DATE) ORDER BY
CAST(timestamp AS DATE) NULLS FIRST",
+ "rawSql": "SELECT CAST(timestamp AS DATE) AS time,
AVG(prompt_length) AS \"Avg Prompt Length\", AVG(response_length) AS \"Avg
Response Length\", MAX(prompt_length) AS \"Max Prompt Length\",
MAX(response_length) AS \"Max Response Length\" FROM _tool_kiro_chat_log WHERE
$__timeFilter(timestamp) GROUP BY CAST(timestamp AS DATE) ORDER BY
CAST(timestamp AS DATE) NULLS FIRST",
"refId": "A"
}
],
@@ -1074,7 +1074,7 @@
"editorMode": "code",
"format": "time_series",
"rawQuery": true,
- "rawSql": "SELECT CAST(timestamp AS DATE) AS time,
ROUND(AVG(left_context_length)) AS \"Avg Left Context\",
ROUND(AVG(right_context_length)) AS \"Avg Right Context\",
ROUND(AVG(left_context_length + right_context_length)) AS \"Avg Total Context\"
FROM lake._tool_kiro_completion_log WHERE $__timeFilter(timestamp) GROUP BY
CAST(timestamp AS DATE) ORDER BY CAST(timestamp AS DATE) NULLS FIRST",
+ "rawSql": "SELECT CAST(timestamp AS DATE) AS time,
ROUND(AVG(left_context_length)) AS \"Avg Left Context\",
ROUND(AVG(right_context_length)) AS \"Avg Right Context\",
ROUND(AVG(left_context_length + right_context_length)) AS \"Avg Total Context\"
FROM _tool_kiro_completion_log WHERE $__timeFilter(timestamp) GROUP BY
CAST(timestamp AS DATE) ORDER BY CAST(timestamp AS DATE) NULLS FIRST",
"refId": "A"
}
],
diff --git a/grafana/dashboards/postgresql/kiro_user_report.json
b/grafana/dashboards/postgresql/kiro_user_report.json
index 4f720f1aa..8f257a6a8 100644
--- a/grafana/dashboards/postgresql/kiro_user_report.json
+++ b/grafana/dashboards/postgresql/kiro_user_report.json
@@ -76,7 +76,7 @@
"editorMode": "code",
"format": "table",
"rawQuery": true,
- "rawSql": "SELECT SUM(credits_used) AS \"Total Credits Used\",
COUNT(DISTINCT user_id) AS \"Active Users\", SUM(total_messages) AS \"Total
Messages\", SUM(chat_conversations) AS \"Total Conversations\" FROM
lake._tool_kiro_user_report WHERE $__timeFilter(date)",
+ "rawSql": "SELECT SUM(credits_used) AS \"Total Credits Used\",
COUNT(DISTINCT user_id) AS \"Active Users\", SUM(total_messages) AS \"Total
Messages\", SUM(chat_conversations) AS \"Total Conversations\" FROM
_tool_kiro_user_report WHERE $__timeFilter(date)",
"refId": "A"
}
],
@@ -174,7 +174,7 @@
"editorMode": "code",
"format": "time_series",
"rawQuery": true,
- "rawSql": "SELECT date AS time, subscription_tier AS metric,
SUM(credits_used) AS value FROM lake._tool_kiro_user_report WHERE
$__timeFilter(date) GROUP BY \"date\", \"subscription_tier\" ORDER BY date
NULLS FIRST",
+ "rawSql": "SELECT date AS time, subscription_tier AS metric,
SUM(credits_used) AS value FROM _tool_kiro_user_report WHERE
$__timeFilter(date) GROUP BY \"date\", \"subscription_tier\" ORDER BY date
NULLS FIRST",
"refId": "A"
}
],
@@ -346,7 +346,7 @@
"editorMode": "code",
"format": "table",
"rawQuery": true,
- "rawSql": "SELECT subscription_tier AS \"Tier\", COUNT(DISTINCT
user_id) AS \"Users\" FROM lake._tool_kiro_user_report WHERE
$__timeFilter(date) AND NOT subscription_tier IS NULL AND subscription_tier <>
'' GROUP BY \"subscription_tier\" ORDER BY COUNT(DISTINCT user_id) DESC NULLS
LAST",
+ "rawSql": "SELECT subscription_tier AS \"Tier\", COUNT(DISTINCT
user_id) AS \"Users\" FROM _tool_kiro_user_report WHERE $__timeFilter(date) AND
NOT subscription_tier IS NULL AND subscription_tier <> '' GROUP BY
\"subscription_tier\" ORDER BY COUNT(DISTINCT user_id) DESC NULLS LAST",
"refId": "A"
}
],
@@ -463,7 +463,7 @@
"editorMode": "code",
"format": "table",
"rawQuery": true,
- "rawSql": "SELECT COALESCE(MAX(display_name), user_id) AS \"User\",
subscription_tier AS \"Tier\", client_type AS \"Client\", SUM(credits_used) AS
\"Credits Used\", SUM(total_messages) AS \"Messages\", SUM(chat_conversations)
AS \"Conversations\", SUM(overage_credits_used) AS \"Overage Credits\", CASE
WHEN MAX(CAST(overage_enabled AS BIGINT)) = 1 THEN 'Yes' ELSE 'No' END AS
\"Overage\", MIN(date) AS \"First Activity\", MAX(date) AS \"Last Activity\"
FROM lake._tool_kiro_user_re [...]
+ "rawSql": "SELECT COALESCE(MAX(display_name), user_id) AS \"User\",
subscription_tier AS \"Tier\", client_type AS \"Client\", SUM(credits_used) AS
\"Credits Used\", SUM(total_messages) AS \"Messages\", SUM(chat_conversations)
AS \"Conversations\", SUM(overage_credits_used) AS \"Overage Credits\", CASE
WHEN BOOL_OR(overage_enabled) THEN 'Yes' ELSE 'No' END AS \"Overage\",
MIN(date) AS \"First Activity\", MAX(date) AS \"Last Activity\" FROM
_tool_kiro_user_report WHERE $__timeFil [...]
"refId": "A"
}
],