mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-06-18 22:48:32 +08:00
This node allows to display a modal to a specific user and react to the answer of the user. It requires the user to be actually on the discourse site. <img width="2089" height="876" alt="Screenshot 2026-06-17 at 11 31 28" src="https://github.com/user-attachments/assets/abc40762-eb8e-445e-80b6-1a24bc3c54ea" /> <img width="281" height="237" alt="Screenshot 2026-06-17 at 11 31 21" src="https://github.com/user-attachments/assets/481a9cfa-9d6b-40a9-a593-458a99d9f50a" />
112 lines
3.4 KiB
JavaScript
Vendored
112 lines
3.4 KiB
JavaScript
Vendored
import { click, settled, visit } from "@ember/test-helpers";
|
|
import { test } from "qunit";
|
|
import {
|
|
acceptance,
|
|
loggedInUser,
|
|
publishToMessageBus,
|
|
} from "discourse/tests/helpers/qunit-helpers";
|
|
|
|
acceptance("Discourse Workflows | User modal", function (needs) {
|
|
// Present only when a published workflow uses a modal node; gates the
|
|
// subscription and provides the channel's starting message-bus id.
|
|
needs.user({ discourse_workflows_user_modal_last_id: 0 });
|
|
|
|
let lastRequestBody = null;
|
|
|
|
needs.pretender((server, helper) => {
|
|
server.post("/discourse-workflows/modal-responses", (request) => {
|
|
lastRequestBody = request.requestBody;
|
|
return helper.response({});
|
|
});
|
|
});
|
|
|
|
needs.hooks.beforeEach(() => (lastRequestBody = null));
|
|
|
|
function channel() {
|
|
return `/discourse-workflows/user-modal/${loggedInUser().id}`;
|
|
}
|
|
|
|
const payload = {
|
|
type: "show_modal",
|
|
title: "Approve topic?",
|
|
body: "Please choose an option",
|
|
buttons: [
|
|
{
|
|
label: "Approve",
|
|
value: "approve",
|
|
style: "primary",
|
|
action_id: "1:approve:sig-approve",
|
|
},
|
|
{
|
|
label: "Reject",
|
|
value: "reject",
|
|
style: "danger",
|
|
action_id: "1:reject:sig-reject",
|
|
},
|
|
],
|
|
};
|
|
|
|
test("opens a modal with the configured title, body, and buttons", async function (assert) {
|
|
await visit("/");
|
|
await publishToMessageBus(channel(), payload);
|
|
await settled();
|
|
|
|
assert.dom(".workflows-user-modal").exists("the modal opens");
|
|
assert.dom(".d-modal__title-text").hasText("Approve topic?");
|
|
assert
|
|
.dom(".workflows-user-modal__body")
|
|
.hasText("Please choose an option");
|
|
assert
|
|
.dom(".d-modal__footer .btn")
|
|
.exists({ count: 2 }, "renders one button per configured option");
|
|
assert.dom(".d-modal__footer .btn-primary").hasText("Approve");
|
|
assert.dom(".d-modal__footer .btn-danger").hasText("Reject");
|
|
});
|
|
|
|
test("posts the chosen button's action id and closes the modal", async function (assert) {
|
|
await visit("/");
|
|
await publishToMessageBus(channel(), payload);
|
|
await settled();
|
|
|
|
await click(".d-modal__footer .btn-primary");
|
|
|
|
assert.strictEqual(
|
|
new URLSearchParams(lastRequestBody).get("action_id"),
|
|
"1:approve:sig-approve",
|
|
"submits the action id of the clicked button"
|
|
);
|
|
assert.dom(".workflows-user-modal").doesNotExist("the modal closes");
|
|
});
|
|
|
|
test("ignores message bus payloads of other types", async function (assert) {
|
|
await visit("/");
|
|
await publishToMessageBus(channel(), { type: "something_else" });
|
|
await settled();
|
|
|
|
assert.dom(".workflows-user-modal").doesNotExist("no modal is opened");
|
|
});
|
|
});
|
|
|
|
acceptance(
|
|
"Discourse Workflows | User modal (feature unused)",
|
|
function (needs) {
|
|
// No `discourse_workflows_user_modal_last_id` on the user: no published
|
|
// workflow uses a modal node, so the initializer must not subscribe.
|
|
needs.user();
|
|
|
|
test("does not subscribe when no workflow uses a modal node", async function (assert) {
|
|
await visit("/");
|
|
await publishToMessageBus(
|
|
`/discourse-workflows/user-modal/${loggedInUser().id}`,
|
|
{
|
|
type: "show_modal",
|
|
title: "Should not appear",
|
|
buttons: [],
|
|
}
|
|
);
|
|
await settled();
|
|
|
|
assert.dom(".workflows-user-modal").doesNotExist("no modal is opened");
|
|
});
|
|
}
|
|
);
|