From 01bcbfd4fdbd904cbd08175e546f8a0b0eeb8458 Mon Sep 17 00:00:00 2001 From: Yuriy Kurant Date: Mon, 2 Jun 2025 23:58:59 +0800 Subject: [PATCH 1/8] ux: category-id-input: allows no-category selection --- .../discourse/components/param-input/category-id-input.gjs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/assets/javascripts/discourse/components/param-input/category-id-input.gjs b/assets/javascripts/discourse/components/param-input/category-id-input.gjs index 96d5baa5..e626a6be 100644 --- a/assets/javascripts/discourse/components/param-input/category-id-input.gjs +++ b/assets/javascripts/discourse/components/param-input/category-id-input.gjs @@ -1,4 +1,5 @@ import Component from "@glimmer/component"; +import { hash } from "@ember/helper"; import CategoryChooser from "select-kit/components/category-chooser"; export default class CategoryIdInput extends Component { @@ -15,6 +16,11 @@ export default class CategoryIdInput extends Component { From f12e3ba4d134a1c621325ef3703448ba85a3d0ae Mon Sep 17 00:00:00 2001 From: Yuriy Kurant Date: Tue, 3 Jun 2025 21:01:34 +0800 Subject: [PATCH 2/8] DEV: category_id query param: adds basic acceptance test --- .../acceptance/param-input-test.js | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/test/javascripts/acceptance/param-input-test.js b/test/javascripts/acceptance/param-input-test.js index 84174eba..adf0c4db 100644 --- a/test/javascripts/acceptance/param-input-test.js +++ b/test/javascripts/acceptance/param-input-test.js @@ -373,6 +373,35 @@ acceptance("Data Explorer Plugin | Param Input", function (needs) { }, }); }); + + server.get("/admin/plugins/explorer/queries/4", () => { + return helper.response({ + query: { + id: 4, + sql: "-- [params]\n-- null category_id :category\n\nSELECT 1", + name: "Params test - category_id chooser", + description: "Test for category_id param.", + param_info: [ + { + identifier: "category", + type: "category_id", + default: null, + nullable: true, + }, + ], + created_at: "2025-06-03T09:05:59.337Z", + username: "system", + group_ids: [], + last_run_at: "2025-06-03T09:05:59.337Z", + hidden: false, + category_id: null, + }, + }); + }); + + server.post("/admin/plugins/explorer/queries/4/run", () => { + return helper.response({}); + }); }); test("puts params for the query into the url", async function (assert) { @@ -429,4 +458,21 @@ acceptance("Data Explorer Plugin | Param Input", function (needs) { await click(".query-edit .btn-save-query"); assert.dom(".query-params input").exists(); }); + + test("nullable category_id param: puts params for the query into the url", async function (assert) { + const selectedCategory = { id: "6", name: "support" }; + + await visit("/admin/plugins/explorer/queries/4"); + assert.dom(".select-kit-selected-name").hasText("(no category)"); + + await click(".select-kit-selected-name"); + await click(".category-row.select-kit-row:first-of-type"); + assert.dom(".select-kit-selected-name").hasText(selectedCategory.name); + + await click("form.query-run button"); + + const searchParams = new URLSearchParams(currentURL().split("?")[1]); + const categoryIdParam = JSON.parse(searchParams.get("params")).category; + assert.strictEqual(categoryIdParam, selectedCategory.id); + }); }); From 7f922c95b6bcc20b47f757902a416967463cbcf7 Mon Sep 17 00:00:00 2001 From: Yuriy Kurant Date: Tue, 3 Jun 2025 21:02:48 +0800 Subject: [PATCH 3/8] DEV: acceptance tests cleanup: removes unused lines of code --- .../acceptance/list-queries-test.js | 73 +---------------- .../acceptance/param-input-test.js | 80 ++----------------- 2 files changed, 6 insertions(+), 147 deletions(-) diff --git a/test/javascripts/acceptance/list-queries-test.js b/test/javascripts/acceptance/list-queries-test.js index 74d75056..af74c99c 100644 --- a/test/javascripts/acceptance/list-queries-test.js +++ b/test/javascripts/acceptance/list-queries-test.js @@ -9,78 +9,7 @@ acceptance("Data Explorer Plugin | List Queries", function (needs) { needs.pretender((server, helper) => { server.get("/admin/plugins/explorer/groups.json", () => { - return helper.response([ - { - id: 1, - name: "admins", - }, - { - id: 2, - name: "moderators", - }, - { - id: 3, - name: "staff", - }, - { - id: 0, - name: "everyone", - }, - { - id: 10, - name: "trust_level_0", - }, - { - id: 11, - name: "trust_level_1", - }, - { - id: 12, - name: "trust_level_2", - }, - { - id: 13, - name: "trust_level_3", - }, - { - id: 14, - name: "trust_level_4", - }, - ]); - }); - - server.get("/admin/plugins/explorer/schema.json", () => { - return helper.response({ - anonymous_users: [ - { - column_name: "id", - data_type: "serial", - primary: true, - }, - { - column_name: "user_id", - data_type: "integer", - fkey_info: "users", - }, - { - column_name: "master_user_id", - data_type: "integer", - fkey_info: "users", - }, - { - column_name: "active", - data_type: "boolean", - }, - { - column_name: "created_at", - data_type: "timestamp", - }, - { - column_name: "updated_at", - data_type: "timestamp", - }, - ], - }); + return helper.response([]); }); server.get("/admin/plugins/explorer/queries", () => { diff --git a/test/javascripts/acceptance/param-input-test.js b/test/javascripts/acceptance/param-input-test.js index adf0c4db..064f9c63 100644 --- a/test/javascripts/acceptance/param-input-test.js +++ b/test/javascripts/acceptance/param-input-test.js @@ -8,82 +8,11 @@ acceptance("Data Explorer Plugin | Param Input", function (needs) { needs.pretender((server, helper) => { server.get("/admin/plugins/explorer/groups.json", () => { - return helper.response([ - { - id: 1, - name: "admins", - }, - { - id: 2, - name: "moderators", - }, - { - id: 3, - name: "staff", - }, - { - id: 0, - name: "everyone", - }, - { - id: 10, - name: "trust_level_0", - }, - { - id: 11, - name: "trust_level_1", - }, - { - id: 12, - name: "trust_level_2", - }, - { - id: 13, - name: "trust_level_3", - }, - { - id: 14, - name: "trust_level_4", - }, - { - id: 41, - name: "discourse", - }, - ]); + return helper.response([]); }); server.get("/admin/plugins/explorer/schema.json", () => { - return helper.response({ - anonymous_users: [ - { - column_name: "id", - data_type: "serial", - primary: true, - }, - { - column_name: "user_id", - data_type: "integer", - fkey_info: "users", - }, - { - column_name: "master_user_id", - data_type: "integer", - fkey_info: "users", - }, - { - column_name: "active", - data_type: "boolean", - }, - { - column_name: "created_at", - data_type: "timestamp", - }, - { - column_name: "updated_at", - data_type: "timestamp", - }, - ], - }); + return helper.response({}); }); server.get("/admin/plugins/explorer/queries", () => { @@ -353,7 +282,8 @@ acceptance("Data Explorer Plugin | Param Input", function (needs) { return helper.response({ query: { id: 3, - sql: "-- [params]\n-- int :months_ago = 1\n\nSELECT 1", + // sql: "-- [params]\n-- int :months_ago = 1\n\nSELECT 1", + sql: "-- [params]\n-- null category_id :cat_id\n-- int :months_ago = 1\n\nSELECT 1", name: "Params test", description: "test for params.", param_info: [ @@ -450,11 +380,11 @@ acceptance("Data Explorer Plugin | Param Input", function (needs) { await visit("/admin/plugins/explorer/queries/3"); assert.dom(".query-params input").doesNotExist(); await click(".query-edit .btn-edit-query"); - await click(".query-editor .ace_text-input"); await fillIn( ".query-editor .ace_text-input", "-- [params]\n-- int :months_ago = 1\n\nSELECT 1" ); + await click(".query-editor .ace_text-input"); // enables `Save Changes` button await click(".query-edit .btn-save-query"); assert.dom(".query-params input").exists(); }); From c52400d86f65bce2efd5dddd98d593fb6518f27b Mon Sep 17 00:00:00 2001 From: Yuriy Kurant Date: Tue, 3 Jun 2025 21:05:59 +0800 Subject: [PATCH 4/8] DEV: reverts leaked line change --- test/javascripts/acceptance/param-input-test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/javascripts/acceptance/param-input-test.js b/test/javascripts/acceptance/param-input-test.js index 064f9c63..66c3db48 100644 --- a/test/javascripts/acceptance/param-input-test.js +++ b/test/javascripts/acceptance/param-input-test.js @@ -282,8 +282,7 @@ acceptance("Data Explorer Plugin | Param Input", function (needs) { return helper.response({ query: { id: 3, - // sql: "-- [params]\n-- int :months_ago = 1\n\nSELECT 1", - sql: "-- [params]\n-- null category_id :cat_id\n-- int :months_ago = 1\n\nSELECT 1", + sql: "-- [params]\n-- int :months_ago = 1\n\nSELECT 1", name: "Params test", description: "test for params.", param_info: [ From ee13330822b5a1255a68157cd50a4c780370d571 Mon Sep 17 00:00:00 2001 From: Yuriy Kurant Date: Wed, 4 Jun 2025 13:28:07 +0800 Subject: [PATCH 5/8] DEV: param-input-test: updates selectors with select-kit-helper --- test/javascripts/acceptance/param-input-test.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/javascripts/acceptance/param-input-test.js b/test/javascripts/acceptance/param-input-test.js index 66c3db48..f75ccf57 100644 --- a/test/javascripts/acceptance/param-input-test.js +++ b/test/javascripts/acceptance/param-input-test.js @@ -1,6 +1,7 @@ import { click, currentURL, fillIn, visit } from "@ember/test-helpers"; import { test } from "qunit"; import { acceptance } from "discourse/tests/helpers/qunit-helpers"; +import selectKit from "discourse/tests/helpers/select-kit-helper"; acceptance("Data Explorer Plugin | Param Input", function (needs) { needs.user(); @@ -390,13 +391,14 @@ acceptance("Data Explorer Plugin | Param Input", function (needs) { test("nullable category_id param: puts params for the query into the url", async function (assert) { const selectedCategory = { id: "6", name: "support" }; + const catChooser = selectKit(".category-chooser"); await visit("/admin/plugins/explorer/queries/4"); - assert.dom(".select-kit-selected-name").hasText("(no category)"); + assert.strictEqual(catChooser.header().value(), null); - await click(".select-kit-selected-name"); - await click(".category-row.select-kit-row:first-of-type"); - assert.dom(".select-kit-selected-name").hasText(selectedCategory.name); + await catChooser.expand(); + await catChooser.selectRowByIndex(0); + assert.strictEqual(catChooser.header().label(), selectedCategory.name); await click("form.query-run button"); From 257f603ba0baf110851413033648d01c28efc51e Mon Sep 17 00:00:00 2001 From: Yuriy Kurant Date: Wed, 4 Jun 2025 19:17:56 +0800 Subject: [PATCH 6/8] DEV: param-input-test: adds null category_id query param check This commit includes DRY update: by adding getSearchParam func --- .../acceptance/param-input-test.js | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/test/javascripts/acceptance/param-input-test.js b/test/javascripts/acceptance/param-input-test.js index f75ccf57..cb58a97e 100644 --- a/test/javascripts/acceptance/param-input-test.js +++ b/test/javascripts/acceptance/param-input-test.js @@ -334,15 +334,18 @@ acceptance("Data Explorer Plugin | Param Input", function (needs) { }); }); + function getSearchParam(param) { + const searchParams = new URLSearchParams(currentURL().split("?")[1]); + return JSON.parse(searchParams.get("params"))[param]; + } + test("puts params for the query into the url", async function (assert) { await visit("/admin/plugins/explorer/queries/-6"); const monthsAgoValue = "2"; await fillIn(".query-params input", monthsAgoValue); await click("form.query-run button"); - const searchParams = new URLSearchParams(currentURL().split("?")[1]); - const monthsAgoParam = JSON.parse(searchParams.get("params")).months_ago; - assert.strictEqual(monthsAgoParam, monthsAgoValue); + assert.strictEqual(getSearchParam("months_ago"), monthsAgoValue); }); test("puts params for the query into the url for group reports", async function (assert) { @@ -351,9 +354,7 @@ acceptance("Data Explorer Plugin | Param Input", function (needs) { await fillIn(".query-params input", monthsAgoValue); await click("form.query-run button"); - const searchParams = new URLSearchParams(currentURL().split("?")[1]); - const monthsAgoParam = JSON.parse(searchParams.get("params")).months_ago; - assert.strictEqual(monthsAgoParam, monthsAgoValue); + assert.strictEqual(getSearchParam("months_ago"), monthsAgoValue); }); test("loads the page if one of the parameter is null", async function (assert) { @@ -396,14 +397,14 @@ acceptance("Data Explorer Plugin | Param Input", function (needs) { await visit("/admin/plugins/explorer/queries/4"); assert.strictEqual(catChooser.header().value(), null); + await click("form.query-run button"); + assert.strictEqual(getSearchParam("category"), ""); + await catChooser.expand(); await catChooser.selectRowByIndex(0); assert.strictEqual(catChooser.header().label(), selectedCategory.name); await click("form.query-run button"); - - const searchParams = new URLSearchParams(currentURL().split("?")[1]); - const categoryIdParam = JSON.parse(searchParams.get("params")).category; - assert.strictEqual(categoryIdParam, selectedCategory.id); + assert.strictEqual(getSearchParam("category"), selectedCategory.id); }); }); From 40a9e37c97feeb9a0b57a2f50a5cfd68228bf93c Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Wed, 4 Jun 2025 15:13:00 +0200 Subject: [PATCH 7/8] clearly test deselecting category --- .../acceptance/param-input-test.js | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/test/javascripts/acceptance/param-input-test.js b/test/javascripts/acceptance/param-input-test.js index cb58a97e..eb0bfa41 100644 --- a/test/javascripts/acceptance/param-input-test.js +++ b/test/javascripts/acceptance/param-input-test.js @@ -2,6 +2,11 @@ import { click, currentURL, fillIn, visit } from "@ember/test-helpers"; import { test } from "qunit"; import { acceptance } from "discourse/tests/helpers/qunit-helpers"; import selectKit from "discourse/tests/helpers/select-kit-helper"; +import Category from "discourse/models/category"; + +async function runQuery() { + await click("form.query-run button"); +} acceptance("Data Explorer Plugin | Param Input", function (needs) { needs.user(); @@ -343,7 +348,7 @@ acceptance("Data Explorer Plugin | Param Input", function (needs) { await visit("/admin/plugins/explorer/queries/-6"); const monthsAgoValue = "2"; await fillIn(".query-params input", monthsAgoValue); - await click("form.query-run button"); + await runQuery(); assert.strictEqual(getSearchParam("months_ago"), monthsAgoValue); }); @@ -352,7 +357,7 @@ acceptance("Data Explorer Plugin | Param Input", function (needs) { await visit("/g/discourse/reports/-8"); const monthsAgoValue = "2"; await fillIn(".query-params input", monthsAgoValue); - await click("form.query-run button"); + await runQuery(); assert.strictEqual(getSearchParam("months_ago"), monthsAgoValue); }); @@ -373,7 +378,7 @@ acceptance("Data Explorer Plugin | Param Input", function (needs) { await visit("/g/discourse/reports/-8"); const monthsAgoValue = "2"; await fillIn(".query-params input", monthsAgoValue); - await click("form.query-run button"); + await runQuery(); assert.dom(".query-params input").hasValue(monthsAgoValue); }); @@ -390,21 +395,30 @@ acceptance("Data Explorer Plugin | Param Input", function (needs) { assert.dom(".query-params input").exists(); }); - test("nullable category_id param: puts params for the query into the url", async function (assert) { - const selectedCategory = { id: "6", name: "support" }; + test("nullable category_id param", async function (assert) { + await visit("/admin/plugins/explorer/queries/4"); const catChooser = selectKit(".category-chooser"); - await visit("/admin/plugins/explorer/queries/4"); assert.strictEqual(catChooser.header().value(), null); - await click("form.query-run button"); + await runQuery(); + assert.strictEqual(getSearchParam("category"), ""); + const category = Category.findById(6); + await catChooser.expand(); + await catChooser.selectRowByValue(category.id); + + assert.strictEqual(catChooser.header().label(), category.name); + + await runQuery(); + + assert.strictEqual(getSearchParam("category"), category.id.toString(), "it updates the URL with the selected category id"); + await catChooser.expand(); await catChooser.selectRowByIndex(0); - assert.strictEqual(catChooser.header().label(), selectedCategory.name); + await runQuery(); - await click("form.query-run button"); - assert.strictEqual(getSearchParam("category"), selectedCategory.id); + assert.strictEqual(getSearchParam("category"), undefined, "it removes the category id from the URL when selecting the first row (null value)"); }); }); From ae0e9560eaf4f4ad91936b7304a4f587509ce667 Mon Sep 17 00:00:00 2001 From: Yuriy Kurant Date: Wed, 4 Jun 2025 21:24:25 +0800 Subject: [PATCH 8/8] DEV: lint fix: order imports --- test/javascripts/acceptance/param-input-test.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/test/javascripts/acceptance/param-input-test.js b/test/javascripts/acceptance/param-input-test.js index eb0bfa41..fd066555 100644 --- a/test/javascripts/acceptance/param-input-test.js +++ b/test/javascripts/acceptance/param-input-test.js @@ -1,8 +1,8 @@ import { click, currentURL, fillIn, visit } from "@ember/test-helpers"; import { test } from "qunit"; +import Category from "discourse/models/category"; import { acceptance } from "discourse/tests/helpers/qunit-helpers"; import selectKit from "discourse/tests/helpers/select-kit-helper"; -import Category from "discourse/models/category"; async function runQuery() { await click("form.query-run button"); @@ -413,12 +413,20 @@ acceptance("Data Explorer Plugin | Param Input", function (needs) { await runQuery(); - assert.strictEqual(getSearchParam("category"), category.id.toString(), "it updates the URL with the selected category id"); + assert.strictEqual( + getSearchParam("category"), + category.id.toString(), + "it updates the URL with the selected category id" + ); await catChooser.expand(); await catChooser.selectRowByIndex(0); await runQuery(); - assert.strictEqual(getSearchParam("category"), undefined, "it removes the category id from the URL when selecting the first row (null value)"); + assert.strictEqual( + getSearchParam("category"), + undefined, + "it removes the category id from the URL when selecting the first row (null value)" + ); }); });