diff --git a/backend/capellacollab/feedback/crud.py b/backend/capellacollab/feedback/crud.py index dafcc30ac9..6184bd4a2a 100644 --- a/backend/capellacollab/feedback/crud.py +++ b/backend/capellacollab/feedback/crud.py @@ -13,13 +13,24 @@ def count_feedback_by_rating( db: orm.Session, -) -> dict[models.FeedbackRating, int]: +) -> dict[tuple[models.FeedbackRating, bool], int]: + anonymity_case = sa.case( + (models.DatabaseFeedback.user_id.is_(None), True), + else_=False, + ) + return { - value[0]: value[1] + (value[0], value[1]): value[2] for value in db.execute( sa.select( - models.DatabaseFeedback.rating, sa.func.count() - ).group_by(models.DatabaseFeedback.rating) + models.DatabaseFeedback.rating, + anonymity_case.label("anonymous"), + # pylint: disable=not-callable + sa.func.count(), + ).group_by( + models.DatabaseFeedback.rating, + anonymity_case, + ) ).all() } diff --git a/backend/capellacollab/feedback/metrics.py b/backend/capellacollab/feedback/metrics.py index b113fee05c..8dcb94ae7a 100644 --- a/backend/capellacollab/feedback/metrics.py +++ b/backend/capellacollab/feedback/metrics.py @@ -17,14 +17,19 @@ def collect(self) -> t.Iterable[prometheus_client.core.Metric]: metric = prometheus_client.core.GaugeMetricFamily( "feedback_count", "Submitted feedback", - labels=["rating"], + labels=["rating", "anonymous"], ) with database.SessionLocal() as db: feedback = crud.count_feedback_by_rating(db) for rating in models.FeedbackRating: - metric.add_metric([str(rating.value)], feedback.get(rating, 0)) + metric.add_metric( + [str(rating.value), "true"], feedback.get((rating, True), 0) + ) + metric.add_metric( + [str(rating.value), "false"], feedback.get((rating, False), 0) + ) yield metric diff --git a/backend/tests/test_feedback.py b/backend/tests/test_feedback.py index 4161790f8f..62c254f03a 100644 --- a/backend/tests/test_feedback.py +++ b/backend/tests/test_feedback.py @@ -278,10 +278,10 @@ def test_feedback_metric(db: orm.Session): collector = feedback_metrics.FeedbackCollector() data = list(collector.collect()) - assert len(data[0].samples) == 3 + assert len(data[0].samples) == 6 bad_sample = data[0].samples[0] - good_sample = data[0].samples[2] + good_sample = data[0].samples[4] assert bad_sample.labels["rating"] == "bad" assert bad_sample.name == "feedback_count" diff --git a/helm/config/grafana/dashboards/feedback.json b/helm/config/grafana/dashboards/feedback.json index 380a7b6f82..5c659c4721 100644 --- a/helm/config/grafana/dashboards/feedback.json +++ b/helm/config/grafana/dashboards/feedback.json @@ -151,7 +151,9 @@ "id": 13, "options": { "legend": { - "calcs": ["lastNotNull"], + "calcs": [ + "lastNotNull" + ], "displayMode": "list", "placement": "bottom", "showLegend": false @@ -168,7 +170,7 @@ "uid": "prometheus_ccm" }, "editorMode": "code", - "expr": "round(increase(feedback_count[$__range]))", + "expr": "round(sum by (rating) (increase(feedback_count[$__range])))", "instant": false, "legendFormat": "{{rating}}", "range": true, @@ -259,13 +261,15 @@ }, "gridPos": { "h": 6, - "w": 5, + "w": 4, "x": 0, "y": 8 }, "id": 8, "options": { - "displayLabels": ["percent"], + "displayLabels": [ + "percent" + ], "legend": { "displayMode": "list", "placement": "bottom", @@ -274,7 +278,9 @@ }, "pieType": "pie", "reduceOptions": { - "calcs": ["lastNotNull"], + "calcs": [ + "lastNotNull" + ], "fields": "", "values": false }, @@ -290,7 +296,7 @@ "uid": "prometheus_ccm" }, "editorMode": "code", - "expr": "round(increase(feedback_count[$__range]))", + "expr": "round(sum by (rating) (increase(feedback_count[$__range])))", "instant": false, "legendFormat": "{{rating}}", "range": true, @@ -333,8 +339,8 @@ }, "gridPos": { "h": 6, - "w": 5, - "x": 5, + "w": 3, + "x": 4, "y": 8 }, "id": 12, @@ -343,7 +349,9 @@ "minVizWidth": 75, "orientation": "auto", "reduceOptions": { - "calcs": ["lastNotNull"], + "calcs": [ + "lastNotNull" + ], "fields": "", "values": false }, @@ -378,6 +386,79 @@ ], "type": "gauge" }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus_ccm" + }, + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "blue", + "mode": "fixed" + }, + "fieldMinMax": false, + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 3, + "x": 7, + "y": 8 + }, + "id": 15, + "options": { + "minVizHeight": 75, + "minVizWidth": 75, + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showThresholdLabels": false, + "showThresholdMarkers": false, + "sizing": "auto", + "text": {} + }, + "pluginVersion": "11.1.0", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus_ccm" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "round((sum(increase(feedback_count{anonymous=\"true\"}[$__range])) / sum(increase(feedback_count[$__range]))) * 100)", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Share of anonymous feedback", + "type": "gauge" + }, { "datasource": { "type": "prometheus", @@ -490,6 +571,6 @@ "timezone": "", "title": "Feedback", "uid": "edzhg6sv97lz4c", - "version": 2, + "version": 3, "weekStart": "" }