DEV: Add compatibility with the Glimmer Post Stream
This commit is contained in:
parent
bf52519dc7
commit
1b8b2a3a32
|
@ -0,0 +1,95 @@
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { concat } from "@ember/helper";
|
||||||
|
import icon from "discourse/helpers/d-icon";
|
||||||
|
import userPrioritizedName from "discourse/helpers/user-prioritized-name";
|
||||||
|
import { i18n } from "discourse-i18n";
|
||||||
|
import { assignedToGroupPath, assignedToUserPath } from "../lib/url";
|
||||||
|
|
||||||
|
export default class AssignedToFirstPost extends Component {
|
||||||
|
get assignedToUser() {
|
||||||
|
return this.args.post?.topic?.assigned_to_user;
|
||||||
|
}
|
||||||
|
|
||||||
|
get assignedToGroup() {
|
||||||
|
return this.args.post?.topic?.assigned_to_group;
|
||||||
|
}
|
||||||
|
|
||||||
|
get icon() {
|
||||||
|
return this.assignedToUser ? "user-plus" : "group-plus";
|
||||||
|
}
|
||||||
|
|
||||||
|
get indirectlyAssignedTo() {
|
||||||
|
return this.args.post?.topic?.indirectly_assigned_to;
|
||||||
|
}
|
||||||
|
|
||||||
|
get indirectAssignments() {
|
||||||
|
if (!this.indirectlyAssignedTo) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.keys(this.indirectlyAssignedTo).map((postId) => {
|
||||||
|
const postNumber = this.indirectlyAssignedTo[postId].post_number;
|
||||||
|
|
||||||
|
return {
|
||||||
|
postId,
|
||||||
|
assignee: this.indirectlyAssignedTo[postId].assigned_to,
|
||||||
|
postNumber,
|
||||||
|
url: `${this.args.post.topic.url}/${postNumber}`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get isAssigned() {
|
||||||
|
return !!(
|
||||||
|
this.assignedToUser ||
|
||||||
|
this.assignedToGroup ||
|
||||||
|
this.args.post?.topic?.indirectly_assigned_to
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{#if this.isAssigned}}
|
||||||
|
<p class="assigned-to">
|
||||||
|
{{icon this.icon}}
|
||||||
|
{{#if this.assignedToUser}}
|
||||||
|
<span class="assignee">
|
||||||
|
<span class="assigned-to--user">
|
||||||
|
{{i18n
|
||||||
|
"discourse_assign.assigned_topic_to"
|
||||||
|
username=(userPrioritizedName this.assignedToUser)
|
||||||
|
path=(assignedToUserPath this.assignedToUser)
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if this.assignedToGroup}}
|
||||||
|
<span class="assignee">
|
||||||
|
<span class="assigned-to--group">
|
||||||
|
{{i18n
|
||||||
|
"discourse_assign.assigned_topic_to"
|
||||||
|
username=this.assignedToGroup.name
|
||||||
|
path=(assignedToGroupPath this.assignedToGroup)
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#each this.indirectAssignments key="postId" as |indirectAssignment|}}
|
||||||
|
<span class="assign-text">
|
||||||
|
{{i18n "discourse_assign.assigned"}}
|
||||||
|
</span>
|
||||||
|
<span class="assignee">
|
||||||
|
<a href={{indirectAssignment.url}} class="assigned-indirectly">
|
||||||
|
{{i18n
|
||||||
|
"discourse_assign.assign_post_to_multiple"
|
||||||
|
post_number=indirectAssignment.postNumber
|
||||||
|
username=(userPrioritizedName indirectAssignment.assignee)
|
||||||
|
}}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
{{/each}}
|
||||||
|
</p>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import { service } from "@ember/service";
|
||||||
import DButton from "discourse/components/d-button";
|
import DButton from "discourse/components/d-button";
|
||||||
import DropdownMenu from "discourse/components/dropdown-menu";
|
import DropdownMenu from "discourse/components/dropdown-menu";
|
||||||
import icon from "discourse/helpers/d-icon";
|
import icon from "discourse/helpers/d-icon";
|
||||||
|
import userPrioritizedName from "discourse/helpers/user-prioritized-name";
|
||||||
import { i18n } from "discourse-i18n";
|
import { i18n } from "discourse-i18n";
|
||||||
import DMenu from "float-kit/components/d-menu";
|
import DMenu from "float-kit/components/d-menu";
|
||||||
|
|
||||||
|
@ -11,14 +12,6 @@ export default class AssignedToPost extends Component {
|
||||||
@service taskActions;
|
@service taskActions;
|
||||||
@service siteSettings;
|
@service siteSettings;
|
||||||
|
|
||||||
get nameOrUsername() {
|
|
||||||
if (this.siteSettings.prioritize_full_name_in_ux) {
|
|
||||||
return this.args.assignedToUser.name || this.args.assignedToUser.username;
|
|
||||||
} else {
|
|
||||||
return this.args.assignedToUser.username;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
unassign() {
|
unassign() {
|
||||||
this.taskActions.unassignPost(this.args.post);
|
this.taskActions.unassignPost(this.args.post);
|
||||||
|
@ -42,7 +35,7 @@ export default class AssignedToPost extends Component {
|
||||||
|
|
||||||
<a href={{@href}} class="assigned-to-username">
|
<a href={{@href}} class="assigned-to-username">
|
||||||
{{#if @assignedToUser}}
|
{{#if @assignedToUser}}
|
||||||
{{this.nameOrUsername}}
|
{{userPrioritizedName @assignedToUser}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{@assignedToGroup.name}}
|
{{@assignedToGroup.name}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { assignedToGroupPath, assignedToUserPath } from "../lib/url";
|
||||||
|
import AssignedFirstPost from "./assigned-to-first-post";
|
||||||
|
import AssignedToPost from "./assigned-to-post";
|
||||||
|
|
||||||
|
export default class PostAssignmentsDisplay extends Component {
|
||||||
|
static shouldRender(args) {
|
||||||
|
return args.post;
|
||||||
|
}
|
||||||
|
|
||||||
|
get post() {
|
||||||
|
return this.args.outletArgs.post;
|
||||||
|
}
|
||||||
|
|
||||||
|
get assignedTo() {
|
||||||
|
return this.post.topic?.indirectly_assigned_to?.[this.post.id]?.assigned_to;
|
||||||
|
}
|
||||||
|
|
||||||
|
get assignedToUser() {
|
||||||
|
return this.assignedTo.username ? this.assignedTo : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
get assignedToGroup() {
|
||||||
|
return !this.assignedToUser && this.assignedTo.name
|
||||||
|
? this.assignedTo
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
get assignedHref() {
|
||||||
|
return this.assignedToUser
|
||||||
|
? assignedToUserPath(this.assignedToUser)
|
||||||
|
: assignedToGroupPath(this.assignedToGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{#if this.post.firstPost}}
|
||||||
|
<AssignedFirstPost @post={{this.post}} />
|
||||||
|
{{else if this.assignedTo}}
|
||||||
|
<p class="assigned-to">
|
||||||
|
<AssignedToPost
|
||||||
|
@assignedToUser={{this.assignedToUser}}
|
||||||
|
@assignedToGroup={{this.assignedToGroup}}
|
||||||
|
@href={{this.assignedHref}}
|
||||||
|
@post={{this.post}}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
{{/if}}
|
||||||
|
</template>
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import { hbs } from "ember-cli-htmlbars";
|
||||||
import { h } from "virtual-dom";
|
import { h } from "virtual-dom";
|
||||||
import { renderAvatar } from "discourse/helpers/user-avatar";
|
import { renderAvatar } from "discourse/helpers/user-avatar";
|
||||||
import discourseComputed from "discourse/lib/decorators";
|
import discourseComputed from "discourse/lib/decorators";
|
||||||
|
import { withSilencedDeprecations } from "discourse/lib/deprecated";
|
||||||
import getURL from "discourse/lib/get-url";
|
import getURL from "discourse/lib/get-url";
|
||||||
import { iconHTML, 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";
|
||||||
|
@ -18,7 +19,9 @@ import { i18n } from "discourse-i18n";
|
||||||
import AssignButton from "../components/assign-button";
|
import AssignButton from "../components/assign-button";
|
||||||
import BulkActionsAssignUser from "../components/bulk-actions/bulk-assign-user";
|
import BulkActionsAssignUser from "../components/bulk-actions/bulk-assign-user";
|
||||||
import EditTopicAssignments from "../components/modal/edit-topic-assignments";
|
import EditTopicAssignments from "../components/modal/edit-topic-assignments";
|
||||||
|
import PostAssignmentsDisplay from "../components/post-assignments-display";
|
||||||
import TopicLevelAssignMenu from "../components/topic-level-assign-menu";
|
import TopicLevelAssignMenu from "../components/topic-level-assign-menu";
|
||||||
|
import { assignedToGroupPath, assignedToUserPath } from "../lib/url";
|
||||||
import { extendTopicModel } from "../models/topic";
|
import { extendTopicModel } from "../models/topic";
|
||||||
|
|
||||||
const DEPENDENT_KEYS = [
|
const DEPENDENT_KEYS = [
|
||||||
|
@ -322,7 +325,10 @@ function initialize(api) {
|
||||||
}
|
}
|
||||||
|
|
||||||
api.addPostSmallActionClassesCallback((post) => {
|
api.addPostSmallActionClassesCallback((post) => {
|
||||||
if (post.actionCode.includes("assigned") && !siteSettings.assigns_public) {
|
// TODO (glimmer-post-stream): only check for .action_code once the widget code is removed
|
||||||
|
const actionCode = post.action_code || post.actionCode;
|
||||||
|
|
||||||
|
if (actionCode.includes("assigned") && !siteSettings.assigns_public) {
|
||||||
return ["private-assign"];
|
return ["private-assign"];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -344,19 +350,6 @@ function initialize(api) {
|
||||||
: {}
|
: {}
|
||||||
);
|
);
|
||||||
|
|
||||||
function assignedToUserPath(assignedToUser) {
|
|
||||||
return getURL(
|
|
||||||
siteSettings.assigns_user_url_path.replace(
|
|
||||||
"{username}",
|
|
||||||
assignedToUser.username
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function assignedToGroupPath(assignedToGroup) {
|
|
||||||
return getURL(`/g/${assignedToGroup.name}/assigned/everyone`);
|
|
||||||
}
|
|
||||||
|
|
||||||
api.modifyClass(
|
api.modifyClass(
|
||||||
"model:bookmark",
|
"model:bookmark",
|
||||||
(Superclass) =>
|
(Superclass) =>
|
||||||
|
@ -403,29 +396,6 @@ function initialize(api) {
|
||||||
api.addPostSmallActionIcon("reassigned", "user-plus");
|
api.addPostSmallActionIcon("reassigned", "user-plus");
|
||||||
api.addPostSmallActionIcon("reassigned_group", "group-plus");
|
api.addPostSmallActionIcon("reassigned_group", "group-plus");
|
||||||
|
|
||||||
api.addPostTransformCallback((transformed) => {
|
|
||||||
if (
|
|
||||||
[
|
|
||||||
"assigned",
|
|
||||||
"unassigned",
|
|
||||||
"reassigned",
|
|
||||||
"assigned_group",
|
|
||||||
"unassigned_group",
|
|
||||||
"reassigned_group",
|
|
||||||
"assigned_to_post",
|
|
||||||
"assigned_group_to_post",
|
|
||||||
"unassigned_from_post",
|
|
||||||
"unassigned_group_from_post",
|
|
||||||
"details_change",
|
|
||||||
"note_change",
|
|
||||||
"status_change",
|
|
||||||
].includes(transformed.actionCode)
|
|
||||||
) {
|
|
||||||
transformed.isSmallAction = true;
|
|
||||||
transformed.canEdit = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
api.addDiscoveryQueryParam("assigned", { replace: true, refreshModel: true });
|
api.addDiscoveryQueryParam("assigned", { replace: true, refreshModel: true });
|
||||||
|
|
||||||
api.addTagsHtmlCallback((topic, params = {}) => {
|
api.addTagsHtmlCallback((topic, params = {}) => {
|
||||||
|
@ -717,6 +687,42 @@ function initialize(api) {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
customizePost(api);
|
||||||
|
|
||||||
|
api.replaceIcon("notification.assigned", "user-plus");
|
||||||
|
|
||||||
|
api.replaceIcon(
|
||||||
|
"notification.discourse_assign.assign_group_notification",
|
||||||
|
"group-plus"
|
||||||
|
);
|
||||||
|
|
||||||
|
api.modifyClass(
|
||||||
|
"controller:preferences/notifications",
|
||||||
|
(Superclass) =>
|
||||||
|
class extends Superclass {
|
||||||
|
@action
|
||||||
|
save() {
|
||||||
|
this.saveAttrNames.push("custom_fields");
|
||||||
|
super.save(...arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
api.addKeyboardShortcut("g a", "", { path: "/my/activity/assigned" });
|
||||||
|
}
|
||||||
|
|
||||||
|
function customizePost(api) {
|
||||||
|
api.renderAfterWrapperOutlet(
|
||||||
|
"post-content-cooked-html",
|
||||||
|
PostAssignmentsDisplay
|
||||||
|
);
|
||||||
|
|
||||||
|
withSilencedDeprecations("discourse.post-stream-widget-overrides", () =>
|
||||||
|
customizeWidgetPost(api)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function customizeWidgetPost(api) {
|
||||||
api.decorateWidget("post-contents:after-cooked", (dec) => {
|
api.decorateWidget("post-contents:after-cooked", (dec) => {
|
||||||
const postModel = dec.getModel();
|
const postModel = dec.getModel();
|
||||||
if (postModel) {
|
if (postModel) {
|
||||||
|
@ -752,26 +758,145 @@ function initialize(api) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
api.replaceIcon("notification.assigned", "user-plus");
|
api.createWidget("assigned-to-post", {
|
||||||
|
html(attrs) {
|
||||||
api.replaceIcon(
|
return new RenderGlimmer(
|
||||||
"notification.discourse_assign.assign_group_notification",
|
this,
|
||||||
"group-plus"
|
"p.assigned-to",
|
||||||
);
|
hbs`
|
||||||
|
<AssignedToPost @assignedToUser={{@data.assignedToUser}} @assignedToGroup={{@data.assignedToGroup}}
|
||||||
api.modifyClass(
|
@href={{@data.href}} @post={{@data.post}} />`,
|
||||||
"controller:preferences/notifications",
|
{
|
||||||
(Superclass) =>
|
assignedToUser: attrs.post.assigned_to_user,
|
||||||
class extends Superclass {
|
assignedToGroup: attrs.post.assigned_to_group,
|
||||||
@action
|
href: attrs.href,
|
||||||
save() {
|
post: attrs.post,
|
||||||
this.saveAttrNames.push("custom_fields");
|
|
||||||
super.save(...arguments);
|
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
);
|
},
|
||||||
|
});
|
||||||
|
|
||||||
api.addKeyboardShortcut("g a", "", { path: "/my/activity/assigned" });
|
api.createWidget("assigned-to-first-post", {
|
||||||
|
html(attrs) {
|
||||||
|
const topic = attrs.topic;
|
||||||
|
const [assignedToUser, assignedToGroup, indirectlyAssignedTo] = [
|
||||||
|
topic.assigned_to_user,
|
||||||
|
topic.assigned_to_group,
|
||||||
|
topic.indirectly_assigned_to,
|
||||||
|
];
|
||||||
|
const assigneeElements = [];
|
||||||
|
|
||||||
|
const assignedHtml = (username, path, type) => {
|
||||||
|
return `<span class="assigned-to--${type}">${htmlSafe(
|
||||||
|
i18n("discourse_assign.assigned_topic_to", {
|
||||||
|
username,
|
||||||
|
path,
|
||||||
|
})
|
||||||
|
)}</span>`;
|
||||||
|
};
|
||||||
|
|
||||||
|
let displayedName = "";
|
||||||
|
if (assignedToUser) {
|
||||||
|
displayedName = !this.siteSettings.prioritize_username_in_ux
|
||||||
|
? assignedToUser.name || assignedToUser.username
|
||||||
|
: assignedToUser.username;
|
||||||
|
|
||||||
|
assigneeElements.push(
|
||||||
|
h(
|
||||||
|
"span.assignee",
|
||||||
|
new RawHtml({
|
||||||
|
html: assignedHtml(
|
||||||
|
displayedName,
|
||||||
|
assignedToUserPath(assignedToUser),
|
||||||
|
"user"
|
||||||
|
),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assignedToGroup) {
|
||||||
|
assigneeElements.push(
|
||||||
|
h(
|
||||||
|
"span.assignee",
|
||||||
|
new RawHtml({
|
||||||
|
html: assignedHtml(
|
||||||
|
assignedToGroup.name,
|
||||||
|
assignedToGroupPath(assignedToGroup),
|
||||||
|
"group"
|
||||||
|
),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indirectlyAssignedTo) {
|
||||||
|
Object.keys(indirectlyAssignedTo).map((postId) => {
|
||||||
|
const assignee = indirectlyAssignedTo[postId].assigned_to;
|
||||||
|
const postNumber = indirectlyAssignedTo[postId].post_number;
|
||||||
|
|
||||||
|
displayedName =
|
||||||
|
!this.siteSettings.prioritize_username_in_ux || !assignee.username
|
||||||
|
? assignee.name || assignee.username
|
||||||
|
: assignee.username;
|
||||||
|
|
||||||
|
assigneeElements.push(
|
||||||
|
h("span.assignee", [
|
||||||
|
h(
|
||||||
|
"a",
|
||||||
|
{
|
||||||
|
attributes: {
|
||||||
|
class: "assigned-indirectly",
|
||||||
|
href: `${topic.url}/${postNumber}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
i18n("discourse_assign.assign_post_to_multiple", {
|
||||||
|
post_number: postNumber,
|
||||||
|
username: displayedName,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isEmpty(assigneeElements)) {
|
||||||
|
return h("p.assigned-to", [
|
||||||
|
assignedToUser ? iconNode("user-plus") : iconNode("group-plus"),
|
||||||
|
assignedToUser || assignedToGroup
|
||||||
|
? ""
|
||||||
|
: h("span.assign-text", i18n("discourse_assign.assigned")),
|
||||||
|
assigneeElements,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// This won't have a direct translation in the Glimmer API as it uses can_edit from the model
|
||||||
|
// TODO (glimmer-post-stream): check the post small action component and introduce a transformer to override the
|
||||||
|
// canEdit behavior there
|
||||||
|
api.addPostTransformCallback((transformed) => {
|
||||||
|
if (
|
||||||
|
[
|
||||||
|
"assigned",
|
||||||
|
"unassigned",
|
||||||
|
"reassigned",
|
||||||
|
"assigned_group",
|
||||||
|
"unassigned_group",
|
||||||
|
"reassigned_group",
|
||||||
|
"assigned_to_post",
|
||||||
|
"assigned_group_to_post",
|
||||||
|
"unassigned_from_post",
|
||||||
|
"unassigned_group_from_post",
|
||||||
|
"details_change",
|
||||||
|
"note_change",
|
||||||
|
"status_change",
|
||||||
|
].includes(transformed.actionCode)
|
||||||
|
) {
|
||||||
|
transformed.isSmallAction = true;
|
||||||
|
transformed.canEdit = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function customizePostMenu(api) {
|
function customizePostMenu(api) {
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { getOwnerWithFallback } from "discourse/lib/get-owner";
|
||||||
|
import getURL from "discourse/lib/get-url";
|
||||||
|
|
||||||
|
export function assignedToUserPath(assignedToUser) {
|
||||||
|
const siteSettings = getOwnerWithFallback(this).lookup(
|
||||||
|
"service:site-settings"
|
||||||
|
);
|
||||||
|
|
||||||
|
return getURL(
|
||||||
|
siteSettings.assigns_user_url_path.replace(
|
||||||
|
"{username}",
|
||||||
|
assignedToUser.username
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assignedToGroupPath(assignedToGroup) {
|
||||||
|
return getURL(`/g/${assignedToGroup.name}/assigned/everyone`);
|
||||||
|
}
|
Loading…
Reference in New Issue