UX: category-id-input: allows no-category selection (#377)

The `category_id` parameter now includes the *(no category)* option, which allows clearing a previously selected category.

The *(no category)* option is selected by default.

---------

Co-authored-by: Joffrey JAFFEUX <[email protected]>
This commit is contained in:
Yuriy Kurant
2025-06-04 21:40:29 +08:00
committed by GitHub
co-authored by Joffrey JAFFEUX
parent a0a7f8d999
commit 5a2bfcebff
3 changed files with 90 additions and 155 deletions
@@ -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 {
<CategoryChooser
@value={{this.data.value}}
@onChange={{@field.set}}
@options={{hash
allowUncategorized=null
autoInsertNoneItem=true
none=true
}}
name={{@info.identifier}}
/>
</@field.Custom>
@@ -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", () => {
+83 -83
View File
@@ -1,6 +1,12 @@
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";
async function runQuery() {
await click("form.query-run button");
}
acceptance("Data Explorer Plugin | Param Input", function (needs) {
needs.user();
@@ -8,82 +14,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", () => {
@@ -373,28 +308,58 @@ 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({});
});
});
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");
await runQuery();
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) {
await visit("/g/discourse/reports/-8");
const monthsAgoValue = "2";
await fillIn(".query-params input", monthsAgoValue);
await click("form.query-run button");
await runQuery();
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) {
@@ -413,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);
});
@@ -421,12 +386,47 @@ 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();
});
test("nullable category_id param", async function (assert) {
await visit("/admin/plugins/explorer/queries/4");
const catChooser = selectKit(".category-chooser");
assert.strictEqual(catChooser.header().value(), null);
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);
await runQuery();
assert.strictEqual(
getSearchParam("category"),
undefined,
"it removes the category id from the URL when selecting the first row (null value)"
);
});
});