Revert to widget instead of glimmer component
This commit is contained in:
parent
29416b8406
commit
75cd3060a8
|
@ -19,7 +19,7 @@ export default class SolvedAcceptAnswerButton extends Component {
|
||||||
|
|
||||||
@action
|
@action
|
||||||
acceptAnswer() {
|
acceptAnswer() {
|
||||||
acceptAnswer(this.args.post, this.appEvents);
|
acceptAnswer(this.args.post, this.appEvents, this.currentUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -34,9 +34,9 @@ export default class SolvedAcceptAnswerButton extends Component {
|
||||||
</template>
|
</template>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function acceptAnswer(post, appEvents) {
|
export function acceptAnswer(post, appEvents, acceptingUser) {
|
||||||
// TODO (glimmer-post-menu): Remove this exported function and move the code into the button action after the widget code is removed
|
// TODO (glimmer-post-menu): Remove this exported function and move the code into the button action after the widget code is removed
|
||||||
acceptPost(post);
|
acceptPost(post, acceptingUser);
|
||||||
|
|
||||||
appEvents.trigger("discourse-solved:solution-toggled", post);
|
appEvents.trigger("discourse-solved:solution-toggled", post);
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ export function acceptAnswer(post, appEvents) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function acceptPost(post) {
|
function acceptPost(post, acceptingUser) {
|
||||||
const topic = post.topic;
|
const topic = post.topic;
|
||||||
|
|
||||||
clearAccepted(topic);
|
clearAccepted(topic);
|
||||||
|
@ -62,6 +62,8 @@ function acceptPost(post) {
|
||||||
name: post.name,
|
name: post.name,
|
||||||
post_number: post.post_number,
|
post_number: post.post_number,
|
||||||
excerpt: post.cooked,
|
excerpt: post.cooked,
|
||||||
|
accepter_username: acceptingUser.username,
|
||||||
|
accepter_name: acceptingUser.name,
|
||||||
});
|
});
|
||||||
|
|
||||||
ajax("/solution/accept", {
|
ajax("/solution/accept", {
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
import Component from "@glimmer/component";
|
|
||||||
import { service } from "@ember/service";
|
|
||||||
import { htmlSafe } from "@ember/template";
|
|
||||||
import { not } from "truth-helpers";
|
|
||||||
import concatClass from "discourse/helpers/concat-class";
|
|
||||||
import { iconHTML } from "discourse/lib/icon-library";
|
|
||||||
import { formatUsername } from "discourse/lib/utilities";
|
|
||||||
import User from "discourse/models/user";
|
|
||||||
import { i18n } from "discourse-i18n";
|
|
||||||
|
|
||||||
export default class SolvedPost extends Component {
|
|
||||||
static shouldRender(args) {
|
|
||||||
return args.post?.post_number === 1 && args.post?.topic?.accepted_answer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@service siteSettings;
|
|
||||||
|
|
||||||
get answerPostPath() {
|
|
||||||
return `${this.args.outletArgs.post.topic.url}/${this.answerPostNumber}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
get acceptedAnswer() {
|
|
||||||
return this.args.outletArgs.post.topic.accepted_answer;
|
|
||||||
}
|
|
||||||
|
|
||||||
get answerPostNumber() {
|
|
||||||
return this.acceptedAnswer?.post_number;
|
|
||||||
}
|
|
||||||
|
|
||||||
get topicId() {
|
|
||||||
return this.args.outletArgs.post.topic.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
get hasExcerpt() {
|
|
||||||
return !!this.solvedExcerpt;
|
|
||||||
}
|
|
||||||
|
|
||||||
get solvedExcerpt() {
|
|
||||||
return this.acceptedAnswer?.excerpt;
|
|
||||||
}
|
|
||||||
|
|
||||||
get username() {
|
|
||||||
return this.acceptedAnswer?.username;
|
|
||||||
}
|
|
||||||
|
|
||||||
get displayedUser() {
|
|
||||||
const { name, username } = this.acceptedAnswer || {};
|
|
||||||
return this.siteSettings.display_name_on_posts && name
|
|
||||||
? name
|
|
||||||
: formatUsername(username);
|
|
||||||
}
|
|
||||||
|
|
||||||
get title() {
|
|
||||||
return i18n("solved.accepted_html", {
|
|
||||||
icon: iconHTML("square-check", { class: "accepted" }),
|
|
||||||
username_lower: this.username?.toLowerCase(),
|
|
||||||
username: this.displayedUser,
|
|
||||||
post_path: this.answerPostPath,
|
|
||||||
post_number: this.answerPostNumber,
|
|
||||||
user_path: User.create({ username: this.username }).path,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get accepter() {
|
|
||||||
const accepterUsername = this.acceptedAnswer?.accepter_username;
|
|
||||||
const accepterName = this.acceptedAnswer?.accepter_name;
|
|
||||||
const formattedUsername = this.siteSettings.display_name_on_posts && accepterName
|
|
||||||
? accepterName
|
|
||||||
: formatUsername(accepterUsername);
|
|
||||||
return i18n("solved.marked_solved_by", {
|
|
||||||
username: formattedUsername,
|
|
||||||
username_lower: accepterUsername.toLowerCase()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="cooked">
|
|
||||||
<aside class="quote accepted-answer"
|
|
||||||
data-post={{this.answerPostNumber}}
|
|
||||||
data-topic={{this.topicId}}>
|
|
||||||
<div
|
|
||||||
class={{concatClass "title" (unless this.hasExcerpt "title-only") }}
|
|
||||||
>
|
|
||||||
<div class="accepted-answer--solver">
|
|
||||||
{{htmlSafe this.title}}
|
|
||||||
</div>
|
|
||||||
<div class="accepted-answer--accepter">
|
|
||||||
{{htmlSafe this.accepter}}
|
|
||||||
</div>
|
|
||||||
<div class="quote-controls"></div>
|
|
||||||
</div>
|
|
||||||
{{#if this.hasExcerpt}}
|
|
||||||
<blockquote>
|
|
||||||
{{this.solvedExcerpt}}
|
|
||||||
</blockquote>
|
|
||||||
{{/if}}
|
|
||||||
</aside>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
}
|
|
|
@ -1,12 +1,16 @@
|
||||||
|
import { computed } from "@ember/object";
|
||||||
import discourseComputed from "discourse/lib/decorators";
|
import discourseComputed from "discourse/lib/decorators";
|
||||||
import { withSilencedDeprecations } from "discourse/lib/deprecated";
|
import { withSilencedDeprecations } from "discourse/lib/deprecated";
|
||||||
import { iconNode } from "discourse/lib/icon-library";
|
import { iconHTML, iconNode } from "discourse/lib/icon-library";
|
||||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||||
|
import { formatUsername } from "discourse/lib/utilities";
|
||||||
|
import Topic from "discourse/models/topic";
|
||||||
|
import User from "discourse/models/user";
|
||||||
|
import PostCooked from "discourse/widgets/post-cooked";
|
||||||
import { i18n } from "discourse-i18n";
|
import { i18n } from "discourse-i18n";
|
||||||
import SolvedAcceptAnswerButton, {
|
import SolvedAcceptAnswerButton, {
|
||||||
acceptAnswer,
|
acceptAnswer,
|
||||||
} from "../components/solved-accept-answer-button";
|
} from "../components/solved-accept-answer-button";
|
||||||
import SolvedPost from "../components/solved-post";
|
|
||||||
import SolvedUnacceptAnswerButton, {
|
import SolvedUnacceptAnswerButton, {
|
||||||
unacceptAnswer,
|
unacceptAnswer,
|
||||||
} from "../components/solved-unaccept-answer-button";
|
} from "../components/solved-unaccept-answer-button";
|
||||||
|
@ -25,10 +29,39 @@ function initializeWithApi(api) {
|
||||||
api.addDiscoveryQueryParam("solved", { replace: true, refreshModel: true });
|
api.addDiscoveryQueryParam("solved", { replace: true, refreshModel: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
api.renderBeforeWrapperOutlet("post-menu", SolvedPost);
|
api.decorateWidget("post-contents:after-cooked", (dec) => {
|
||||||
|
if (dec.attrs.post_number === 1) {
|
||||||
|
const postModel = dec.getModel();
|
||||||
|
if (postModel) {
|
||||||
|
const topic = postModel.topic;
|
||||||
|
if (topic.accepted_answer) {
|
||||||
|
const hasExcerpt = !!topic.accepted_answer.excerpt;
|
||||||
|
const excerpt = hasExcerpt
|
||||||
|
? ` <blockquote> ${topic.accepted_answer.excerpt} </blockquote> `
|
||||||
|
: "";
|
||||||
|
const solvedQuote = `
|
||||||
|
<aside class='quote accepted-answer' data-post="${topic.get("accepted_answer").post_number}" data-topic="${topic.id}">
|
||||||
|
<div class='title ${hasExcerpt ? "" : "title-only"}'>
|
||||||
|
<div class="accepted-answer--solver">
|
||||||
|
${topic.solvedByHtml}
|
||||||
|
<\/div>
|
||||||
|
<div class="accepted-answer--accepter">
|
||||||
|
${topic.accepterHtml}
|
||||||
|
<\/div>
|
||||||
|
<div class="quote-controls"><\/div>
|
||||||
|
</div>
|
||||||
|
${excerpt}
|
||||||
|
</aside>`;
|
||||||
|
|
||||||
|
const cooked = new PostCooked({ cooked: solvedQuote }, dec);
|
||||||
|
return dec.rawHtml(cooked.init());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
api.attachWidgetAction("post", "acceptAnswer", function () {
|
api.attachWidgetAction("post", "acceptAnswer", function () {
|
||||||
acceptAnswer(this.model, this.appEvents);
|
acceptAnswer(this.model, this.appEvents, this.currentUser);
|
||||||
});
|
});
|
||||||
|
|
||||||
api.attachWidgetAction("post", "unacceptAnswer", function () {
|
api.attachWidgetAction("post", "unacceptAnswer", function () {
|
||||||
|
@ -132,6 +165,45 @@ function customizeWidgetPostMenu(api) {
|
||||||
export default {
|
export default {
|
||||||
name: "extend-for-solved-button",
|
name: "extend-for-solved-button",
|
||||||
initialize() {
|
initialize() {
|
||||||
|
Topic.reopen({
|
||||||
|
// keeping this here cause there is complex localization
|
||||||
|
solvedByHtml: computed("accepted_answer", "id", function () {
|
||||||
|
const username = this.get("accepted_answer.username");
|
||||||
|
const name = this.get("accepted_answer.name");
|
||||||
|
const postNumber = this.get("accepted_answer.post_number");
|
||||||
|
|
||||||
|
if (!username || !postNumber) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const displayedUser =
|
||||||
|
this.siteSettings.display_name_on_posts && name
|
||||||
|
? name
|
||||||
|
: formatUsername(username);
|
||||||
|
|
||||||
|
return i18n("solved.accepted_html", {
|
||||||
|
icon: iconHTML("square-check", { class: "accepted" }),
|
||||||
|
username_lower: username.toLowerCase(),
|
||||||
|
username: displayedUser,
|
||||||
|
post_path: `${this.url}/${postNumber}`,
|
||||||
|
post_number: postNumber,
|
||||||
|
user_path: User.create({ username }).path,
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
accepterHtml: computed("accepted_answer", function () {
|
||||||
|
const username = this.get("accepted_answer.accepter_username");
|
||||||
|
const name = this.get("accepted_answer.accepter_name");
|
||||||
|
const formattedUsername =
|
||||||
|
this.siteSettings.display_name_on_posts && name
|
||||||
|
? name
|
||||||
|
: formatUsername(username);
|
||||||
|
return i18n("solved.marked_solved_by", {
|
||||||
|
username: formattedUsername,
|
||||||
|
username_lower: username.toLowerCase(),
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
withPluginApi("2.0.0", (api) => {
|
withPluginApi("2.0.0", (api) => {
|
||||||
withSilencedDeprecations("discourse.hbr-topic-list-overrides", () => {
|
withSilencedDeprecations("discourse.hbr-topic-list-overrides", () => {
|
||||||
let topicStatusIcons;
|
let topicStatusIcons;
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
describe "About page", type: :system do
|
||||||
|
fab!(:admin)
|
||||||
|
fab!(:solver) { Fabricate(:user) }
|
||||||
|
fab!(:accepter) { Fabricate(:user) }
|
||||||
|
fab!(:topic) { Fabricate(:post, user: admin).topic }
|
||||||
|
fab!(:post1) { Fabricate(:post, topic:, user: solver, cooked: "The answer is 42") }
|
||||||
|
let(:topic_page) { PageObjects::Pages::Topic.new }
|
||||||
|
|
||||||
|
before do
|
||||||
|
SiteSetting.solved_enabled = true
|
||||||
|
SiteSetting.allow_solved_on_all_topics = true
|
||||||
|
SiteSetting.accept_all_solutions_allowed_groups = Group::AUTO_GROUPS[:everyone]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "accepts post as solution and shows in OP" do
|
||||||
|
sign_in(accepter)
|
||||||
|
|
||||||
|
topic_page.visit_topic(topic, post_number: 2)
|
||||||
|
|
||||||
|
expect(topic_page).to have_css(".post-action-menu__solved-unaccepted")
|
||||||
|
|
||||||
|
find(".post-action-menu__solved-unaccepted").click
|
||||||
|
|
||||||
|
expect(topic_page).to have_css(".post-action-menu__solved-accepted")
|
||||||
|
expect(topic_page.find(".title .accepted-answer--solver")).to have_content(
|
||||||
|
"Solved by #{solver.username}",
|
||||||
|
)
|
||||||
|
expect(topic_page.find(".title .accepted-answer--accepter")).to have_content(
|
||||||
|
"Marked as solved by #{accepter.username}",
|
||||||
|
)
|
||||||
|
expect(topic_page.find("blockquote")).to have_content("The answer is 42")
|
||||||
|
end
|
||||||
|
end
|
|
@ -199,6 +199,12 @@ export const postStreamWithAcceptedAnswerExcerpt = (excerpt) => {
|
||||||
featured_link: null,
|
featured_link: null,
|
||||||
topic_timer: null,
|
topic_timer: null,
|
||||||
message_bus_last_id: 0,
|
message_bus_last_id: 0,
|
||||||
accepted_answer: { post_number: 2, username: "kzh", excerpt },
|
accepted_answer: {
|
||||||
|
post_number: 2,
|
||||||
|
username: "kzh",
|
||||||
|
excerpt,
|
||||||
|
accepter_username: "tomtom",
|
||||||
|
accepter_name: "Tomtom",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,89 +0,0 @@
|
||||||
import { render } from "@ember/test-helpers";
|
|
||||||
import { hbs } from "ember-cli-htmlbars";
|
|
||||||
import { module, test } from "qunit";
|
|
||||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
|
||||||
|
|
||||||
module("Integration | Component | solved-post", function (hooks) {
|
|
||||||
setupRenderingTest(hooks);
|
|
||||||
|
|
||||||
test("renders solved post information", async function (assert) {
|
|
||||||
this.siteSettings = {
|
|
||||||
display_name_on_posts: true
|
|
||||||
};
|
|
||||||
|
|
||||||
const post = {
|
|
||||||
post_number: 1,
|
|
||||||
topic: {
|
|
||||||
id: 123,
|
|
||||||
url: "/t/topic/123",
|
|
||||||
accepted_answer: {
|
|
||||||
username: "solver",
|
|
||||||
name: "Solver Person",
|
|
||||||
post_number: 7,
|
|
||||||
excerpt: "This is the solution",
|
|
||||||
accepter_username: "accepter",
|
|
||||||
accepter_name: "Accepter Person"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.set("outletArgs", { post });
|
|
||||||
|
|
||||||
await render(hbs`<SolvedPost @outletArgs={{this.outletArgs}} />`);
|
|
||||||
|
|
||||||
assert.dom(".accepted-answer").exists("shows accepted answer section");
|
|
||||||
assert.dom(".accepted-answer[data-post='7']").exists("has correct post number");
|
|
||||||
assert.dom(".accepted-answer[data-topic='123']").exists("has correct topic id");
|
|
||||||
assert.dom(".title .accepted-answer--solver").includesText("Solved by solver in post #7", "shows solver name");
|
|
||||||
assert.dom(".title .accepted-answer--accepter").includesText("Marked as solved by accepter", "shows accepter name");
|
|
||||||
assert.dom("blockquote").hasText("This is the solution", "shows excerpt");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("handles missing excerpt", async function (assert) {
|
|
||||||
const post = {
|
|
||||||
post_number: 1,
|
|
||||||
topic: {
|
|
||||||
id: 123,
|
|
||||||
accepted_answer: {
|
|
||||||
username: "solver",
|
|
||||||
post_number: 7,
|
|
||||||
accepter_username: "accepter"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.set("outletArgs", { post });
|
|
||||||
|
|
||||||
await render(hbs`<SolvedPost @outletArgs={{this.outletArgs}} />`);
|
|
||||||
|
|
||||||
assert.dom(".title").hasClass("title-only", "adds title-only class when no excerpt");
|
|
||||||
assert.dom("blockquote").doesNotExist("doesn't show blockquote without excerpt");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("uses username when display_name_on_posts is false", async function (assert) {
|
|
||||||
this.siteSettings = {
|
|
||||||
display_name_on_posts: false
|
|
||||||
};
|
|
||||||
|
|
||||||
const post = {
|
|
||||||
post_number: 1,
|
|
||||||
topic: {
|
|
||||||
id: 123,
|
|
||||||
accepted_answer: {
|
|
||||||
username: "solver",
|
|
||||||
name: "Solver Person",
|
|
||||||
post_number: 7,
|
|
||||||
accepter_username: "accepter",
|
|
||||||
accepter_name: "Accepter Person"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.set("outletArgs", { post });
|
|
||||||
|
|
||||||
await render(hbs`<SolvedPost @outletArgs={{this.outletArgs}} />`);
|
|
||||||
|
|
||||||
assert.dom(".title .accepted-answer--solver").includesText("solver", "shows username");
|
|
||||||
assert.dom(".title .accepted-answer--accepter").includesText("accepter", "shows accepter username");
|
|
||||||
});
|
|
||||||
});
|
|
Loading…
Reference in New Issue