DEV: Added compatibility with the Glimmer Post Menu (#313)
This commit is contained in:
parent
c2f549fd4f
commit
28ae24ffb8
|
@ -0,0 +1,85 @@
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import DButton from "discourse/components/d-button";
|
||||||
|
import { ajax } from "discourse/lib/ajax";
|
||||||
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
|
||||||
|
export default class SolvedAcceptAnswerButton extends Component {
|
||||||
|
static hidden(args) {
|
||||||
|
return args.post.topic_accepted_answer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@service appEvents;
|
||||||
|
@service currentUser;
|
||||||
|
|
||||||
|
get showLabel() {
|
||||||
|
return this.currentUser?.id === this.args.post.topicCreatedById;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
acceptAnswer() {
|
||||||
|
acceptAnswer(this.args.post, this.appEvents);
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<DButton
|
||||||
|
class="post-action-menu__solved-unaccepted unaccepted"
|
||||||
|
...attributes
|
||||||
|
@action={{this.acceptAnswer}}
|
||||||
|
@icon="far-check-square"
|
||||||
|
@label={{if this.showLabel "solved.solution"}}
|
||||||
|
@title="solved.accept_answer"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function acceptAnswer(post, appEvents) {
|
||||||
|
// TODO (glimmer-post-menu): Remove this exported function and move the code into the button action after the widget code is removed
|
||||||
|
acceptPost(post);
|
||||||
|
|
||||||
|
appEvents.trigger("discourse-solved:solution-toggled", post);
|
||||||
|
|
||||||
|
post.get("topic.postStream.posts").forEach((p) => {
|
||||||
|
p.set("topic_accepted_answer", true);
|
||||||
|
appEvents.trigger("post-stream:refresh", { id: p.id });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function acceptPost(post) {
|
||||||
|
const topic = post.topic;
|
||||||
|
|
||||||
|
clearAccepted(topic);
|
||||||
|
|
||||||
|
post.setProperties({
|
||||||
|
can_unaccept_answer: true,
|
||||||
|
can_accept_answer: false,
|
||||||
|
accepted_answer: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
topic.set("accepted_answer", {
|
||||||
|
username: post.username,
|
||||||
|
name: post.name,
|
||||||
|
post_number: post.post_number,
|
||||||
|
excerpt: post.cooked,
|
||||||
|
});
|
||||||
|
|
||||||
|
ajax("/solution/accept", {
|
||||||
|
type: "POST",
|
||||||
|
data: { id: post.id },
|
||||||
|
}).catch(popupAjaxError);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearAccepted(topic) {
|
||||||
|
const posts = topic.get("postStream.posts");
|
||||||
|
posts.forEach((post) => {
|
||||||
|
if (post.get("post_number") > 1) {
|
||||||
|
post.setProperties({
|
||||||
|
accepted_answer: false,
|
||||||
|
can_accept_answer: true,
|
||||||
|
can_unaccept_answer: false,
|
||||||
|
topic_accepted_answer: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import DButton from "discourse/components/d-button";
|
||||||
|
import { ajax } from "discourse/lib/ajax";
|
||||||
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
import dIcon from "discourse-common/helpers/d-icon";
|
||||||
|
import i18n from "discourse-common/helpers/i18n";
|
||||||
|
|
||||||
|
export default class SolvedUnacceptAnswerButton extends Component {
|
||||||
|
@service appEvents;
|
||||||
|
|
||||||
|
@action
|
||||||
|
unacceptAnswer() {
|
||||||
|
unacceptAnswer(this.args.post, this.appEvents);
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<span class="extra-buttons">
|
||||||
|
{{#if @post.can_unaccept_answer}}
|
||||||
|
<DButton
|
||||||
|
class="post-action-menu__solved-accepted accepted fade-out"
|
||||||
|
...attributes
|
||||||
|
@action={{this.unacceptAnswer}}
|
||||||
|
@icon="check-square"
|
||||||
|
@label="solved.solution"
|
||||||
|
@title="solved.unaccept_answer"
|
||||||
|
/>
|
||||||
|
{{else}}
|
||||||
|
<span
|
||||||
|
class="accepted-text"
|
||||||
|
title={{i18n "solved.accepted_description"}}
|
||||||
|
>
|
||||||
|
<span>{{dIcon "check"}}</span>
|
||||||
|
<span class="accepted-label">
|
||||||
|
{{i18n "solved.solution"}}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
}
|
||||||
|
|
||||||
|
export function unacceptAnswer(post, appEvents) {
|
||||||
|
// TODO (glimmer-post-menu): Remove this exported function and move the code into the button action after the widget code is removed
|
||||||
|
unacceptPost(post);
|
||||||
|
|
||||||
|
appEvents.trigger("discourse-solved:solution-toggled", post);
|
||||||
|
|
||||||
|
post.get("topic.postStream.posts").forEach((p) => {
|
||||||
|
p.set("topic_accepted_answer", false);
|
||||||
|
appEvents.trigger("post-stream:refresh", { id: p.id });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function unacceptPost(post) {
|
||||||
|
if (!post.can_unaccept_answer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const topic = post.topic;
|
||||||
|
|
||||||
|
post.setProperties({
|
||||||
|
can_accept_answer: true,
|
||||||
|
can_unaccept_answer: false,
|
||||||
|
accepted_answer: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
topic.set("accepted_answer", undefined);
|
||||||
|
|
||||||
|
ajax("/solution/unaccept", {
|
||||||
|
type: "POST",
|
||||||
|
data: { id: post.id },
|
||||||
|
}).catch(popupAjaxError);
|
||||||
|
}
|
|
@ -1,75 +1,23 @@
|
||||||
import { computed } from "@ember/object";
|
import { computed } from "@ember/object";
|
||||||
import TopicStatusIcons from "discourse/helpers/topic-status-icons";
|
import TopicStatusIcons from "discourse/helpers/topic-status-icons";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
|
||||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||||
import { formatUsername } from "discourse/lib/utilities";
|
import { formatUsername } from "discourse/lib/utilities";
|
||||||
import Topic from "discourse/models/topic";
|
import Topic from "discourse/models/topic";
|
||||||
import User from "discourse/models/user";
|
import User from "discourse/models/user";
|
||||||
import TopicStatus from "discourse/raw-views/topic-status";
|
import TopicStatus from "discourse/raw-views/topic-status";
|
||||||
import PostCooked from "discourse/widgets/post-cooked";
|
import PostCooked from "discourse/widgets/post-cooked";
|
||||||
|
import { withSilencedDeprecations } from "discourse-common/lib/deprecated";
|
||||||
import { iconHTML, iconNode } from "discourse-common/lib/icon-library";
|
import { iconHTML, iconNode } from "discourse-common/lib/icon-library";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
|
import SolvedAcceptAnswerButton, {
|
||||||
function clearAccepted(topic) {
|
acceptAnswer,
|
||||||
const posts = topic.get("postStream.posts");
|
} from "../components/solved-accept-answer-button";
|
||||||
posts.forEach((post) => {
|
import SolvedUnacceptAnswerButton, {
|
||||||
if (post.get("post_number") > 1) {
|
unacceptAnswer,
|
||||||
post.setProperties({
|
} from "../components/solved-unaccept-answer-button";
|
||||||
accepted_answer: false,
|
|
||||||
can_accept_answer: true,
|
|
||||||
can_unaccept_answer: false,
|
|
||||||
topic_accepted_answer: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function unacceptPost(post) {
|
|
||||||
if (!post.can_unaccept_answer) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const topic = post.topic;
|
|
||||||
|
|
||||||
post.setProperties({
|
|
||||||
can_accept_answer: true,
|
|
||||||
can_unaccept_answer: false,
|
|
||||||
accepted_answer: false,
|
|
||||||
});
|
|
||||||
topic.set("accepted_answer", undefined);
|
|
||||||
|
|
||||||
ajax("/solution/unaccept", {
|
|
||||||
type: "POST",
|
|
||||||
data: { id: post.id },
|
|
||||||
}).catch(popupAjaxError);
|
|
||||||
}
|
|
||||||
|
|
||||||
function acceptPost(post) {
|
|
||||||
const topic = post.topic;
|
|
||||||
|
|
||||||
clearAccepted(topic);
|
|
||||||
|
|
||||||
post.setProperties({
|
|
||||||
can_unaccept_answer: true,
|
|
||||||
can_accept_answer: false,
|
|
||||||
accepted_answer: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
topic.set("accepted_answer", {
|
|
||||||
username: post.username,
|
|
||||||
name: post.name,
|
|
||||||
post_number: post.post_number,
|
|
||||||
excerpt: post.cooked,
|
|
||||||
});
|
|
||||||
|
|
||||||
ajax("/solution/accept", {
|
|
||||||
type: "POST",
|
|
||||||
data: { id: post.id },
|
|
||||||
}).catch(popupAjaxError);
|
|
||||||
}
|
|
||||||
|
|
||||||
function initializeWithApi(api) {
|
function initializeWithApi(api) {
|
||||||
const currentUser = api.getCurrentUser();
|
customizePostMenu(api);
|
||||||
|
|
||||||
TopicStatusIcons.addObject([
|
TopicStatusIcons.addObject([
|
||||||
"has_accepted_answer",
|
"has_accepted_answer",
|
||||||
|
@ -88,6 +36,100 @@ function initializeWithApi(api) {
|
||||||
api.addDiscoveryQueryParam("solved", { replace: true, refreshModel: true });
|
api.addDiscoveryQueryParam("solved", { replace: true, refreshModel: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 withExcerpt = `
|
||||||
|
<aside class='quote accepted-answer' data-post="${
|
||||||
|
topic.get("accepted_answer").post_number
|
||||||
|
}" data-topic="${topic.id}">
|
||||||
|
<div class='title'>
|
||||||
|
${topic.acceptedAnswerHtml} <div class="quote-controls"><\/div>
|
||||||
|
</div>
|
||||||
|
<blockquote>
|
||||||
|
${topic.accepted_answer.excerpt}
|
||||||
|
</blockquote>
|
||||||
|
</aside>`;
|
||||||
|
|
||||||
|
const withoutExcerpt = `
|
||||||
|
<aside class='quote accepted-answer'>
|
||||||
|
<div class='title title-only'>
|
||||||
|
${topic.acceptedAnswerHtml}
|
||||||
|
</div>
|
||||||
|
</aside>`;
|
||||||
|
|
||||||
|
const cooked = new PostCooked(
|
||||||
|
{ cooked: hasExcerpt ? withExcerpt : withoutExcerpt },
|
||||||
|
dec
|
||||||
|
);
|
||||||
|
return dec.rawHtml(cooked.init());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
api.attachWidgetAction("post", "acceptAnswer", function () {
|
||||||
|
acceptAnswer(this.model, this.appEvents);
|
||||||
|
});
|
||||||
|
|
||||||
|
api.attachWidgetAction("post", "unacceptAnswer", function () {
|
||||||
|
unacceptAnswer(this.model, this.appEvents);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function customizePostMenu(api) {
|
||||||
|
const transformerRegistered = api.registerValueTransformer(
|
||||||
|
"post-menu-buttons",
|
||||||
|
({
|
||||||
|
value: dag,
|
||||||
|
context: {
|
||||||
|
post,
|
||||||
|
firstButtonKey,
|
||||||
|
secondLastHiddenButtonKey,
|
||||||
|
lastHiddenButtonKey,
|
||||||
|
},
|
||||||
|
}) => {
|
||||||
|
let solvedButton;
|
||||||
|
|
||||||
|
if (post.can_accept_answer) {
|
||||||
|
solvedButton = SolvedAcceptAnswerButton;
|
||||||
|
} else if (post.accepted_answer) {
|
||||||
|
solvedButton = SolvedUnacceptAnswerButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
solvedButton &&
|
||||||
|
dag.add(
|
||||||
|
"solved",
|
||||||
|
solvedButton,
|
||||||
|
post.topic_accepted_answer && !post.accepted_answer
|
||||||
|
? {
|
||||||
|
before: lastHiddenButtonKey,
|
||||||
|
after: secondLastHiddenButtonKey,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
before: [
|
||||||
|
"assign", // button added by the assign plugin
|
||||||
|
firstButtonKey,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const silencedKey =
|
||||||
|
transformerRegistered && "discourse.post-menu-widget-overrides";
|
||||||
|
|
||||||
|
withSilencedDeprecations(silencedKey, () => customizeWidgetPostMenu(api));
|
||||||
|
}
|
||||||
|
|
||||||
|
function customizeWidgetPostMenu(api) {
|
||||||
|
const currentUser = api.getCurrentUser();
|
||||||
|
|
||||||
api.addPostMenuButton("solved", (attrs) => {
|
api.addPostMenuButton("solved", (attrs) => {
|
||||||
if (attrs.can_accept_answer) {
|
if (attrs.can_accept_answer) {
|
||||||
const isOp = currentUser?.id === attrs.topicCreatedById;
|
const isOp = currentUser?.id === attrs.topicCreatedById;
|
||||||
|
@ -131,67 +173,6 @@ function initializeWithApi(api) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
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 withExcerpt = `
|
|
||||||
<aside class='quote accepted-answer' data-post="${
|
|
||||||
topic.get("accepted_answer").post_number
|
|
||||||
}" data-topic="${topic.id}">
|
|
||||||
<div class='title'>
|
|
||||||
${topic.acceptedAnswerHtml} <div class="quote-controls"><\/div>
|
|
||||||
</div>
|
|
||||||
<blockquote>
|
|
||||||
${topic.accepted_answer.excerpt}
|
|
||||||
</blockquote>
|
|
||||||
</aside>`;
|
|
||||||
|
|
||||||
const withoutExcerpt = `
|
|
||||||
<aside class='quote accepted-answer'>
|
|
||||||
<div class='title title-only'>
|
|
||||||
${topic.acceptedAnswerHtml}
|
|
||||||
</div>
|
|
||||||
</aside>`;
|
|
||||||
|
|
||||||
const cooked = new PostCooked(
|
|
||||||
{ cooked: hasExcerpt ? withExcerpt : withoutExcerpt },
|
|
||||||
dec
|
|
||||||
);
|
|
||||||
return dec.rawHtml(cooked.init());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
api.attachWidgetAction("post", "acceptAnswer", function () {
|
|
||||||
const post = this.model;
|
|
||||||
acceptPost(post);
|
|
||||||
|
|
||||||
this.appEvents.trigger("discourse-solved:solution-toggled", post);
|
|
||||||
|
|
||||||
post.get("topic.postStream.posts").forEach((p) => {
|
|
||||||
p.set("topic_accepted_answer", true);
|
|
||||||
this.appEvents.trigger("post-stream:refresh", { id: p.id });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
api.attachWidgetAction("post", "unacceptAnswer", function () {
|
|
||||||
const post = this.model;
|
|
||||||
unacceptPost(post);
|
|
||||||
|
|
||||||
this.appEvents.trigger("discourse-solved:solution-toggled", post);
|
|
||||||
|
|
||||||
post.get("topic.postStream.posts").forEach((p) => {
|
|
||||||
p.set("topic_accepted_answer", false);
|
|
||||||
this.appEvents.trigger("post-stream:refresh", { id: p.id });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -252,7 +233,7 @@ export default {
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
withPluginApi("0.1", initializeWithApi);
|
withPluginApi("1.34.0", initializeWithApi);
|
||||||
|
|
||||||
withPluginApi("0.8.10", (api) => {
|
withPluginApi("0.8.10", (api) => {
|
||||||
api.replaceIcon(
|
api.replaceIcon(
|
||||||
|
|
|
@ -14,15 +14,6 @@ $solved-color: green;
|
||||||
color: $solved-color;
|
color: $solved-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-controls {
|
|
||||||
.accepted,
|
|
||||||
.unaccepted {
|
|
||||||
.d-button-label {
|
|
||||||
margin-left: 7px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.post-controls .extra-buttons {
|
.post-controls .extra-buttons {
|
||||||
// anon text
|
// anon text
|
||||||
.accepted-text {
|
.accepted-text {
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
import { click, visit } from "@ember/test-helpers";
|
||||||
|
import { test } from "qunit";
|
||||||
|
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||||
|
import I18n from "I18n";
|
||||||
|
import { postStreamWithAcceptedAnswerExcerpt } from "../helpers/discourse-solved-helpers";
|
||||||
|
|
||||||
|
acceptance(
|
||||||
|
"Discourse Solved | Post Menu | Accept and Unaccept",
|
||||||
|
function (needs) {
|
||||||
|
needs.user({
|
||||||
|
admin: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
needs.settings({
|
||||||
|
glimmer_post_menu_mode: "enabled",
|
||||||
|
solved_enabled: true,
|
||||||
|
allow_solved_on_all_topics: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
needs.pretender((server, helper) => {
|
||||||
|
server.post("/solution/accept", () => helper.response({ success: "OK" }));
|
||||||
|
server.post("/solution/unaccept", () =>
|
||||||
|
helper.response({ success: "OK" })
|
||||||
|
);
|
||||||
|
|
||||||
|
server.get("/t/12.json", () => {
|
||||||
|
return helper.response(postStreamWithAcceptedAnswerExcerpt(null));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("accepting and unaccepting a post works", async function (assert) {
|
||||||
|
await visit("/t/without-excerpt/12");
|
||||||
|
|
||||||
|
assert
|
||||||
|
.dom("#post_2 .post-action-menu__solved-accepted")
|
||||||
|
.exists("Unaccept button is visible")
|
||||||
|
.hasText(I18n.t("solved.solution"), "Unaccept button has correct text");
|
||||||
|
|
||||||
|
await click("#post_2 .post-action-menu__solved-accepted");
|
||||||
|
|
||||||
|
assert
|
||||||
|
.dom("#post_2 .post-action-menu__solved-unaccepted")
|
||||||
|
.exists("Accept button is visible");
|
||||||
|
|
||||||
|
await click("#post_2 .post-action-menu__solved-unaccepted");
|
||||||
|
|
||||||
|
assert
|
||||||
|
.dom("#post_2 .post-action-menu__solved-accepted")
|
||||||
|
.exists("Unccept button is visible again");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
|
@ -3,221 +3,12 @@ import { test } from "qunit";
|
||||||
import { fixturesByUrl } from "discourse/tests/helpers/create-pretender";
|
import { fixturesByUrl } from "discourse/tests/helpers/create-pretender";
|
||||||
import { acceptance, queryAll } from "discourse/tests/helpers/qunit-helpers";
|
import { acceptance, queryAll } from "discourse/tests/helpers/qunit-helpers";
|
||||||
import { cloneJSON } from "discourse-common/lib/object";
|
import { cloneJSON } from "discourse-common/lib/object";
|
||||||
|
import { postStreamWithAcceptedAnswerExcerpt } from "../helpers/discourse-solved-helpers";
|
||||||
|
|
||||||
acceptance("Discourse Solved Plugin", function (needs) {
|
acceptance("Discourse Solved Plugin", function (needs) {
|
||||||
needs.user();
|
needs.user();
|
||||||
|
|
||||||
needs.pretender((server, helper) => {
|
needs.pretender((server, helper) => {
|
||||||
const postStreamWithAcceptedAnswerExcerpt = (excerpt) => {
|
|
||||||
return {
|
|
||||||
post_stream: {
|
|
||||||
posts: [
|
|
||||||
{
|
|
||||||
id: 21,
|
|
||||||
name: null,
|
|
||||||
username: "kzh",
|
|
||||||
avatar_template:
|
|
||||||
"/letter_avatar_proxy/v2/letter/k/ac91a4/{size}.png",
|
|
||||||
created_at: "2017-08-08T20:11:32.542Z",
|
|
||||||
cooked: "<p>How do I declare a variable in ruby?</p>",
|
|
||||||
post_number: 1,
|
|
||||||
post_type: 1,
|
|
||||||
updated_at: "2017-08-08T21:03:30.521Z",
|
|
||||||
reply_count: 0,
|
|
||||||
reply_to_post_number: null,
|
|
||||||
quote_count: 0,
|
|
||||||
avg_time: null,
|
|
||||||
incoming_link_count: 0,
|
|
||||||
reads: 1,
|
|
||||||
score: 0,
|
|
||||||
yours: true,
|
|
||||||
topic_id: 23,
|
|
||||||
topic_slug: "test-solved",
|
|
||||||
display_username: null,
|
|
||||||
primary_group_name: null,
|
|
||||||
primary_group_flair_url: null,
|
|
||||||
primary_group_flair_bg_color: null,
|
|
||||||
primary_group_flair_color: null,
|
|
||||||
version: 2,
|
|
||||||
can_edit: true,
|
|
||||||
can_delete: false,
|
|
||||||
can_recover: null,
|
|
||||||
can_wiki: true,
|
|
||||||
read: true,
|
|
||||||
user_title: null,
|
|
||||||
actions_summary: [
|
|
||||||
{ id: 3, can_act: true },
|
|
||||||
{ id: 4, can_act: true },
|
|
||||||
{ id: 5, hidden: true, can_act: true },
|
|
||||||
{ id: 7, can_act: true },
|
|
||||||
{ id: 8, can_act: true },
|
|
||||||
],
|
|
||||||
moderator: false,
|
|
||||||
admin: true,
|
|
||||||
staff: true,
|
|
||||||
user_id: 1,
|
|
||||||
hidden: false,
|
|
||||||
hidden_reason_id: null,
|
|
||||||
trust_level: 4,
|
|
||||||
deleted_at: null,
|
|
||||||
user_deleted: false,
|
|
||||||
edit_reason: null,
|
|
||||||
can_view_edit_history: true,
|
|
||||||
wiki: false,
|
|
||||||
can_accept_answer: false,
|
|
||||||
can_unaccept_answer: false,
|
|
||||||
accepted_answer: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 22,
|
|
||||||
name: null,
|
|
||||||
username: "kzh",
|
|
||||||
avatar_template:
|
|
||||||
"/letter_avatar_proxy/v2/letter/k/ac91a4/{size}.png",
|
|
||||||
created_at: "2017-08-08T20:12:04.657Z",
|
|
||||||
cooked:
|
|
||||||
"<p>this is a long answer that potentially solves the question</p>",
|
|
||||||
post_number: 2,
|
|
||||||
post_type: 1,
|
|
||||||
updated_at: "2017-08-08T21:20:24.417Z",
|
|
||||||
reply_count: 0,
|
|
||||||
reply_to_post_number: null,
|
|
||||||
quote_count: 0,
|
|
||||||
avg_time: null,
|
|
||||||
incoming_link_count: 0,
|
|
||||||
reads: 1,
|
|
||||||
score: 0,
|
|
||||||
yours: true,
|
|
||||||
topic_id: 23,
|
|
||||||
topic_slug: "test-solved",
|
|
||||||
display_username: null,
|
|
||||||
primary_group_name: null,
|
|
||||||
primary_group_flair_url: null,
|
|
||||||
primary_group_flair_bg_color: null,
|
|
||||||
primary_group_flair_color: null,
|
|
||||||
version: 2,
|
|
||||||
can_edit: true,
|
|
||||||
can_delete: true,
|
|
||||||
can_recover: null,
|
|
||||||
can_wiki: true,
|
|
||||||
read: true,
|
|
||||||
user_title: null,
|
|
||||||
actions_summary: [
|
|
||||||
{ id: 3, can_act: true },
|
|
||||||
{ id: 4, can_act: true },
|
|
||||||
{ id: 5, hidden: true, can_act: true },
|
|
||||||
{ id: 7, can_act: true },
|
|
||||||
{ id: 8, can_act: true },
|
|
||||||
],
|
|
||||||
moderator: false,
|
|
||||||
admin: true,
|
|
||||||
staff: true,
|
|
||||||
user_id: 1,
|
|
||||||
hidden: false,
|
|
||||||
hidden_reason_id: null,
|
|
||||||
trust_level: 4,
|
|
||||||
deleted_at: null,
|
|
||||||
user_deleted: false,
|
|
||||||
edit_reason: null,
|
|
||||||
can_view_edit_history: true,
|
|
||||||
wiki: false,
|
|
||||||
can_accept_answer: false,
|
|
||||||
can_unaccept_answer: true,
|
|
||||||
accepted_answer: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
stream: [21, 22],
|
|
||||||
},
|
|
||||||
timeline_lookup: [[1, 0]],
|
|
||||||
id: 23,
|
|
||||||
title: "Test solved",
|
|
||||||
fancy_title: "Test solved",
|
|
||||||
posts_count: 2,
|
|
||||||
created_at: "2017-08-08T20:11:32.098Z",
|
|
||||||
views: 6,
|
|
||||||
reply_count: 0,
|
|
||||||
participant_count: 1,
|
|
||||||
like_count: 0,
|
|
||||||
last_posted_at: "2017-08-08T20:12:04.657Z",
|
|
||||||
visible: true,
|
|
||||||
closed: false,
|
|
||||||
archived: false,
|
|
||||||
has_summary: false,
|
|
||||||
archetype: "regular",
|
|
||||||
slug: "test-solved",
|
|
||||||
category_id: 1,
|
|
||||||
word_count: 18,
|
|
||||||
deleted_at: null,
|
|
||||||
pending_posts_count: 0,
|
|
||||||
user_id: 1,
|
|
||||||
pm_with_non_human_user: false,
|
|
||||||
draft: null,
|
|
||||||
draft_key: "topic_23",
|
|
||||||
draft_sequence: 6,
|
|
||||||
posted: true,
|
|
||||||
unpinned: null,
|
|
||||||
pinned_globally: false,
|
|
||||||
pinned: false,
|
|
||||||
pinned_at: null,
|
|
||||||
pinned_until: null,
|
|
||||||
details: {
|
|
||||||
created_by: {
|
|
||||||
id: 1,
|
|
||||||
username: "kzh",
|
|
||||||
avatar_template:
|
|
||||||
"/letter_avatar_proxy/v2/letter/k/ac91a4/{size}.png",
|
|
||||||
},
|
|
||||||
last_poster: {
|
|
||||||
id: 1,
|
|
||||||
username: "kzh",
|
|
||||||
avatar_template:
|
|
||||||
"/letter_avatar_proxy/v2/letter/k/ac91a4/{size}.png",
|
|
||||||
},
|
|
||||||
participants: [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
username: "kzh",
|
|
||||||
avatar_template:
|
|
||||||
"/letter_avatar_proxy/v2/letter/k/ac91a4/{size}.png",
|
|
||||||
post_count: 2,
|
|
||||||
primary_group_name: null,
|
|
||||||
primary_group_flair_url: null,
|
|
||||||
primary_group_flair_color: null,
|
|
||||||
primary_group_flair_bg_color: null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
notification_level: 3,
|
|
||||||
notifications_reason_id: 1,
|
|
||||||
can_move_posts: true,
|
|
||||||
can_edit: true,
|
|
||||||
can_delete: true,
|
|
||||||
can_remove_allowed_users: true,
|
|
||||||
can_invite_to: true,
|
|
||||||
can_invite_via_email: true,
|
|
||||||
can_create_post: true,
|
|
||||||
can_reply_as_new_topic: true,
|
|
||||||
can_flag_topic: true,
|
|
||||||
},
|
|
||||||
highest_post_number: 2,
|
|
||||||
last_read_post_number: 2,
|
|
||||||
last_read_post_id: 22,
|
|
||||||
deleted_by: null,
|
|
||||||
has_deleted: false,
|
|
||||||
actions_summary: [
|
|
||||||
{ id: 4, count: 0, hidden: false, can_act: true },
|
|
||||||
{ id: 7, count: 0, hidden: false, can_act: true },
|
|
||||||
{ id: 8, count: 0, hidden: false, can_act: true },
|
|
||||||
],
|
|
||||||
chunk_size: 20,
|
|
||||||
bookmarked: false,
|
|
||||||
tags: [],
|
|
||||||
featured_link: null,
|
|
||||||
topic_timer: null,
|
|
||||||
message_bus_last_id: 0,
|
|
||||||
accepted_answer: { post_number: 2, username: "kzh", excerpt },
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
server.get("/t/11.json", () => {
|
server.get("/t/11.json", () => {
|
||||||
return helper.response(
|
return helper.response(
|
||||||
postStreamWithAcceptedAnswerExcerpt("this is an excerpt")
|
postStreamWithAcceptedAnswerExcerpt("this is an excerpt")
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
import { click, visit } from "@ember/test-helpers";
|
||||||
|
import { test } from "qunit";
|
||||||
|
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||||
|
import I18n from "I18n";
|
||||||
|
import { postStreamWithAcceptedAnswerExcerpt } from "../helpers/discourse-solved-helpers";
|
||||||
|
|
||||||
|
acceptance(
|
||||||
|
"Discourse Solved | Widget Post Menu |Accept and Unaccept",
|
||||||
|
function (needs) {
|
||||||
|
needs.user({
|
||||||
|
admin: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
needs.settings({
|
||||||
|
glimmer_post_menu_mode: "disabled",
|
||||||
|
solved_enabled: true,
|
||||||
|
allow_solved_on_all_topics: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
needs.pretender((server, helper) => {
|
||||||
|
server.post("/solution/accept", () => helper.response({ success: "OK" }));
|
||||||
|
server.post("/solution/unaccept", () =>
|
||||||
|
helper.response({ success: "OK" })
|
||||||
|
);
|
||||||
|
|
||||||
|
server.get("/t/12.json", () => {
|
||||||
|
return helper.response(postStreamWithAcceptedAnswerExcerpt(null));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("accepting and unaccepting a post works", async function (assert) {
|
||||||
|
await visit("/t/without-excerpt/12");
|
||||||
|
|
||||||
|
assert
|
||||||
|
.dom("#post_2 .accepted")
|
||||||
|
.exists("Unaccept button is visible")
|
||||||
|
.hasText(I18n.t("solved.solution"), "Unaccept button has correct text");
|
||||||
|
|
||||||
|
await click("#post_2 .accepted");
|
||||||
|
|
||||||
|
assert.dom("#post_2 .unaccepted").exists("Accept button is visible");
|
||||||
|
|
||||||
|
await click("#post_2 .unaccepted");
|
||||||
|
|
||||||
|
assert.dom("#post_2 .accepted").exists("Unccept button is visible again");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
|
@ -0,0 +1,204 @@
|
||||||
|
export const postStreamWithAcceptedAnswerExcerpt = (excerpt) => {
|
||||||
|
return {
|
||||||
|
post_stream: {
|
||||||
|
posts: [
|
||||||
|
{
|
||||||
|
id: 21,
|
||||||
|
name: null,
|
||||||
|
username: "kzh",
|
||||||
|
avatar_template: "/letter_avatar_proxy/v2/letter/k/ac91a4/{size}.png",
|
||||||
|
created_at: "2017-08-08T20:11:32.542Z",
|
||||||
|
cooked: "<p>How do I declare a variable in ruby?</p>",
|
||||||
|
post_number: 1,
|
||||||
|
post_type: 1,
|
||||||
|
updated_at: "2017-08-08T21:03:30.521Z",
|
||||||
|
reply_count: 0,
|
||||||
|
reply_to_post_number: null,
|
||||||
|
quote_count: 0,
|
||||||
|
avg_time: null,
|
||||||
|
incoming_link_count: 0,
|
||||||
|
reads: 1,
|
||||||
|
score: 0,
|
||||||
|
yours: true,
|
||||||
|
topic_id: 23,
|
||||||
|
topic_slug: "test-solved",
|
||||||
|
display_username: null,
|
||||||
|
primary_group_name: null,
|
||||||
|
primary_group_flair_url: null,
|
||||||
|
primary_group_flair_bg_color: null,
|
||||||
|
primary_group_flair_color: null,
|
||||||
|
version: 2,
|
||||||
|
can_edit: true,
|
||||||
|
can_delete: false,
|
||||||
|
can_recover: null,
|
||||||
|
can_wiki: true,
|
||||||
|
read: true,
|
||||||
|
user_title: null,
|
||||||
|
actions_summary: [
|
||||||
|
{ id: 3, can_act: true },
|
||||||
|
{ id: 4, can_act: true },
|
||||||
|
{ id: 5, hidden: true, can_act: true },
|
||||||
|
{ id: 7, can_act: true },
|
||||||
|
{ id: 8, can_act: true },
|
||||||
|
],
|
||||||
|
moderator: false,
|
||||||
|
admin: true,
|
||||||
|
staff: true,
|
||||||
|
user_id: 1,
|
||||||
|
hidden: false,
|
||||||
|
hidden_reason_id: null,
|
||||||
|
trust_level: 4,
|
||||||
|
deleted_at: null,
|
||||||
|
user_deleted: false,
|
||||||
|
edit_reason: null,
|
||||||
|
can_view_edit_history: true,
|
||||||
|
wiki: false,
|
||||||
|
can_accept_answer: false,
|
||||||
|
can_unaccept_answer: false,
|
||||||
|
accepted_answer: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 22,
|
||||||
|
name: null,
|
||||||
|
username: "kzh",
|
||||||
|
avatar_template: "/letter_avatar_proxy/v2/letter/k/ac91a4/{size}.png",
|
||||||
|
created_at: "2017-08-08T20:12:04.657Z",
|
||||||
|
cooked:
|
||||||
|
"<p>this is a long answer that potentially solves the question</p>",
|
||||||
|
post_number: 2,
|
||||||
|
post_type: 1,
|
||||||
|
updated_at: "2017-08-08T21:20:24.417Z",
|
||||||
|
reply_count: 0,
|
||||||
|
reply_to_post_number: null,
|
||||||
|
quote_count: 0,
|
||||||
|
avg_time: null,
|
||||||
|
incoming_link_count: 0,
|
||||||
|
reads: 1,
|
||||||
|
score: 0,
|
||||||
|
yours: true,
|
||||||
|
topic_id: 23,
|
||||||
|
topic_slug: "test-solved",
|
||||||
|
display_username: null,
|
||||||
|
primary_group_name: null,
|
||||||
|
primary_group_flair_url: null,
|
||||||
|
primary_group_flair_bg_color: null,
|
||||||
|
primary_group_flair_color: null,
|
||||||
|
version: 2,
|
||||||
|
can_edit: true,
|
||||||
|
can_delete: true,
|
||||||
|
can_recover: null,
|
||||||
|
can_wiki: true,
|
||||||
|
read: true,
|
||||||
|
user_title: null,
|
||||||
|
actions_summary: [
|
||||||
|
{ id: 3, can_act: true },
|
||||||
|
{ id: 4, can_act: true },
|
||||||
|
{ id: 5, hidden: true, can_act: true },
|
||||||
|
{ id: 7, can_act: true },
|
||||||
|
{ id: 8, can_act: true },
|
||||||
|
],
|
||||||
|
moderator: false,
|
||||||
|
admin: true,
|
||||||
|
staff: true,
|
||||||
|
user_id: 1,
|
||||||
|
hidden: false,
|
||||||
|
hidden_reason_id: null,
|
||||||
|
trust_level: 4,
|
||||||
|
deleted_at: null,
|
||||||
|
user_deleted: false,
|
||||||
|
edit_reason: null,
|
||||||
|
can_view_edit_history: true,
|
||||||
|
wiki: false,
|
||||||
|
can_accept_answer: false,
|
||||||
|
can_unaccept_answer: true,
|
||||||
|
accepted_answer: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
stream: [21, 22],
|
||||||
|
},
|
||||||
|
timeline_lookup: [[1, 0]],
|
||||||
|
id: 23,
|
||||||
|
title: "Test solved",
|
||||||
|
fancy_title: "Test solved",
|
||||||
|
posts_count: 2,
|
||||||
|
created_at: "2017-08-08T20:11:32.098Z",
|
||||||
|
views: 6,
|
||||||
|
reply_count: 0,
|
||||||
|
participant_count: 1,
|
||||||
|
like_count: 0,
|
||||||
|
last_posted_at: "2017-08-08T20:12:04.657Z",
|
||||||
|
visible: true,
|
||||||
|
closed: false,
|
||||||
|
archived: false,
|
||||||
|
has_summary: false,
|
||||||
|
archetype: "regular",
|
||||||
|
slug: "test-solved",
|
||||||
|
category_id: 1,
|
||||||
|
word_count: 18,
|
||||||
|
deleted_at: null,
|
||||||
|
pending_posts_count: 0,
|
||||||
|
user_id: 1,
|
||||||
|
pm_with_non_human_user: false,
|
||||||
|
draft: null,
|
||||||
|
draft_key: "topic_23",
|
||||||
|
draft_sequence: 6,
|
||||||
|
posted: true,
|
||||||
|
unpinned: null,
|
||||||
|
pinned_globally: false,
|
||||||
|
pinned: false,
|
||||||
|
pinned_at: null,
|
||||||
|
pinned_until: null,
|
||||||
|
details: {
|
||||||
|
created_by: {
|
||||||
|
id: 1,
|
||||||
|
username: "kzh",
|
||||||
|
avatar_template: "/letter_avatar_proxy/v2/letter/k/ac91a4/{size}.png",
|
||||||
|
},
|
||||||
|
last_poster: {
|
||||||
|
id: 1,
|
||||||
|
username: "kzh",
|
||||||
|
avatar_template: "/letter_avatar_proxy/v2/letter/k/ac91a4/{size}.png",
|
||||||
|
},
|
||||||
|
participants: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
username: "kzh",
|
||||||
|
avatar_template: "/letter_avatar_proxy/v2/letter/k/ac91a4/{size}.png",
|
||||||
|
post_count: 2,
|
||||||
|
primary_group_name: null,
|
||||||
|
primary_group_flair_url: null,
|
||||||
|
primary_group_flair_color: null,
|
||||||
|
primary_group_flair_bg_color: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
notification_level: 3,
|
||||||
|
notifications_reason_id: 1,
|
||||||
|
can_move_posts: true,
|
||||||
|
can_edit: true,
|
||||||
|
can_delete: true,
|
||||||
|
can_remove_allowed_users: true,
|
||||||
|
can_invite_to: true,
|
||||||
|
can_invite_via_email: true,
|
||||||
|
can_create_post: true,
|
||||||
|
can_reply_as_new_topic: true,
|
||||||
|
can_flag_topic: true,
|
||||||
|
},
|
||||||
|
highest_post_number: 2,
|
||||||
|
last_read_post_number: 2,
|
||||||
|
last_read_post_id: 22,
|
||||||
|
deleted_by: null,
|
||||||
|
has_deleted: false,
|
||||||
|
actions_summary: [
|
||||||
|
{ id: 4, count: 0, hidden: false, can_act: true },
|
||||||
|
{ id: 7, count: 0, hidden: false, can_act: true },
|
||||||
|
{ id: 8, count: 0, hidden: false, can_act: true },
|
||||||
|
],
|
||||||
|
chunk_size: 20,
|
||||||
|
bookmarked: false,
|
||||||
|
tags: [],
|
||||||
|
featured_link: null,
|
||||||
|
topic_timer: null,
|
||||||
|
message_bus_last_id: 0,
|
||||||
|
accepted_answer: { post_number: 2, username: "kzh", excerpt },
|
||||||
|
};
|
||||||
|
};
|
Loading…
Reference in New Issue