REFACTOR: Glimmerify topic summarization widgets. (#23043)
* REFACTOR: Glimerify topic summarization widgets. Simplifies all the logic for generating/regenerating summaries and expanding/collapsing the summary box. It makes streaming easier to implement since now we can subscribe to message bus directly from the component. * Update app/assets/javascripts/discourse/app/components/summary-box.hbs Co-authored-by: David Taylor <david@taylorhq.com> * Update app/assets/javascripts/discourse/app/components/summary-box.hbs Co-authored-by: David Taylor <david@taylorhq.com> * Update app/assets/javascripts/discourse/app/components/summary-box.hbs Co-authored-by: David Taylor <david@taylorhq.com> --------- Co-authored-by: David Taylor <david@taylorhq.com>
This commit is contained in:
parent
0b29dc5d38
commit
b832786f35
|
@ -1,4 +1,5 @@
|
||||||
<ul class="ai-summary__list" {{did-insert this.setupAnimation}}>
|
<div class="ai-summary__container">
|
||||||
|
<ul class="ai-summary__list" {{did-insert this.setupAnimation}}>
|
||||||
{{#each this.blocks as |block|}}
|
{{#each this.blocks as |block|}}
|
||||||
<li
|
<li
|
||||||
class={{concat-class
|
class={{concat-class
|
||||||
|
@ -12,9 +13,9 @@
|
||||||
{{will-destroy this.teardownAnimation}}
|
{{will-destroy this.teardownAnimation}}
|
||||||
></li>
|
></li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<span>
|
<span>
|
||||||
<div class="ai-summary__generating-text">
|
<div class="ai-summary__generating-text">
|
||||||
{{i18n "summary.in_progress"}}
|
{{i18n "summary.in_progress"}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -23,4 +24,5 @@
|
||||||
<span class="ai-summary__indicator-dot">.</span>
|
<span class="ai-summary__indicator-dot">.</span>
|
||||||
<span class="ai-summary__indicator-dot">.</span>
|
<span class="ai-summary__indicator-dot">.</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
|
@ -0,0 +1,62 @@
|
||||||
|
{{#if @postAttrs.hasTopRepliesSummary}}
|
||||||
|
<p>{{html-safe this.topRepliesSummaryInfo}}</p>
|
||||||
|
{{/if}}
|
||||||
|
<div class="summarization-buttons">
|
||||||
|
{{#if @postAttrs.summarizable}}
|
||||||
|
{{#if this.canCollapseSummary}}
|
||||||
|
<DButton
|
||||||
|
@class="btn-primary topic-strategy-summarization"
|
||||||
|
@action={{this.toggleSummary}}
|
||||||
|
@title="summary.buttons.hide"
|
||||||
|
@label="summary.buttons.hide"
|
||||||
|
@icon="chevron-up"
|
||||||
|
/>
|
||||||
|
{{else}}
|
||||||
|
<DButton
|
||||||
|
@class="btn-primary topic-strategy-summarization"
|
||||||
|
@action={{this.generateSummary}}
|
||||||
|
@translatedLabel={{this.generateSummaryTitle}}
|
||||||
|
@translatedTitle={{this.generateSummaryTitle}}
|
||||||
|
@icon={{this.generateSummaryIcon}}
|
||||||
|
@disabled={{this.loadingSummary}}
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if @postAttrs.hasTopRepliesSummary}}
|
||||||
|
<DButton
|
||||||
|
@class="top-replies"
|
||||||
|
@action={{this.toggleTopRepliesFilter}}
|
||||||
|
@translatedTitle={{this.topRepliesTitle}}
|
||||||
|
@translatedLabel={{this.topRepliesLabel}}
|
||||||
|
@icon={{this.topRepliesIcon}}
|
||||||
|
/>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if this.showSummaryBox}}
|
||||||
|
<article class="summary-box">
|
||||||
|
{{#if this.loadingSummary}}
|
||||||
|
<AiSummarySkeleton />
|
||||||
|
{{else}}
|
||||||
|
<div class="generated-summary">{{this.summary}}</div>
|
||||||
|
<div class="summarized-on">
|
||||||
|
<p>
|
||||||
|
{{i18n "summary.summarized_on" date=this.summarizedOn}}
|
||||||
|
<span>
|
||||||
|
{{d-icon "info-circle"}}
|
||||||
|
<DTooltip @placement="top-end">
|
||||||
|
{{i18n "summary.model_used" model=this.summarizedBy}}
|
||||||
|
</DTooltip>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{{#if this.outdated}}
|
||||||
|
<p class="outdated-summary">
|
||||||
|
{{this.outdatedSummaryWarningText}}
|
||||||
|
</p>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</article>
|
||||||
|
{{/if}}
|
|
@ -0,0 +1,156 @@
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import I18n from "I18n";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { ajax } from "discourse/lib/ajax";
|
||||||
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
import { cookAsync } from "discourse/lib/text";
|
||||||
|
import { shortDateNoYear } from "discourse/lib/formatter";
|
||||||
|
|
||||||
|
const MIN_POST_READ_TIME = 4;
|
||||||
|
|
||||||
|
export default class SummaryBox extends Component {
|
||||||
|
@service siteSettings;
|
||||||
|
|
||||||
|
@tracked summary = "";
|
||||||
|
@tracked summarizedOn = null;
|
||||||
|
@tracked summarizedBy = null;
|
||||||
|
@tracked newPostsSinceSummary = null;
|
||||||
|
@tracked outdated = false;
|
||||||
|
@tracked canRegenerate = false;
|
||||||
|
|
||||||
|
@tracked regenerated = false;
|
||||||
|
@tracked showSummaryBox = false;
|
||||||
|
@tracked canCollapseSummary = false;
|
||||||
|
@tracked loadingSummary = false;
|
||||||
|
|
||||||
|
get generateSummaryTitle() {
|
||||||
|
const title = this.canRegenerate
|
||||||
|
? "summary.buttons.regenerate"
|
||||||
|
: "summary.buttons.generate";
|
||||||
|
|
||||||
|
return I18n.t(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
get generateSummaryIcon() {
|
||||||
|
return this.canRegenerate ? "sync" : "magic";
|
||||||
|
}
|
||||||
|
|
||||||
|
get outdatedSummaryWarningText() {
|
||||||
|
let outdatedText = I18n.t("summary.outdated");
|
||||||
|
|
||||||
|
if (
|
||||||
|
!this.args.postAttrs.hasTopRepliesSummary &&
|
||||||
|
this.newPostsSinceSummary > 0
|
||||||
|
) {
|
||||||
|
outdatedText += " ";
|
||||||
|
outdatedText += I18n.t("summary.outdated_posts", {
|
||||||
|
count: this.newPostsSinceSummary,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return outdatedText;
|
||||||
|
}
|
||||||
|
|
||||||
|
get topRepliesSummaryEnabled() {
|
||||||
|
return this.args.postAttrs.topicSummaryEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
get topRepliesSummaryInfo() {
|
||||||
|
if (this.args.postAttrs.topicSummaryEnabled) {
|
||||||
|
return I18n.t("summary.enabled_description");
|
||||||
|
}
|
||||||
|
|
||||||
|
const wordCount = this.args.postAttrs.topicWordCount;
|
||||||
|
if (wordCount && this.siteSettings.read_time_word_count > 0) {
|
||||||
|
const readingTime = Math.ceil(
|
||||||
|
Math.max(
|
||||||
|
wordCount / this.siteSettings.read_time_word_count,
|
||||||
|
(this.args.postAttrs.topicPostsCount * MIN_POST_READ_TIME) / 60
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return I18n.messageFormat("summary.description_time_MF", {
|
||||||
|
replyCount: this.args.postAttrs.topicReplyCount,
|
||||||
|
readingTime,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return I18n.t("summary.description", {
|
||||||
|
count: this.args.postAttrs.topicReplyCount,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get topRepliesTitle() {
|
||||||
|
if (this.topRepliesSummaryEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return I18n.t("summary.short_title");
|
||||||
|
}
|
||||||
|
|
||||||
|
get topRepliesLabel() {
|
||||||
|
const label = this.topRepliesSummaryEnabled
|
||||||
|
? "summary.disable"
|
||||||
|
: "summary.enable";
|
||||||
|
|
||||||
|
return I18n.t(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
get topRepliesIcon() {
|
||||||
|
if (this.topRepliesSummaryEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "layer-group";
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
toggleTopRepliesFilter() {
|
||||||
|
const filterFunction = this.topRepliesSummaryEnabled
|
||||||
|
? "cancelFilter"
|
||||||
|
: "showTopReplies";
|
||||||
|
|
||||||
|
this.args.topRepliesToggle(filterFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
collapseSummary() {
|
||||||
|
this.showSummaryBox = false;
|
||||||
|
this.canCollapseSummary = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
generateSummary() {
|
||||||
|
this.showSummaryBox = true;
|
||||||
|
|
||||||
|
if (this.summary && !this.canRegenerate) {
|
||||||
|
this.canCollapseSummary = true;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
this.loadingSummary = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let fetchURL = `/t/${this.args.postAttrs.topicId}/strategy-summary`;
|
||||||
|
|
||||||
|
if (this.canRegenerate) {
|
||||||
|
fetchURL += "?skip_age_check=true";
|
||||||
|
}
|
||||||
|
|
||||||
|
ajax(fetchURL)
|
||||||
|
.then((data) => {
|
||||||
|
cookAsync(data.summary).then((cooked) => {
|
||||||
|
this.summary = cooked;
|
||||||
|
this.summarizedOn = shortDateNoYear(data.summarized_on);
|
||||||
|
this.summarizedBy = data.summarized_by;
|
||||||
|
this.newPostsSinceSummary = data.new_posts_since_summary;
|
||||||
|
this.outdated = data.outdated;
|
||||||
|
this.newPostsSinceSummary = data.new_posts_since_summary;
|
||||||
|
this.canRegenerate = data.outdated && data.can_regenerate;
|
||||||
|
|
||||||
|
this.canCollapseSummary = !this.canRegenerate;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(popupAjaxError)
|
||||||
|
.finally(() => (this.loadingSummary = false));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,116 +0,0 @@
|
||||||
import { createWidget } from "discourse/widgets/widget";
|
|
||||||
import { hbs } from "ember-cli-htmlbars";
|
|
||||||
import { ajax } from "discourse/lib/ajax";
|
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
|
||||||
import { cookAsync } from "discourse/lib/text";
|
|
||||||
import RawHtml from "discourse/widgets/raw-html";
|
|
||||||
import I18n from "I18n";
|
|
||||||
import { shortDateNoYear } from "discourse/lib/formatter";
|
|
||||||
import { h } from "virtual-dom";
|
|
||||||
import { iconNode } from "discourse-common/lib/icon-library";
|
|
||||||
import RenderGlimmer from "discourse/widgets/render-glimmer";
|
|
||||||
|
|
||||||
export default createWidget("summary-box", {
|
|
||||||
tagName: "article.summary-box",
|
|
||||||
buildKey: (attrs) => `summary-box-${attrs.topicId}`,
|
|
||||||
|
|
||||||
defaultState() {
|
|
||||||
return { expandSummarizedOn: false };
|
|
||||||
},
|
|
||||||
|
|
||||||
html(attrs) {
|
|
||||||
const html = [];
|
|
||||||
|
|
||||||
const summary = attrs.summary;
|
|
||||||
|
|
||||||
if (summary && !attrs.skipAgeCheck) {
|
|
||||||
html.push(
|
|
||||||
new RawHtml({
|
|
||||||
html: `<div class="generated-summary">${summary.summarized_text}</div>`,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
const summarizationInfo = [
|
|
||||||
h("p", {}, [
|
|
||||||
I18n.t("summary.summarized_on", { date: summary.summarized_on }),
|
|
||||||
this.buildTooltip(attrs),
|
|
||||||
]),
|
|
||||||
];
|
|
||||||
|
|
||||||
if (summary.outdated) {
|
|
||||||
summarizationInfo.push(this.outdatedSummaryWarning(attrs));
|
|
||||||
}
|
|
||||||
|
|
||||||
html.push(h("div.summarized-on", {}, summarizationInfo));
|
|
||||||
} else {
|
|
||||||
html.push(this.buildSummarySkeleton());
|
|
||||||
this.fetchSummary(attrs.topicId, attrs.skipAgeCheck);
|
|
||||||
}
|
|
||||||
|
|
||||||
return html;
|
|
||||||
},
|
|
||||||
|
|
||||||
buildSummarySkeleton() {
|
|
||||||
return new RenderGlimmer(
|
|
||||||
this,
|
|
||||||
"div.ai-summary__container",
|
|
||||||
hbs`{{ai-summary-skeleton}}`
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
buildTooltip(attrs) {
|
|
||||||
return new RenderGlimmer(
|
|
||||||
this,
|
|
||||||
"span",
|
|
||||||
hbs`{{d-icon "info-circle"}}<DTooltip @placement="top-end">
|
|
||||||
{{i18n "summary.model_used" model=@data.summarizedBy}}
|
|
||||||
</DTooltip>`,
|
|
||||||
{
|
|
||||||
summarizedBy: attrs.summary.summarized_by,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
outdatedSummaryWarning(attrs) {
|
|
||||||
let outdatedText = I18n.t("summary.outdated");
|
|
||||||
|
|
||||||
if (
|
|
||||||
!attrs.hasTopRepliesSummary &&
|
|
||||||
attrs.summary.new_posts_since_summary > 0
|
|
||||||
) {
|
|
||||||
outdatedText += " ";
|
|
||||||
outdatedText += I18n.t("summary.outdated_posts", {
|
|
||||||
count: attrs.summary.new_posts_since_summary,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return h("p.outdated-summary", {}, [
|
|
||||||
outdatedText,
|
|
||||||
iconNode("exclamation-triangle", { class: "info-icon" }),
|
|
||||||
]);
|
|
||||||
},
|
|
||||||
|
|
||||||
fetchSummary(topicId, skipAgeCheck) {
|
|
||||||
let fetchURL = `/t/${topicId}/strategy-summary`;
|
|
||||||
|
|
||||||
if (skipAgeCheck) {
|
|
||||||
fetchURL += "?skip_age_check=true";
|
|
||||||
}
|
|
||||||
|
|
||||||
ajax(fetchURL)
|
|
||||||
.then((data) => {
|
|
||||||
cookAsync(data.summary).then((cooked) => {
|
|
||||||
// We store the summary in the parent so we can re-render it without doing a new request.
|
|
||||||
data.summarized_text = cooked.string;
|
|
||||||
data.summarized_on = shortDateNoYear(data.summarized_on);
|
|
||||||
|
|
||||||
if (skipAgeCheck) {
|
|
||||||
data.regenerated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.sendWidgetEvent("summaryUpdated", data);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(popupAjaxError);
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -1,154 +0,0 @@
|
||||||
import I18n from "I18n";
|
|
||||||
import RawHtml from "discourse/widgets/raw-html";
|
|
||||||
import { createWidget } from "discourse/widgets/widget";
|
|
||||||
import { h } from "virtual-dom";
|
|
||||||
|
|
||||||
const MIN_POST_READ_TIME = 4;
|
|
||||||
|
|
||||||
createWidget("toggle-summary-description", {
|
|
||||||
description(attrs) {
|
|
||||||
if (attrs.topicSummaryEnabled) {
|
|
||||||
return I18n.t("summary.enabled_description");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attrs.topicWordCount && this.siteSettings.read_time_word_count > 0) {
|
|
||||||
const readingTime = Math.ceil(
|
|
||||||
Math.max(
|
|
||||||
attrs.topicWordCount / this.siteSettings.read_time_word_count,
|
|
||||||
(attrs.topicPostsCount * MIN_POST_READ_TIME) / 60
|
|
||||||
)
|
|
||||||
);
|
|
||||||
return I18n.messageFormat("summary.description_time_MF", {
|
|
||||||
replyCount: attrs.topicReplyCount,
|
|
||||||
readingTime,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return I18n.t("summary.description", { count: attrs.topicReplyCount });
|
|
||||||
},
|
|
||||||
|
|
||||||
html(attrs) {
|
|
||||||
// vdom makes putting html in the i18n difficult
|
|
||||||
return new RawHtml({ html: `<p>${this.description(attrs)}</p>` });
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default createWidget("toggle-topic-summary", {
|
|
||||||
tagName: "section.information.toggle-summary",
|
|
||||||
buildKey: (attrs) => `toggle-topic-summary-${attrs.topicId}`,
|
|
||||||
|
|
||||||
defaultState() {
|
|
||||||
return {
|
|
||||||
expandSummaryBox: false,
|
|
||||||
summaryBoxHidden: true,
|
|
||||||
summary: "",
|
|
||||||
summarizedOn: null,
|
|
||||||
summarizedBy: null,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
html(attrs, state) {
|
|
||||||
const html = [];
|
|
||||||
const summarizationButtons = [];
|
|
||||||
|
|
||||||
if (attrs.summarizable) {
|
|
||||||
const canRegenerate =
|
|
||||||
!state.regenerate &&
|
|
||||||
state.summary.outdated &&
|
|
||||||
state.summary.can_regenerate;
|
|
||||||
const canCollapse =
|
|
||||||
!canRegenerate && !this.loadingSummary() && this.summaryBoxVisble();
|
|
||||||
const summarizeButton = canCollapse
|
|
||||||
? this.hideSummaryButton()
|
|
||||||
: this.generateSummaryButton(canRegenerate);
|
|
||||||
|
|
||||||
summarizationButtons.push(summarizeButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attrs.hasTopRepliesSummary) {
|
|
||||||
html.push(this.attach("toggle-summary-description", attrs));
|
|
||||||
summarizationButtons.push(
|
|
||||||
this.attach("button", {
|
|
||||||
className: "btn top-replies",
|
|
||||||
icon: attrs.topicSummaryEnabled ? null : "layer-group",
|
|
||||||
title: attrs.topicSummaryEnabled ? null : "summary.short_title",
|
|
||||||
label: attrs.topicSummaryEnabled
|
|
||||||
? "summary.disable"
|
|
||||||
: "summary.enable",
|
|
||||||
action: attrs.topicSummaryEnabled ? "cancelFilter" : "showTopReplies",
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (summarizationButtons) {
|
|
||||||
html.push(h("div.summarization-buttons", summarizationButtons));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.summaryBoxVisble()) {
|
|
||||||
attrs.summary = state.summary;
|
|
||||||
attrs.skipAgeCheck = state.regenerate;
|
|
||||||
|
|
||||||
html.push(this.attach("summary-box", attrs));
|
|
||||||
}
|
|
||||||
|
|
||||||
return html;
|
|
||||||
},
|
|
||||||
|
|
||||||
generateSummaryButton(canRegenerate) {
|
|
||||||
const title = canRegenerate
|
|
||||||
? "summary.buttons.regenerate"
|
|
||||||
: "summary.buttons.generate";
|
|
||||||
const icon = canRegenerate ? "sync" : "magic";
|
|
||||||
|
|
||||||
return this.attach("button", {
|
|
||||||
className: "btn btn-primary topic-strategy-summarization",
|
|
||||||
icon,
|
|
||||||
title: I18n.t(title),
|
|
||||||
translatedTitle: I18n.t(title),
|
|
||||||
translatedLabel: I18n.t(title),
|
|
||||||
action: canRegenerate ? "regenerateSummary" : "expandSummaryBox",
|
|
||||||
disabled: this.loadingSummary(),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
hideSummaryButton() {
|
|
||||||
return this.attach("button", {
|
|
||||||
className: "btn btn-primary topic-strategy-summarization",
|
|
||||||
icon: "chevron-up",
|
|
||||||
title: "summary.buttons.hide",
|
|
||||||
label: "summary.buttons.hide",
|
|
||||||
action: "toggleSummaryBox",
|
|
||||||
disabled: this.loadingSummary(),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
loadingSummary() {
|
|
||||||
return (
|
|
||||||
this.summaryBoxVisble() && (!this.state.summary || this.state.regenerate)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
summaryUpdatedEvent(summary) {
|
|
||||||
this.state.summary = summary;
|
|
||||||
|
|
||||||
if (summary.regenerated) {
|
|
||||||
this.state.regenerate = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
summaryBoxVisble() {
|
|
||||||
return this.state.expandSummaryBox && !this.state.summaryBoxHidden;
|
|
||||||
},
|
|
||||||
|
|
||||||
expandSummaryBox() {
|
|
||||||
this.state.expandSummaryBox = true;
|
|
||||||
this.state.summaryBoxHidden = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
regenerateSummary() {
|
|
||||||
this.state.regenerate = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
toggleSummaryBox() {
|
|
||||||
this.state.summaryBoxHidden = !this.state.summaryBoxHidden;
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -6,6 +6,8 @@ import { h } from "virtual-dom";
|
||||||
import { replaceEmoji } from "discourse/widgets/emoji";
|
import { replaceEmoji } from "discourse/widgets/emoji";
|
||||||
import autoGroupFlairForUser from "discourse/lib/avatar-flair";
|
import autoGroupFlairForUser from "discourse/lib/avatar-flair";
|
||||||
import { userPath } from "discourse/lib/url";
|
import { userPath } from "discourse/lib/url";
|
||||||
|
import RenderGlimmer from "discourse/widgets/render-glimmer";
|
||||||
|
import { hbs } from "ember-cli-htmlbars";
|
||||||
|
|
||||||
const LINKS_SHOWN = 5;
|
const LINKS_SHOWN = 5;
|
||||||
|
|
||||||
|
@ -387,7 +389,7 @@ export default createWidget("topic-map", {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attrs.hasTopRepliesSummary || attrs.summarizable) {
|
if (attrs.hasTopRepliesSummary || attrs.summarizable) {
|
||||||
contents.push(this.attach("toggle-topic-summary", attrs));
|
contents.push(this.buildSummaryBox(attrs));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attrs.showPMMap) {
|
if (attrs.showPMMap) {
|
||||||
|
@ -399,4 +401,21 @@ export default createWidget("topic-map", {
|
||||||
toggleMap() {
|
toggleMap() {
|
||||||
this.state.collapsed = !this.state.collapsed;
|
this.state.collapsed = !this.state.collapsed;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
buildSummaryBox(attrs) {
|
||||||
|
return new RenderGlimmer(
|
||||||
|
this,
|
||||||
|
"section.information.toggle-summary",
|
||||||
|
hbs`<SummaryBox
|
||||||
|
@postAttrs={{@data.postAttrs}}
|
||||||
|
@topRepliesToggle={{@data.actionDispatchFunc}}
|
||||||
|
/>`,
|
||||||
|
{
|
||||||
|
postAttrs: attrs,
|
||||||
|
actionDispatchFunc: (actionName) => {
|
||||||
|
this.sendWidgetAction(actionName);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue