DEV: Modernization/cleanup (#480)
* Component template colocation * Native classes * glimmer plugin connector * `this.` in templates * `?.` operator * Merged `withPluginApi` calls * Updated deps
This commit is contained in:
parent
3ca56e82d7
commit
2bff29e919
38
Gemfile.lock
38
Gemfile.lock
|
@ -3,34 +3,42 @@ GEM
|
|||
specs:
|
||||
ast (2.4.2)
|
||||
json (2.6.3)
|
||||
parallel (1.22.1)
|
||||
parser (3.1.3.0)
|
||||
parallel (1.23.0)
|
||||
parser (3.2.2.3)
|
||||
ast (~> 2.4.1)
|
||||
prettier_print (1.2.0)
|
||||
racc
|
||||
prettier_print (1.2.1)
|
||||
racc (1.7.1)
|
||||
rainbow (3.1.1)
|
||||
regexp_parser (2.6.1)
|
||||
regexp_parser (2.8.1)
|
||||
rexml (3.2.5)
|
||||
rubocop (1.41.1)
|
||||
rubocop (1.52.1)
|
||||
json (~> 2.3)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 3.1.2.1)
|
||||
parser (>= 3.2.2.3)
|
||||
rainbow (>= 2.2.2, < 4.0)
|
||||
regexp_parser (>= 1.8, < 3.0)
|
||||
rexml (>= 3.2.5, < 4.0)
|
||||
rubocop-ast (>= 1.23.0, < 2.0)
|
||||
rubocop-ast (>= 1.28.0, < 2.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 1.4.0, < 3.0)
|
||||
rubocop-ast (1.24.0)
|
||||
parser (>= 3.1.1.0)
|
||||
rubocop-discourse (3.0.1)
|
||||
unicode-display_width (>= 2.4.0, < 3.0)
|
||||
rubocop-ast (1.29.0)
|
||||
parser (>= 3.2.1.0)
|
||||
rubocop-capybara (2.18.0)
|
||||
rubocop (~> 1.41)
|
||||
rubocop-discourse (3.2.0)
|
||||
rubocop (>= 1.1.0)
|
||||
rubocop-rspec (>= 2.0.0)
|
||||
rubocop-rspec (2.16.0)
|
||||
rubocop-factory_bot (2.23.1)
|
||||
rubocop (~> 1.33)
|
||||
ruby-progressbar (1.11.0)
|
||||
syntax_tree (5.1.0)
|
||||
rubocop-rspec (2.22.0)
|
||||
rubocop (~> 1.33)
|
||||
rubocop-capybara (~> 2.17)
|
||||
rubocop-factory_bot (~> 2.22)
|
||||
ruby-progressbar (1.13.0)
|
||||
syntax_tree (6.1.1)
|
||||
prettier_print (>= 1.2.0)
|
||||
unicode-display_width (2.3.0)
|
||||
unicode-display_width (2.4.2)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
export default {
|
||||
resource: "group",
|
||||
|
||||
map() {
|
||||
this.route("assigned", function () {
|
||||
this.route("show", { path: "/:filter" });
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
export default {
|
||||
resource: "user.userPrivateMessages",
|
||||
|
||||
map() {
|
||||
this.route("assigned", { path: "/assigned" }, function () {
|
||||
this.route("index", { path: "/" });
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
export default {
|
||||
resource: "user.userActivity",
|
||||
|
||||
map() {
|
||||
this.route("assigned");
|
||||
},
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
<div class="reviewable-filter discourse-assign-assign-to-filter">
|
||||
<label class="filter-label">{{i18n "discourse_assign.assigned_to"}}</label>
|
||||
<EmailGroupUserChooser
|
||||
@value={{additionalFilters.assigned_to}}
|
||||
@value={{this.additionalFilters.assigned_to}}
|
||||
@onChange={{action "updateAssignedTo"}}
|
||||
autocomplete="off"
|
||||
@options={{hash
|
||||
maximum=1
|
||||
fullWidthWrap=true
|
||||
filterPlaceholder=placeholderKey
|
||||
filterPlaceholder=this.placeholderKey
|
||||
includeGroups=false
|
||||
groupMembersOf=allowedGroups
|
||||
groupMembersOf=this.allowedGroups
|
||||
}}
|
||||
/>
|
||||
</div>
|
|
@ -4,7 +4,7 @@
|
|||
}}</label>
|
||||
<div class="controls">
|
||||
<EmailGroupUserChooser
|
||||
@value={{searchedTerms.assigned}}
|
||||
@value={{this.searchedTerms.assigned}}
|
||||
@onChange={{action "onChangeAssigned"}}
|
||||
@options={{hash
|
||||
maximum=1
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<label class="checkbox-label">
|
||||
<Input
|
||||
@type="checkbox"
|
||||
@checked={{readonly category.enable_unassigned_filter}}
|
||||
@checked={{readonly this.category.enable_unassigned_filter}}
|
||||
{{on "change" (action "onChangeSetting" value="target.checked")}}
|
||||
/>
|
||||
{{i18n "discourse_assign.add_unassigned_filter"}}
|
||||
|
|
|
@ -1 +1 @@
|
|||
<GroupAssignedMenuItem @group={{group}} />
|
||||
<GroupAssignedMenuItem @group={{this.group}} />
|
|
@ -1,8 +1,7 @@
|
|||
export default {
|
||||
shouldRender(args, component) {
|
||||
return (
|
||||
component.currentUser &&
|
||||
component.currentUser.can_assign &&
|
||||
component.currentUser?.can_assign &&
|
||||
args.group.can_show_assigned_tab &&
|
||||
args.group.assignment_count > 0
|
||||
);
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
<div class="control-group">
|
||||
<label class="control-label">{{i18n
|
||||
"discourse_assign.admin.groups.manage.interaction.assign"
|
||||
}}</label>
|
||||
<label for="visiblity">{{i18n
|
||||
<label class="control-label">
|
||||
{{i18n "discourse_assign.admin.groups.manage.interaction.assign"}}
|
||||
</label>
|
||||
|
||||
<label for="visiblity">
|
||||
{{i18n
|
||||
"discourse_assign.admin.groups.manage.interaction.assignable_levels.title"
|
||||
}}</label>
|
||||
}}
|
||||
</label>
|
||||
|
||||
<ComboBox
|
||||
@name="alias"
|
||||
@valueProperty="value"
|
||||
@value={{assignableLevel}}
|
||||
@content={{assignableLevelOptions}}
|
||||
@value={{this.assignableLevel}}
|
||||
@content={{this.assignableLevelOptions}}
|
||||
@class="groups-form-assignable-level"
|
||||
@onChange={{action (mut model.assignable_level)}}
|
||||
@onChange={{action (mut @outletArgs.model.assignable_level)}}
|
||||
/>
|
||||
</div>
|
|
@ -1,24 +1,17 @@
|
|||
import Component from "@glimmer/component";
|
||||
import I18n from "I18n";
|
||||
import { or } from "@ember/object/computed";
|
||||
import { defineProperty } from "@ember/object";
|
||||
|
||||
export default {
|
||||
name: "assignable-interaction-fields",
|
||||
export default class AssignableInteractionFields extends Component {
|
||||
assignableLevelOptions = [
|
||||
{ name: I18n.t("groups.alias_levels.nobody"), value: 0 },
|
||||
{ name: I18n.t("groups.alias_levels.only_admins"), value: 1 },
|
||||
{ name: I18n.t("groups.alias_levels.mods_and_admins"), value: 2 },
|
||||
{ name: I18n.t("groups.alias_levels.members_mods_and_admins"), value: 3 },
|
||||
{ name: I18n.t("groups.alias_levels.owners_mods_and_admins"), value: 4 },
|
||||
{ name: I18n.t("groups.alias_levels.everyone"), value: 99 },
|
||||
];
|
||||
|
||||
setupComponent(args, component) {
|
||||
this.assignableLevelOptions = [
|
||||
{ name: I18n.t("groups.alias_levels.nobody"), value: 0 },
|
||||
{ name: I18n.t("groups.alias_levels.only_admins"), value: 1 },
|
||||
{ name: I18n.t("groups.alias_levels.mods_and_admins"), value: 2 },
|
||||
{ name: I18n.t("groups.alias_levels.members_mods_and_admins"), value: 3 },
|
||||
{ name: I18n.t("groups.alias_levels.owners_mods_and_admins"), value: 4 },
|
||||
{ name: I18n.t("groups.alias_levels.everyone"), value: 99 },
|
||||
];
|
||||
|
||||
defineProperty(
|
||||
component,
|
||||
"assignableLevel",
|
||||
or("model.assignable_level", "assignableLevelOptions.firstObject.value")
|
||||
);
|
||||
},
|
||||
};
|
||||
get assignableLevel() {
|
||||
return this.args.outletArgs.model.assignable_level || 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{{#if currentUser.can_assign}}
|
||||
{{#if this.currentUser.can_assign}}
|
||||
<LinkTo @route="userActivity.assigned">
|
||||
{{d-icon "user-plus"}}
|
||||
{{i18n "discourse_assign.assigned"}}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<LinkTo @route="userPrivateMessages.assigned" @model={{model}}>
|
||||
<LinkTo @route="userPrivateMessages.assigned" @model={{this.model}}>
|
||||
{{d-icon "user-plus" class="glyph"}}
|
||||
{{i18n "discourse_assign.assigned"}}
|
||||
</LinkTo>
|
|
@ -1,9 +1,7 @@
|
|||
export function shouldShowAssigned(args, component) {
|
||||
const needsButton =
|
||||
component.currentUser && component.currentUser.get("can_assign");
|
||||
const needsButton = component.currentUser?.can_assign;
|
||||
return (
|
||||
needsButton &&
|
||||
(!component.get("site.mobileView") || args.model.get("isPrivateMessage"))
|
||||
needsButton && (!component.site.mobileView || args.model.isPrivateMessage)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
<RemindAssignsFrequency @user={{model}} />
|
||||
<RemindAssignsFrequency @user={{this.model}} />
|
|
@ -1,5 +1,5 @@
|
|||
export default {
|
||||
shouldRender(args, component) {
|
||||
return component.currentUser && component.currentUser.get("can_assign");
|
||||
return component.currentUser?.can_assign;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -8,17 +8,19 @@ import { isEmpty } from "@ember/utils";
|
|||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
|
||||
export default Controller.extend(ModalFunctionality, {
|
||||
topicBulkActions: controller(),
|
||||
assignSuggestions: null,
|
||||
allowedGroups: null,
|
||||
taskActions: service(),
|
||||
autofocus: not("capabilities.touch"),
|
||||
assigneeName: or("model.username", "model.group_name"),
|
||||
assigneeError: false,
|
||||
export default class AssignUser extends Controller.extend(ModalFunctionality) {
|
||||
@service taskActions;
|
||||
@controller topicBulkActions;
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
assignSuggestions = null;
|
||||
allowedGroups = null;
|
||||
assigneeError = false;
|
||||
|
||||
@not("capabilities.touch") autofocus;
|
||||
@or("model.username", "model.group_name") assigneeName;
|
||||
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
||||
this.set("allowedGroups", []);
|
||||
this.set("assigneeError", false);
|
||||
|
@ -31,17 +33,17 @@ export default Controller.extend(ModalFunctionality, {
|
|||
this.set("allowedGroups", data.assign_allowed_on_groups);
|
||||
this.set("allowedGroupsForAssignment", data.assign_allowed_for_groups);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
onShow() {
|
||||
this.set("assigneeError", false);
|
||||
},
|
||||
}
|
||||
|
||||
onClose() {
|
||||
if (this.get("model.onClose") && this.get("model.username")) {
|
||||
this.get("model.onClose")(this.get("model.username"));
|
||||
if (this.model.onClose && this.model.username) {
|
||||
this.model.onClose(this.model.username);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
bulkAction(username, note) {
|
||||
return this.topicBulkActions.performAndRefresh({
|
||||
|
@ -49,19 +51,19 @@ export default Controller.extend(ModalFunctionality, {
|
|||
username,
|
||||
note,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("siteSettings.enable_assign_status")
|
||||
statusEnabled() {
|
||||
return this.siteSettings.enable_assign_status;
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("siteSettings.assign_statuses")
|
||||
availableStatuses() {
|
||||
return this.siteSettings.assign_statuses.split("|").map((status) => {
|
||||
return { id: status, name: status };
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("siteSettings.assign_statuses", "model.status")
|
||||
status() {
|
||||
|
@ -70,22 +72,19 @@ export default Controller.extend(ModalFunctionality, {
|
|||
this.model.target.assignment_status ||
|
||||
this.siteSettings.assign_statuses.split("|")[0]
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
handleTextAreaKeydown(event) {
|
||||
if ((event.ctrlKey || event.metaKey) && event.key === "Enter") {
|
||||
this.assign();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
assign() {
|
||||
if (this.isBulkAction) {
|
||||
return this.bulkAction(
|
||||
this.get("model.username"),
|
||||
this.get("model.note")
|
||||
);
|
||||
return this.bulkAction(this.model.username, this.model.note);
|
||||
}
|
||||
|
||||
if (!this.assigneeName) {
|
||||
|
@ -95,18 +94,15 @@ export default Controller.extend(ModalFunctionality, {
|
|||
|
||||
let path = "/assign/assign";
|
||||
|
||||
if (isEmpty(this.get("model.username"))) {
|
||||
if (isEmpty(this.model.username)) {
|
||||
this.model.target.set("assigned_to_user", null);
|
||||
}
|
||||
|
||||
if (isEmpty(this.get("model.group_name"))) {
|
||||
if (isEmpty(this.model.group_name)) {
|
||||
this.model.target.set("assigned_to_group", null);
|
||||
}
|
||||
|
||||
if (
|
||||
isEmpty(this.get("model.username")) &&
|
||||
isEmpty(this.get("model.group_name"))
|
||||
) {
|
||||
if (isEmpty(this.model.username) && isEmpty(this.model.group_name)) {
|
||||
path = "/assign/unassign";
|
||||
}
|
||||
|
||||
|
@ -115,19 +111,19 @@ export default Controller.extend(ModalFunctionality, {
|
|||
return ajax(path, {
|
||||
type: "PUT",
|
||||
data: {
|
||||
username: this.get("model.username"),
|
||||
group_name: this.get("model.group_name"),
|
||||
target_id: this.get("model.target.id"),
|
||||
target_type: this.get("model.targetType"),
|
||||
note: this.get("model.note"),
|
||||
status: this.get("model.status"),
|
||||
username: this.model.username,
|
||||
group_name: this.model.group_name,
|
||||
target_id: this.model.target.id,
|
||||
target_type: this.model.targetType,
|
||||
note: this.model.note,
|
||||
status: this.model.status,
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
this.get("model.onSuccess")?.();
|
||||
this.model.onSuccess?.();
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
assignUser(name) {
|
||||
|
@ -136,27 +132,27 @@ export default Controller.extend(ModalFunctionality, {
|
|||
if (name) {
|
||||
return this.assign();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
assignUsername(selected) {
|
||||
this.setGroupOrUser(selected.firstObject);
|
||||
},
|
||||
}
|
||||
|
||||
setGroupOrUser(name) {
|
||||
this.set("assigneeError", false);
|
||||
this.set("model.allowedGroups", this.taskActions.allowedGroups);
|
||||
|
||||
if (this.allowedGroupsForAssignment.includes(name)) {
|
||||
this.setProperties({
|
||||
"model.username": null,
|
||||
"model.group_name": name,
|
||||
"model.allowedGroups": this.taskActions.allowedGroups,
|
||||
});
|
||||
} else {
|
||||
this.setProperties({
|
||||
"model.username": name,
|
||||
"model.group_name": null,
|
||||
"model.allowedGroups": this.taskActions.allowedGroups,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,22 +6,23 @@ import { inject as controller } from "@ember/controller";
|
|||
import { inject as service } from "@ember/service";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default UserTopicsList.extend({
|
||||
user: controller(),
|
||||
taskActions: service(),
|
||||
order: "",
|
||||
ascending: false,
|
||||
search: "",
|
||||
bulkSelectEnabled: false,
|
||||
selected: [],
|
||||
canBulkSelect: alias("currentUser.staff"),
|
||||
export default class GroupAssignedShow extends UserTopicsList {
|
||||
@service taskActions;
|
||||
@controller user;
|
||||
|
||||
queryParams: ["order", "ascending", "search"],
|
||||
queryParams = ["order", "ascending", "search"];
|
||||
order = "";
|
||||
ascending = false;
|
||||
search = "";
|
||||
bulkSelectEnabled = false;
|
||||
selected = [];
|
||||
|
||||
@alias("currentUser.staff") canBulkSelect;
|
||||
|
||||
_setSearchTerm(searchTerm) {
|
||||
this.set("search", searchTerm);
|
||||
this.refreshModel();
|
||||
},
|
||||
}
|
||||
|
||||
refreshModel() {
|
||||
this.set("loading", true);
|
||||
|
@ -39,21 +40,21 @@ export default UserTopicsList.extend({
|
|||
.finally(() => {
|
||||
this.set("loading", false);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
unassign(targetId, targetType = "Topic") {
|
||||
this.taskActions
|
||||
.unassign(targetId, targetType)
|
||||
.then(() => this.send("changeAssigned"));
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
reassign(topic) {
|
||||
this.taskActions
|
||||
.assign(topic)
|
||||
.set("model.onSuccess", () => this.send("changeAssigned"));
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
changeSort(sortBy) {
|
||||
|
@ -64,20 +65,20 @@ export default UserTopicsList.extend({
|
|||
this.setProperties({ order: sortBy, ascending: false });
|
||||
this.refreshModel();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
onChangeFilter(value) {
|
||||
discourseDebounce(this, this._setSearchTerm, value, INPUT_DELAY * 2);
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
toggleBulkSelect() {
|
||||
this.toggleProperty("bulkSelectEnabled");
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
refresh() {
|
||||
this.refreshModel();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,33 +6,34 @@ import discourseComputed from "discourse-common/utils/decorators";
|
|||
import discourseDebounce from "discourse-common/lib/debounce";
|
||||
import { INPUT_DELAY } from "discourse-common/config/environment";
|
||||
|
||||
export default Controller.extend({
|
||||
router: service(),
|
||||
application: controller(),
|
||||
loading: false,
|
||||
offset: 0,
|
||||
filterName: "",
|
||||
filter: "",
|
||||
export default class GroupAssigned extends Controller {
|
||||
@service router;
|
||||
@controller application;
|
||||
|
||||
loading = false;
|
||||
offset = 0;
|
||||
filterName = "";
|
||||
filter = "";
|
||||
|
||||
@discourseComputed("router.currentRoute.queryParams.order")
|
||||
order(order) {
|
||||
return order || "";
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("router.currentRoute.queryParams.ascending")
|
||||
ascending(ascending) {
|
||||
return ascending || false;
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("router.currentRoute.queryParams.search")
|
||||
search(search) {
|
||||
return search || "";
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("site.mobileView")
|
||||
isDesktop(mobileView) {
|
||||
return !mobileView;
|
||||
},
|
||||
}
|
||||
|
||||
_setFilter(filter) {
|
||||
this.set("loading", true);
|
||||
|
@ -53,7 +54,7 @@ export default Controller.extend({
|
|||
.finally(() => {
|
||||
this.set("loading", false);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
findMembers(refresh) {
|
||||
if (refresh) {
|
||||
|
@ -77,15 +78,15 @@ export default Controller.extend({
|
|||
})
|
||||
.finally(() => this.set("loading", false));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
loadMore() {
|
||||
this.findMembers();
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
onChangeFilterName(value) {
|
||||
discourseDebounce(this, this._setFilter, value, INPUT_DELAY * 2);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,23 +10,19 @@ import { iconHTML } from "discourse-common/lib/icon-library";
|
|||
import I18n from "I18n";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
|
||||
export default UserTopicsList.extend({
|
||||
user: controller(),
|
||||
taskActions: service(),
|
||||
queryParams: ["order", "ascending", "search"],
|
||||
order: "",
|
||||
ascending: false,
|
||||
search: "",
|
||||
export default class UserActivityAssigned extends UserTopicsList {
|
||||
@service taskActions;
|
||||
@controller user;
|
||||
|
||||
_setSearchTerm(searchTerm) {
|
||||
this.set("search", searchTerm);
|
||||
this.refreshModel();
|
||||
},
|
||||
queryParams = ["order", "ascending", "search"];
|
||||
order = "";
|
||||
ascending = false;
|
||||
search = "";
|
||||
|
||||
@discourseComputed("model.topics.length", "search")
|
||||
doesntHaveAssignments(topicsLength, search) {
|
||||
return !search && !topicsLength;
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed
|
||||
emptyStateBody() {
|
||||
|
@ -36,7 +32,12 @@ export default UserTopicsList.extend({
|
|||
icon: iconHTML("user-plus"),
|
||||
})
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
_setSearchTerm(searchTerm) {
|
||||
this.set("search", searchTerm);
|
||||
this.refreshModel();
|
||||
}
|
||||
|
||||
refreshModel() {
|
||||
this.set("loading", true);
|
||||
|
@ -53,21 +54,21 @@ export default UserTopicsList.extend({
|
|||
.finally(() => {
|
||||
this.set("loading", false);
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
unassign(targetId, targetType = "Topic") {
|
||||
this.taskActions
|
||||
.unassign(targetId, targetType)
|
||||
.then(() => this.send("changeAssigned"));
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
reassign(topic) {
|
||||
this.taskActions
|
||||
.assign(topic)
|
||||
.set("model.onSuccess", () => this.send("changeAssigned"));
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
changeSort(sortBy) {
|
||||
|
@ -78,10 +79,10 @@ export default UserTopicsList.extend({
|
|||
this.setProperties({ order: sortBy, ascending: false });
|
||||
this.refreshModel();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
onChangeFilter(value) {
|
||||
discourseDebounce(this, this._setSearchTerm, value, INPUT_DELAY * 2);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,23 +26,17 @@ const DEPENDENT_KEYS = [
|
|||
"topic.assigned_to_user.username",
|
||||
];
|
||||
|
||||
function titleForState(name) {
|
||||
if (name) {
|
||||
return I18n.t("discourse_assign.unassign.help", {
|
||||
username: name,
|
||||
});
|
||||
function defaultTitle(topic) {
|
||||
const username =
|
||||
topic.assigned_to_user?.username || topic.assigned_to_group?.name;
|
||||
|
||||
if (username) {
|
||||
return I18n.t("discourse_assign.unassign.help", { username });
|
||||
} else {
|
||||
return I18n.t("discourse_assign.assign.help");
|
||||
}
|
||||
}
|
||||
|
||||
function defaultTitle(topic) {
|
||||
return titleForState(
|
||||
topic.get("topic.assigned_to_user.username") ||
|
||||
topic.get("topic.assigned_to_group.name")
|
||||
);
|
||||
}
|
||||
|
||||
function includeIsAssignedOnTopic(api) {
|
||||
api.modifyClass("model:topic", {
|
||||
pluginId: PLUGIN_ID,
|
||||
|
@ -57,7 +51,7 @@ function registerTopicFooterButtons(api) {
|
|||
id: "reassign",
|
||||
|
||||
action(id) {
|
||||
if (!this.get("currentUser.can_assign")) {
|
||||
if (!this.currentUser?.can_assign) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -103,8 +97,8 @@ function registerTopicFooterButtons(api) {
|
|||
},
|
||||
|
||||
noneItem() {
|
||||
const user = this.get("topic.assigned_to_user");
|
||||
const group = this.get("topic.assigned_to_group");
|
||||
const user = this.topic.assigned_to_user;
|
||||
const group = this.topic.assigned_to_group;
|
||||
const label = I18n.t("discourse_assign.unassign.title_w_ellipsis");
|
||||
const groupLabel = I18n.t("discourse_assign.unassign.title");
|
||||
|
||||
|
@ -149,8 +143,7 @@ function registerTopicFooterButtons(api) {
|
|||
];
|
||||
if (
|
||||
this.topic.isAssigned() &&
|
||||
this.get("topic.assigned_to_user")?.username !==
|
||||
this.currentUser.username
|
||||
this.topic.assigned_to_user?.username !== this.currentUser.username
|
||||
) {
|
||||
content.push({
|
||||
id: "reassign-self",
|
||||
|
@ -176,7 +169,7 @@ function registerTopicFooterButtons(api) {
|
|||
|
||||
displayed() {
|
||||
return (
|
||||
this.get("currentUser.can_assign") &&
|
||||
this.currentUser?.can_assign &&
|
||||
!this.site.mobileView &&
|
||||
this.topic.isAssigned()
|
||||
);
|
||||
|
@ -194,16 +187,16 @@ function registerTopicFooterButtons(api) {
|
|||
},
|
||||
priority: 250,
|
||||
translatedTitle() {
|
||||
return defaultTitle(this);
|
||||
return defaultTitle(this.topic);
|
||||
},
|
||||
translatedAriaLabel() {
|
||||
return defaultTitle(this);
|
||||
return defaultTitle(this.topic);
|
||||
},
|
||||
translatedLabel() {
|
||||
return I18n.t("discourse_assign.assign.title");
|
||||
},
|
||||
action() {
|
||||
if (!this.get("currentUser.can_assign")) {
|
||||
if (!this.currentUser?.can_assign) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -238,14 +231,14 @@ function registerTopicFooterButtons(api) {
|
|||
api.registerTopicFooterButton({
|
||||
id: "unassign-mobile-header",
|
||||
translatedTitle() {
|
||||
return defaultTitle(this);
|
||||
return defaultTitle(this.topic);
|
||||
},
|
||||
translatedAriaLabel() {
|
||||
return defaultTitle(this);
|
||||
return defaultTitle(this.topic);
|
||||
},
|
||||
translatedLabel() {
|
||||
const user = this.get("topic.assigned_to_user");
|
||||
const group = this.get("topic.assigned_to_group");
|
||||
const user = this.topic.assigned_to_user;
|
||||
const group = this.topic.assigned_to_group;
|
||||
const label = I18n.t("discourse_assign.assigned_to_w_ellipsis");
|
||||
|
||||
if (user) {
|
||||
|
@ -280,10 +273,10 @@ function registerTopicFooterButtons(api) {
|
|||
return "user-times";
|
||||
},
|
||||
translatedTitle() {
|
||||
return defaultTitle(this);
|
||||
return defaultTitle(this.topic);
|
||||
},
|
||||
translatedAriaLabel() {
|
||||
return defaultTitle(this);
|
||||
return defaultTitle(this.topic);
|
||||
},
|
||||
translatedLabel() {
|
||||
const label = I18n.t("discourse_assign.unassign.title");
|
||||
|
@ -293,7 +286,7 @@ function registerTopicFooterButtons(api) {
|
|||
);
|
||||
},
|
||||
action() {
|
||||
if (!this.get("currentUser.can_assign")) {
|
||||
if (!this.currentUser?.can_assign) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -341,7 +334,7 @@ function registerTopicFooterButtons(api) {
|
|||
);
|
||||
},
|
||||
action() {
|
||||
if (!this.get("currentUser.can_assign")) {
|
||||
if (!this.currentUser?.can_assign) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -366,8 +359,7 @@ function registerTopicFooterButtons(api) {
|
|||
this.site.mobileView &&
|
||||
this.currentUser?.can_assign &&
|
||||
this.topic.isAssigned() &&
|
||||
this.get("topic.assigned_to_user")?.username !==
|
||||
this.currentUser.username
|
||||
this.topic.assigned_to_user?.username !== this.currentUser.username
|
||||
);
|
||||
},
|
||||
});
|
||||
|
@ -391,7 +383,7 @@ function registerTopicFooterButtons(api) {
|
|||
);
|
||||
},
|
||||
action() {
|
||||
if (!this.get("currentUser.can_assign")) {
|
||||
if (!this.currentUser?.can_assign) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -611,13 +603,13 @@ function initialize(api) {
|
|||
};
|
||||
|
||||
let assignedToIndirectly;
|
||||
if (topic.get("indirectly_assigned_to")) {
|
||||
assignedToIndirectly = Object.entries(
|
||||
topic.get("indirectly_assigned_to")
|
||||
).map(([key, value]) => {
|
||||
value.assigned_to.assignedToPostId = key;
|
||||
return value;
|
||||
});
|
||||
if (topic.indirectly_assigned_to) {
|
||||
assignedToIndirectly = Object.entries(topic.indirectly_assigned_to).map(
|
||||
([key, value]) => {
|
||||
value.assigned_to.assignedToPostId = key;
|
||||
return value;
|
||||
}
|
||||
);
|
||||
} else {
|
||||
assignedToIndirectly = [];
|
||||
}
|
||||
|
@ -821,7 +813,7 @@ function initialize(api) {
|
|||
unsubscribe() {
|
||||
this._super(...arguments);
|
||||
|
||||
if (!this.get("model.id")) {
|
||||
if (!this.model?.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -899,7 +891,7 @@ export default {
|
|||
SearchAdvancedOptions.reopen({
|
||||
updateSearchTermForAssignedUsername() {
|
||||
const match = this.filterBlocks(REGEXP_USERNAME_PREFIX);
|
||||
const userFilter = this.get("searchedTerms.assigned");
|
||||
const userFilter = this.searchedTerms?.assigned;
|
||||
let searchTerm = this.searchTerm || "";
|
||||
let keyword = "assigned";
|
||||
|
||||
|
@ -944,23 +936,20 @@ export default {
|
|||
});
|
||||
}
|
||||
|
||||
withPluginApi("0.13.0", (api) => includeIsAssignedOnTopic(api));
|
||||
withPluginApi("0.11.0", (api) => initialize(api));
|
||||
withPluginApi("0.8.28", (api) => registerTopicFooterButtons(api));
|
||||
withPluginApi("0.13.0", (api) => {
|
||||
includeIsAssignedOnTopic(api);
|
||||
initialize(api);
|
||||
registerTopicFooterButtons(api);
|
||||
|
||||
withPluginApi("0.11.7", (api) => {
|
||||
api.addSearchSuggestion("in:assigned");
|
||||
api.addSearchSuggestion("in:unassigned");
|
||||
});
|
||||
|
||||
withPluginApi("0.12.2", (api) => {
|
||||
api.addGroupPostSmallActionCode("assigned_group");
|
||||
api.addGroupPostSmallActionCode("reassigned_group");
|
||||
api.addGroupPostSmallActionCode("unassigned_group");
|
||||
api.addGroupPostSmallActionCode("assigned_group_to_post");
|
||||
api.addGroupPostSmallActionCode("unassigned_group_from_post");
|
||||
});
|
||||
withPluginApi("0.12.3", (api) => {
|
||||
|
||||
api.addUserSearchOption("assignableGroups");
|
||||
});
|
||||
},
|
||||
|
|
|
@ -1,49 +1,43 @@
|
|||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { findOrResetCachedTopicList } from "discourse/lib/cached-topic-list";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
export default class GroupAssignedShow extends DiscourseRoute {
|
||||
beforeModel(transition) {
|
||||
if (!(transition.hasOwnProperty("from") && transition.from)) {
|
||||
return;
|
||||
}
|
||||
if (transition.from.localName === "show") {
|
||||
if (transition.from?.localName === "show") {
|
||||
this.session.set("topicListScrollPosition", 1);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
model(params) {
|
||||
let filter = null;
|
||||
if (
|
||||
["everyone", this.modelFor("group").get("name")].includes(params.filter)
|
||||
) {
|
||||
filter = `topics/group-topics-assigned/${this.modelFor("group").get(
|
||||
"name"
|
||||
)}`;
|
||||
let filter;
|
||||
if (["everyone", this.modelFor("group").name].includes(params.filter)) {
|
||||
filter = `topics/group-topics-assigned/${this.modelFor("group").name}`;
|
||||
} else {
|
||||
filter = `topics/messages-assigned/${params.filter}`;
|
||||
}
|
||||
const lastTopicList = findOrResetCachedTopicList(this.session, filter);
|
||||
return lastTopicList
|
||||
? lastTopicList
|
||||
: this.store.findFiltered("topicList", {
|
||||
filter,
|
||||
params: {
|
||||
order: params.order,
|
||||
ascending: params.ascending,
|
||||
search: params.search,
|
||||
direct: params.filter !== "everyone",
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
return (
|
||||
findOrResetCachedTopicList(this.session, filter) ||
|
||||
this.store.findFiltered("topicList", {
|
||||
filter,
|
||||
params: {
|
||||
order: params.order,
|
||||
ascending: params.ascending,
|
||||
search: params.search,
|
||||
direct: params.filter !== "everyone",
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
setupController(controller, model) {
|
||||
controller.setProperties({
|
||||
model,
|
||||
search: this.currentModel.params.search,
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
renderTemplate() {
|
||||
this.render("group-topics-list");
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@ import DiscourseRoute from "discourse/routes/discourse";
|
|||
import { ajax } from "discourse/lib/ajax";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default DiscourseRoute.extend({
|
||||
export default class GroupAssigned extends DiscourseRoute {
|
||||
model() {
|
||||
return ajax(`/assign/members/${this.modelFor("group").get("name")}`);
|
||||
},
|
||||
return ajax(`/assign/members/${this.modelFor("group").name}`);
|
||||
}
|
||||
|
||||
setupController(controller, model) {
|
||||
controller.setProperties({
|
||||
|
@ -19,7 +19,7 @@ export default DiscourseRoute.extend({
|
|||
});
|
||||
|
||||
controller.findMembers(true);
|
||||
},
|
||||
}
|
||||
|
||||
redirect(model, transition) {
|
||||
if (transition.to.params.hasOwnProperty("filter")) {
|
||||
|
@ -27,10 +27,10 @@ export default DiscourseRoute.extend({
|
|||
} else {
|
||||
this.transitionTo("group.assigned.show", "everyone");
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
changeAssigned() {
|
||||
this.refresh();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,19 +3,19 @@ import UserTopicListRoute from "discourse/routes/user-topic-list";
|
|||
import cookie from "discourse/lib/cookie";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default UserTopicListRoute.extend({
|
||||
templateName: "user-activity-assigned",
|
||||
controllerName: "user-activity-assigned",
|
||||
export default class UserActivityAssigned extends UserTopicListRoute {
|
||||
templateName = "user-activity-assigned";
|
||||
controllerName = "user-activity-assigned";
|
||||
|
||||
userActionType: 16,
|
||||
noContentHelpKey: "discourse_assigns.no_assigns",
|
||||
userActionType = 16;
|
||||
noContentHelpKey = "discourse_assigns.no_assigns";
|
||||
|
||||
beforeModel() {
|
||||
if (!this.currentUser) {
|
||||
cookie("destination_url", window.location.href);
|
||||
this.transitionTo("login");
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
model(params) {
|
||||
return this.store.findFiltered("topicList", {
|
||||
|
@ -29,14 +29,14 @@ export default UserTopicListRoute.extend({
|
|||
search: params.search,
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
titleToken() {
|
||||
return I18n.t("discourse_assign.assigned");
|
||||
},
|
||||
}
|
||||
|
||||
@action
|
||||
changeAssigned() {
|
||||
this.refresh();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<div class="assigned-to-user">
|
||||
{{avatar @user imageSize="small"}}
|
||||
|
||||
<span class="assigned-username">
|
||||
{{@user.username}}
|
||||
</span>
|
||||
|
||||
{{yield}}
|
||||
</div>
|
|
@ -1,5 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ["assigned-to-user"],
|
||||
});
|
|
@ -0,0 +1,86 @@
|
|||
{{!
|
||||
The `~` syntax strip spaces between the elements, making it produce
|
||||
`<a class=topic-post-badges>Some text</a><span class=topic-post-badges>`,
|
||||
with no space between them.
|
||||
This causes the topic-post-badge to be considered the same word as "text"
|
||||
at the end of the link, preventing it from line wrapping onto its own line.
|
||||
}}
|
||||
{{#if this.bulkSelectEnabled}}
|
||||
<td class="bulk-select topic-list-data">
|
||||
<input type="checkbox" class="bulk-select" />
|
||||
</td>
|
||||
{{/if}}
|
||||
<td class="main-link clearfix topic-list-data" colspan="1">
|
||||
<span class="link-top-line">
|
||||
{{~raw "topic-status" topic=this.topic}}
|
||||
{{~#if this.isPrivateMessage}}
|
||||
{{~d-icon "envelope" class="private-message-icon"}}
|
||||
{{~/if}}
|
||||
{{~topic-link this.topic class="raw-link raw-topic-link"}}
|
||||
{{~#if this.topic.featured_link}}
|
||||
{{~topic-featured-link this.topic}}
|
||||
{{~/if}}
|
||||
{{~#if this.showTopicPostBadges}}
|
||||
{{~raw
|
||||
"topic-post-badges"
|
||||
unread=this.topic.unread
|
||||
unseen=this.topic.unseen
|
||||
url=this.topic.lastUnreadUrl
|
||||
newDotText=this.newDotText
|
||||
}}
|
||||
{{~/if}}
|
||||
</span>
|
||||
<div class="link-bottom-line">
|
||||
{{#if (or (not this.hideCategory) (not this.topic.isPinnedUncategorized))}}
|
||||
{{category-link this.topic.category}}
|
||||
{{/if}}
|
||||
{{discourse-tags this.topic mode="list" tagsForUser=this.tagsForUser}}
|
||||
{{raw
|
||||
"list/action-list"
|
||||
topic=this.topic
|
||||
postNumbers=this.topic.liked_post_numbers
|
||||
className="likes"
|
||||
icon="heart"
|
||||
}}
|
||||
</div>
|
||||
{{#if this.expandPinned}}
|
||||
{{raw "list/topic-excerpt" topic=this.topic}}
|
||||
{{/if}}
|
||||
</td>
|
||||
|
||||
{{#if this.showPosters}}
|
||||
{{raw "list/posters-column" posters=this.topic.featuredUsers}}
|
||||
{{/if}}
|
||||
|
||||
{{raw "list/posts-count-column" topic=this.topic}}
|
||||
|
||||
<td class="num views {{this.topic.viewsHeat}} topic-list-data">{{number
|
||||
this.topic.views
|
||||
numberKey="views_long"
|
||||
}}</td>
|
||||
{{raw
|
||||
"list/activity-column"
|
||||
topic=this.topic
|
||||
class="num topic-list-data"
|
||||
tagName="td"
|
||||
}}
|
||||
<td class="topic-list-data">
|
||||
{{#if this.topic.assigned_to_user}}
|
||||
<AssignActionsDropdown
|
||||
@topic={{this.topic}}
|
||||
@assignee={{this.topic.assigned_to_user.username}}
|
||||
@unassign={{this.unassign}}
|
||||
@reassign={{this.reassign}}
|
||||
/>
|
||||
{{else if this.topic.assigned_to_group}}
|
||||
<AssignActionsDropdown
|
||||
@topic={{this.topic}}
|
||||
@assignee={{this.topic.assigned_to_group.name}}
|
||||
@group={{true}}
|
||||
@unassign={{this.unassign}}
|
||||
@reassign={{this.reassign}}
|
||||
/>
|
||||
{{else}}
|
||||
<AssignActionsDropdown @topic={{this.topic}} @unassign={{this.unassign}} />
|
||||
{{/if}}
|
||||
</td>
|
|
@ -1,7 +1,8 @@
|
|||
import TopicListItem from "discourse/components/topic-list-item";
|
||||
import { equal } from "@ember/object/computed";
|
||||
|
||||
export default TopicListItem.extend({
|
||||
classNames: ["assigned-topic-list-item"],
|
||||
isPrivateMessage: equal("topic.archetype", "private_message"),
|
||||
});
|
||||
export default class AssignedTopicListItem extends TopicListItem {
|
||||
classNames = ["assigned-topic-list-item"];
|
||||
|
||||
@equal("topic.archetype", "private_message") isPrivateMessage;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
{{#unless this.skipHeader}}
|
||||
<thead class="topic-list-header assigned-topic-list-header">
|
||||
{{raw
|
||||
"topic-list-header"
|
||||
canBulkSelect=this.canBulkSelect
|
||||
canDoBulkActions=this.canDoBulkActions
|
||||
toggleInTitle=this.toggleInTitle
|
||||
hideCategory=this.hideCategory
|
||||
showPosters=true
|
||||
showLikes=this.showLikes
|
||||
showOpLikes=this.showOpLikes
|
||||
order=this.order
|
||||
ascending=this.ascending
|
||||
sortable=this.sortable
|
||||
listTitle=this.listTitle
|
||||
bulkSelectEnabled=this.bulkSelectEnabled
|
||||
}}
|
||||
</thead>
|
||||
{{/unless}}
|
||||
|
||||
<tbody class="topic-list-body assigned-topic-list-body">
|
||||
{{#each this.filteredTopics as |topic|}}
|
||||
<AssignedTopicListItem
|
||||
@topic={{topic}}
|
||||
@bulkSelectEnabled={{this.bulkSelectEnabled}}
|
||||
@showTopicPostBadges={{this.showTopicPostBadges}}
|
||||
@hideCategory={{this.hideCategory}}
|
||||
@showPosters={{true}}
|
||||
@showLikes={{this.showLikes}}
|
||||
@showOpLikes={{this.showOpLikes}}
|
||||
@expandGloballyPinned={{this.expandGloballyPinned}}
|
||||
@expandAllPinned={{this.expandAllPinned}}
|
||||
@lastVisitedTopic={{this.lastVisitedTopic}}
|
||||
@selected={{this.selected}}
|
||||
@tagsForUser={{this.tagsForUser}}
|
||||
@unassign={{this.unassign}}
|
||||
@reassign={{this.reassign}}
|
||||
/>
|
||||
|
||||
{{raw
|
||||
"list/visited-line"
|
||||
lastVisitedTopic=this.lastVisitedTopic
|
||||
topic=topic
|
||||
}}
|
||||
{{/each}}
|
||||
</tbody>
|
|
@ -1,3 +1,3 @@
|
|||
import EmailGroupUserChooserRow from "select-kit/components/email-group-user-chooser-row";
|
||||
|
||||
export default EmailGroupUserChooserRow.extend();
|
||||
export default class AssigneeChooserRow extends EmailGroupUserChooserRow {}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import EmailGroupUserChooser from "select-kit/components/email-group-user-chooser";
|
||||
|
||||
export default EmailGroupUserChooser.extend({
|
||||
export default class AssigneeChooser extends EmailGroupUserChooser {
|
||||
modifyComponentForRow() {
|
||||
return "assignee-chooser-row";
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<ConditionalLoadingSpinner @condition={{this.loading}}>
|
||||
{{#if this.hasIncoming}}
|
||||
<div class="show-mores">
|
||||
<a href class="alert alert-info clickable" {{action this.showInserted}}>
|
||||
<CountI18n
|
||||
@key="topic_count_"
|
||||
@suffix="latest"
|
||||
@count={{this.incomingCount}}
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if this.topics}}
|
||||
<AssignedTopicList
|
||||
@showPosters={{this.showPosters}}
|
||||
@hideCategory={{this.hideCategory}}
|
||||
@topics={{this.topics}}
|
||||
@expandExcerpts={{this.expandExcerpts}}
|
||||
@bulkSelectEnabled={{this.bulkSelectEnabled}}
|
||||
@canBulkSelect={{this.canBulkSelect}}
|
||||
@bulkSelectAction={{this.bulkSelectAction}}
|
||||
@selected={{this.selected}}
|
||||
@skipHeader={{this.skipHeader}}
|
||||
@tagsForUser={{this.tagsForUser}}
|
||||
@changeSort={{this.changeSort}}
|
||||
@toggleBulkSelect={{this.toggleBulkSelect}}
|
||||
@unassign={{this.unassign}}
|
||||
@reassign={{this.reassign}}
|
||||
@onScroll={{this.onScroll}}
|
||||
@scrollOnLoad={{this.scrollOnLoad}}
|
||||
/>
|
||||
{{else}}
|
||||
{{#unless this.loadingMore}}
|
||||
<div class="alert alert-info">
|
||||
{{i18n "choose_topic.none_found"}}
|
||||
</div>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
</ConditionalLoadingSpinner>
|
|
@ -7,21 +7,21 @@ function assignIfEqual(topic, data) {
|
|||
}
|
||||
}
|
||||
|
||||
export default Component.extend({
|
||||
export default class FlaggedTopicListener extends Component {
|
||||
didInsertElement() {
|
||||
this._super();
|
||||
super.didInsertElement(...arguments);
|
||||
|
||||
this.messageBus.subscribe("/staff/topic-assignment", (data) => {
|
||||
let flaggedTopics = this.flaggedTopics;
|
||||
if (flaggedTopics) {
|
||||
flaggedTopics.forEach((ft) => assignIfEqual(ft.topic, data));
|
||||
if (this.flaggedTopics) {
|
||||
this.flaggedTopics.forEach((ft) => assignIfEqual(ft.topic, data));
|
||||
} else {
|
||||
assignIfEqual(this.topic, data);
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
willDestroyElement() {
|
||||
this._super();
|
||||
super.willDestroyElement(...arguments);
|
||||
this.messageBus.unsubscribe("/staff/topic-assignment");
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<li>
|
||||
{{#if @showAvatar}}
|
||||
<LinkTo
|
||||
@route="group.assigned.show"
|
||||
@model={{@filter.username_lower}}
|
||||
@query={{hash order=@order ascending=@ascending search=@search}}
|
||||
>
|
||||
<div class="assign-image">
|
||||
<a
|
||||
href={{@filter.userPath}}
|
||||
data-user-card={{@filter.username}}
|
||||
>{{avatar filter imageSize="large"}}</a>
|
||||
</div>
|
||||
|
||||
<div class="assign-names">
|
||||
<div class="assign-username">{{format-username @filter.username}}</div>
|
||||
<div class="assign-name">{{@filter.name}}</div>
|
||||
</div>
|
||||
|
||||
<div class="assign-count">
|
||||
{{@filter.assignments_count}}
|
||||
</div>
|
||||
</LinkTo>
|
||||
{{else if @groupName}}
|
||||
<LinkTo
|
||||
@route="group.assigned.show"
|
||||
@model={{@filter}}
|
||||
@query={{hash order=@order ascending=@ascending search=@search}}
|
||||
>
|
||||
<div class="assign-image">
|
||||
{{d-icon "group-plus"}}
|
||||
</div>
|
||||
<div class="assign-names">
|
||||
<div class="assign-username">{{@groupName}}</div>
|
||||
</div>
|
||||
|
||||
<div class="assign-count">
|
||||
{{@assignmentCount}}
|
||||
</div>
|
||||
</LinkTo>
|
||||
{{else}}
|
||||
<LinkTo
|
||||
@route="group.assigned.show"
|
||||
@model={{@filter}}
|
||||
@query={{hash order=@order ascending=@ascending search=@search}}
|
||||
>
|
||||
<div class="assign-everyone">
|
||||
{{i18n "discourse_assign.group_everyone"}}
|
||||
</div>
|
||||
<div class="assign-count">
|
||||
{{@assignmentCount}}
|
||||
</div>
|
||||
</LinkTo>
|
||||
{{/if}}
|
||||
</li>
|
|
@ -1,5 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "li",
|
||||
});
|
|
@ -1,4 +1,4 @@
|
|||
<LinkTo @route="group.assigned">
|
||||
{{d-icon "group-plus" class="glyph"}}{{i18n "discourse_assign.assigned"}}
|
||||
({{group.assignment_count}})
|
||||
({{@group.assignment_count}})
|
||||
</LinkTo>
|
|
@ -1,5 +0,0 @@
|
|||
import Component from "@ember/component";
|
||||
|
||||
export default Component.extend({
|
||||
tagName: "",
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
{{#if this.siteSettings.assign_enabled}}
|
||||
<div class="controls controls-dropdown">
|
||||
<label>{{i18n "discourse_assign.reminders_frequency.description"}}</label>
|
||||
<ComboBox
|
||||
@id="remind-assigns-frequency"
|
||||
@valueProperty="value"
|
||||
@content={{this.availableFrequencies}}
|
||||
@value={{this.selectedFrequency}}
|
||||
@onChange={{action
|
||||
(mut this.user.custom_fields.remind_assigns_frequency)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
|
@ -2,7 +2,7 @@ import Component from "@ember/component";
|
|||
import I18n from "I18n";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Component.extend({
|
||||
export default class RemindAssignsFrequency extends Component {
|
||||
@discourseComputed(
|
||||
"user.custom_fields.remind_assigns_frequency",
|
||||
"siteSettings.remind_assigns_frequency"
|
||||
|
@ -17,16 +17,14 @@ export default Component.extend({
|
|||
}
|
||||
|
||||
return siteDefaultAssignsFrequency;
|
||||
},
|
||||
}
|
||||
|
||||
@discourseComputed("user.reminders_frequency")
|
||||
availableFrequencies(userRemindersFrequency) {
|
||||
return userRemindersFrequency.map((freq) => {
|
||||
return {
|
||||
name: I18n.t(freq.name),
|
||||
value: freq.value,
|
||||
selected: false,
|
||||
};
|
||||
});
|
||||
},
|
||||
});
|
||||
return userRemindersFrequency.map((freq) => ({
|
||||
name: I18n.t(freq.name),
|
||||
value: freq.value,
|
||||
selected: false,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import Service from "@ember/service";
|
|||
import { ajax } from "discourse/lib/ajax";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
|
||||
export default Service.extend({
|
||||
export default class TaskActions extends Service {
|
||||
i18nSuffix(targetType) {
|
||||
switch (targetType) {
|
||||
case "Post":
|
||||
|
@ -10,7 +10,7 @@ export default Service.extend({
|
|||
case "Topic":
|
||||
return "_modal";
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
unassign(targetId, targetType = "Topic") {
|
||||
return ajax("/assign/unassign", {
|
||||
|
@ -20,7 +20,7 @@ export default Service.extend({
|
|||
target_type: targetType,
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
assign(target, options = { isAssigned: false, targetType: "Topic" }) {
|
||||
return showModal("assign-user", {
|
||||
|
@ -37,7 +37,7 @@ export default Service.extend({
|
|||
status: target.assignment_status,
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
reassignUserToTopic(user, target, targetType = "Topic") {
|
||||
return ajax("/assign/assign", {
|
||||
|
@ -49,5 +49,5 @@ export default Service.extend({
|
|||
status: target.assignment_status,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
{{avatar user imageSize="small"}}
|
||||
<span class="assigned-username">
|
||||
{{user.username}}
|
||||
</span>
|
||||
{{yield}}
|
|
@ -1,88 +0,0 @@
|
|||
{{!
|
||||
The `~` syntax strip spaces between the elements, making it produce
|
||||
`<a class=topic-post-badges>Some text</a><span class=topic-post-badges>`,
|
||||
with no space between them.
|
||||
This causes the topic-post-badge to be considered the same word as "text"
|
||||
at the end of the link, preventing it from line wrapping onto its own line.
|
||||
}}
|
||||
{{#if bulkSelectEnabled}}
|
||||
<td class="bulk-select topic-list-data">
|
||||
<input type="checkbox" class="bulk-select" />
|
||||
</td>
|
||||
{{/if}}
|
||||
<td class="main-link clearfix topic-list-data" colspan="1">
|
||||
<span class="link-top-line">
|
||||
{{~raw "topic-status" topic=topic}}
|
||||
{{~#if isPrivateMessage}}
|
||||
{{~d-icon "envelope" class="private-message-icon"}}
|
||||
{{~/if}}
|
||||
{{~topic-link topic class="raw-link raw-topic-link"}}
|
||||
{{~#if topic.featured_link}}
|
||||
{{~topic-featured-link topic}}
|
||||
{{~/if}}
|
||||
{{~#if showTopicPostBadges}}
|
||||
{{~raw
|
||||
"topic-post-badges"
|
||||
unread=topic.unread
|
||||
unseen=topic.unseen
|
||||
url=topic.lastUnreadUrl
|
||||
newDotText=newDotText
|
||||
}}
|
||||
{{~/if}}
|
||||
</span>
|
||||
<div class="link-bottom-line">
|
||||
{{#unless hideCategory}}
|
||||
{{#unless topic.isPinnedUncategorized}}
|
||||
{{category-link topic.category}}
|
||||
{{/unless}}
|
||||
{{/unless}}
|
||||
{{discourse-tags topic mode="list" tagsForUser=tagsForUser}}
|
||||
{{raw
|
||||
"list/action-list"
|
||||
topic=topic
|
||||
postNumbers=topic.liked_post_numbers
|
||||
className="likes"
|
||||
icon="heart"
|
||||
}}
|
||||
</div>
|
||||
{{#if expandPinned}}
|
||||
{{raw "list/topic-excerpt" topic=topic}}
|
||||
{{/if}}
|
||||
</td>
|
||||
|
||||
{{#if showPosters}}
|
||||
{{raw "list/posters-column" posters=topic.featuredUsers}}
|
||||
{{/if}}
|
||||
|
||||
{{raw "list/posts-count-column" topic=topic}}
|
||||
|
||||
<td class="num views {{topic.viewsHeat}} topic-list-data">{{number
|
||||
topic.views
|
||||
numberKey="views_long"
|
||||
}}</td>
|
||||
{{raw
|
||||
"list/activity-column"
|
||||
topic=topic
|
||||
class="num topic-list-data"
|
||||
tagName="td"
|
||||
}}
|
||||
<td class="topic-list-data">
|
||||
{{#if topic.assigned_to_user}}
|
||||
<AssignActionsDropdown
|
||||
@topic={{topic}}
|
||||
@assignee={{topic.assigned_to_user.username}}
|
||||
@unassign={{unassign}}
|
||||
@reassign={{reassign}}
|
||||
/>
|
||||
{{else if topic.assigned_to_group}}
|
||||
<AssignActionsDropdown
|
||||
@topic={{topic}}
|
||||
@assignee={{topic.assigned_to_group.name}}
|
||||
@group={{true}}
|
||||
@unassign={{unassign}}
|
||||
@reassign={{reassign}}
|
||||
/>
|
||||
{{else}}
|
||||
<AssignActionsDropdown @topic={{topic}} @unassign={{unassign}} />
|
||||
{{/if}}
|
||||
</td>
|
|
@ -1,42 +0,0 @@
|
|||
{{#unless skipHeader}}
|
||||
<thead class="topic-list-header assigned-topic-list-header">
|
||||
{{raw
|
||||
"topic-list-header"
|
||||
canBulkSelect=canBulkSelect
|
||||
canDoBulkActions=canDoBulkActions
|
||||
toggleInTitle=toggleInTitle
|
||||
hideCategory=hideCategory
|
||||
showPosters=true
|
||||
showLikes=showLikes
|
||||
showOpLikes=showOpLikes
|
||||
order=order
|
||||
ascending=ascending
|
||||
sortable=sortable
|
||||
listTitle=listTitle
|
||||
bulkSelectEnabled=bulkSelectEnabled
|
||||
}}
|
||||
</thead>
|
||||
{{/unless}}
|
||||
|
||||
<tbody class="topic-list-body assigned-topic-list-body">
|
||||
{{#each filteredTopics as |topic|}}
|
||||
<AssignedTopicListItem
|
||||
@topic={{topic}}
|
||||
@bulkSelectEnabled={{bulkSelectEnabled}}
|
||||
@showTopicPostBadges={{showTopicPostBadges}}
|
||||
@hideCategory={{hideCategory}}
|
||||
@showPosters={{true}}
|
||||
@showLikes={{showLikes}}
|
||||
@showOpLikes={{showOpLikes}}
|
||||
@expandGloballyPinned={{expandGloballyPinned}}
|
||||
@expandAllPinned={{expandAllPinned}}
|
||||
@lastVisitedTopic={{lastVisitedTopic}}
|
||||
@selected={{selected}}
|
||||
@tagsForUser={{tagsForUser}}
|
||||
@unassign={{unassign}}
|
||||
@reassign={{reassign}}
|
||||
/>
|
||||
|
||||
{{raw "list/visited-line" lastVisitedTopic=lastVisitedTopic topic=topic}}
|
||||
{{/each}}
|
||||
</tbody>
|
|
@ -1,40 +0,0 @@
|
|||
<ConditionalLoadingSpinner @condition={{loading}}>
|
||||
{{#if hasIncoming}}
|
||||
<div class="show-mores">
|
||||
<a href class="alert alert-info clickable" {{action showInserted}}>
|
||||
<CountI18n
|
||||
@key="topic_count_"
|
||||
@suffix="latest"
|
||||
@count={{incomingCount}}
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if topics}}
|
||||
<AssignedTopicList
|
||||
@showPosters={{showPosters}}
|
||||
@hideCategory={{hideCategory}}
|
||||
@topics={{topics}}
|
||||
@expandExcerpts={{expandExcerpts}}
|
||||
@bulkSelectEnabled={{bulkSelectEnabled}}
|
||||
@canBulkSelect={{canBulkSelect}}
|
||||
@bulkSelectAction={{bulkSelectAction}}
|
||||
@selected={{selected}}
|
||||
@skipHeader={{skipHeader}}
|
||||
@tagsForUser={{tagsForUser}}
|
||||
@changeSort={{changeSort}}
|
||||
@toggleBulkSelect={{toggleBulkSelect}}
|
||||
@unassign={{unassign}}
|
||||
@reassign={{reassign}}
|
||||
@onScroll={{onScroll}}
|
||||
@scrollOnLoad={{scrollOnLoad}}
|
||||
/>
|
||||
{{else}}
|
||||
{{#unless loadingMore}}
|
||||
<div class="alert alert-info">
|
||||
{{i18n "choose_topic.none_found"}}
|
||||
</div>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
</ConditionalLoadingSpinner>
|
|
@ -1,53 +0,0 @@
|
|||
{{#if showAvatar}}
|
||||
<LinkTo
|
||||
@route="group.assigned.show"
|
||||
@model={{filter.username_lower}}
|
||||
@query={{hash order=order ascending=ascending search=search}}
|
||||
>
|
||||
<div class="assign-image">
|
||||
<a href={{filter.userPath}} data-user-card={{filter.username}}>{{avatar
|
||||
filter
|
||||
imageSize="large"
|
||||
}}</a>
|
||||
</div>
|
||||
|
||||
<div class="assign-names">
|
||||
<div class="assign-username">{{format-username filter.username}}</div>
|
||||
<div class="assign-name">{{filter.name}}</div>
|
||||
</div>
|
||||
|
||||
<div class="assign-count">
|
||||
{{filter.assignments_count}}
|
||||
</div>
|
||||
</LinkTo>
|
||||
{{else if groupName}}
|
||||
<LinkTo
|
||||
@route="group.assigned.show"
|
||||
@model={{filter}}
|
||||
@query={{hash order=order ascending=ascending search=search}}
|
||||
>
|
||||
<div class="assign-image">
|
||||
{{d-icon "group-plus"}}
|
||||
</div>
|
||||
<div class="assign-names">
|
||||
<div class="assign-username">{{groupName}}</div>
|
||||
</div>
|
||||
|
||||
<div class="assign-count">
|
||||
{{assignmentCount}}
|
||||
</div>
|
||||
</LinkTo>
|
||||
{{else}}
|
||||
<LinkTo
|
||||
@route="group.assigned.show"
|
||||
@model={{filter}}
|
||||
@query={{hash order=order ascending=ascending search=search}}
|
||||
>
|
||||
<div class="assign-everyone">
|
||||
{{i18n "discourse_assign.group_everyone"}}
|
||||
</div>
|
||||
<div class="assign-count">
|
||||
{{assignmentCount}}
|
||||
</div>
|
||||
</LinkTo>
|
||||
{{/if}}
|
|
@ -1,12 +0,0 @@
|
|||
{{#if siteSettings.assign_enabled}}
|
||||
<div class="controls controls-dropdown">
|
||||
<label>{{i18n "discourse_assign.reminders_frequency.description"}}</label>
|
||||
<ComboBox
|
||||
@id="remind-assigns-frequency"
|
||||
@valueProperty="value"
|
||||
@content={{availableFrequencies}}
|
||||
@value={{selectedFrequency}}
|
||||
@onChange={{action (mut user.custom_fields.remind_assigns_frequency)}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
|
@ -2,7 +2,7 @@
|
|||
<div class="inline-form full-width">
|
||||
<Input
|
||||
class="no-blur"
|
||||
@value={{readonly search}}
|
||||
@value={{readonly this.search}}
|
||||
placeholder={{i18n "discourse_assign.topic_search_placeholder"}}
|
||||
autocomplete="off"
|
||||
@type="search"
|
||||
|
@ -10,31 +10,31 @@
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<LoadMore
|
||||
@class="paginated-topics-list"
|
||||
@selector=".paginated-topics-list .topic-list tr"
|
||||
@action={{action "loadMore"}}
|
||||
>
|
||||
|
||||
<BasicAssignedTopicList
|
||||
@topicList={{model}}
|
||||
@hideCategory={{hideCategory}}
|
||||
@showPosters={{showPosters}}
|
||||
@bulkSelectEnabled={{bulkSelectEnabled}}
|
||||
@canBulkSelect={{canBulkSelect}}
|
||||
@selected={{selected}}
|
||||
@hasIncoming={{hasIncoming}}
|
||||
@incomingCount={{incomingCount}}
|
||||
@topicList={{this.model}}
|
||||
@hideCategory={{this.hideCategory}}
|
||||
@showPosters={{this.showPosters}}
|
||||
@bulkSelectEnabled={{this.bulkSelectEnabled}}
|
||||
@canBulkSelect={{this.canBulkSelect}}
|
||||
@selected={{this.selected}}
|
||||
@hasIncoming={{this.hasIncoming}}
|
||||
@incomingCount={{this.incomingCount}}
|
||||
@showInserted={{action "showInserted"}}
|
||||
@tagsForUser={{tagsForUser}}
|
||||
@tagsForUser={{this.tagsForUser}}
|
||||
@changeSort={{action "changeSort"}}
|
||||
@toggleBulkSelect={{action "toggleBulkSelect"}}
|
||||
@bulkSelectAction={{action "refresh"}}
|
||||
@unassign={{action "unassign"}}
|
||||
@reassign={{action "reassign"}}
|
||||
@onScroll={{saveScrollPosition}}
|
||||
@onScroll={{this.saveScrollPosition}}
|
||||
@scrollOnLoad={{true}}
|
||||
/>
|
||||
|
||||
<ConditionalLoadingSpinner @condition={{model.loadingMore}} />
|
||||
<ConditionalLoadingSpinner @condition={{this.model.loadingMore}} />
|
||||
</LoadMore>
|
|
@ -3,53 +3,58 @@
|
|||
@class="activity-nav"
|
||||
@desktopClass="action-list activity-list nav-stacked"
|
||||
>
|
||||
{{#if isDesktop}}
|
||||
{{#if this.isDesktop}}
|
||||
<div class="search-div">
|
||||
<Input
|
||||
@type="text"
|
||||
placeholder={{i18n
|
||||
"discourse_assign.sidebar_name_filter_placeholder"
|
||||
}}
|
||||
@value={{readonly filterName}}
|
||||
@value={{readonly this.filterName}}
|
||||
class="search"
|
||||
{{on "input" (action "onChangeFilterName" value="target.value")}}
|
||||
{{on "input" (action this.onChangeFilterName value="target.value")}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<LoadMore @selector=".activity-nav li" @action={{action "loadMore"}}>
|
||||
<GroupAssignedFilter
|
||||
@showAvatar={{false}}
|
||||
@filter="everyone"
|
||||
@routeType={{route_type}}
|
||||
@assignmentCount={{group.assignment_count}}
|
||||
@search={{search}}
|
||||
@ascending={{ascending}}
|
||||
@order={{order}}
|
||||
@routeType={{this.route_type}}
|
||||
@assignmentCount={{this.group.assignment_count}}
|
||||
@search={{this.search}}
|
||||
@ascending={{this.ascending}}
|
||||
@order={{this.order}}
|
||||
/>
|
||||
|
||||
<GroupAssignedFilter
|
||||
@showAvatar={{false}}
|
||||
@groupName={{group.name}}
|
||||
@filter={{group.name}}
|
||||
@routeType={{route_type}}
|
||||
@assignmentCount={{group.group_assignment_count}}
|
||||
@search={{search}}
|
||||
@ascending={{ascending}}
|
||||
@order={{order}}
|
||||
@groupName={{this.group.name}}
|
||||
@filter={{this.group.name}}
|
||||
@routeType={{this.route_type}}
|
||||
@assignmentCount={{this.group.group_assignment_count}}
|
||||
@search={{this.search}}
|
||||
@ascending={{this.ascending}}
|
||||
@order={{this.order}}
|
||||
/>
|
||||
{{#each members as |member|}}
|
||||
|
||||
{{#each this.members as |member|}}
|
||||
<GroupAssignedFilter
|
||||
@showAvatar={{true}}
|
||||
@filter={{member}}
|
||||
@routeType={{route_type}}
|
||||
@search={{search}}
|
||||
@ascending={{ascending}}
|
||||
@order={{order}}
|
||||
@routeType={{this.route_type}}
|
||||
@search={{this.search}}
|
||||
@ascending={{this.ascending}}
|
||||
@order={{this.order}}
|
||||
/>
|
||||
{{/each}}
|
||||
<ConditionalLoadingSpinner @condition={{loading}} />
|
||||
|
||||
<ConditionalLoadingSpinner @condition={{this.loading}} />
|
||||
</LoadMore>
|
||||
</MobileNav>
|
||||
</section>
|
||||
|
||||
<section class="user-content">
|
||||
{{outlet}}
|
||||
</section>
|
|
@ -1,25 +1,25 @@
|
|||
<td class="topic-list-data">
|
||||
<div class="main-link">
|
||||
<TopicStatus @topic={{topic}} />
|
||||
{{~#if isPrivateMessage}}
|
||||
<TopicStatus @topic={{this.topic}} />
|
||||
{{~#if this.isPrivateMessage}}
|
||||
{{~d-icon "envelope" class="private-message-icon"}}
|
||||
{{~/if}}
|
||||
{{~topic-link topic}}
|
||||
{{#if topic.unseen}}
|
||||
{{~topic-link this.topic}}
|
||||
{{#if this.topic.unseen}}
|
||||
<span class="badge-notification new-topic"></span>
|
||||
{{/if}}
|
||||
{{#if topic.hasExcerpt}}
|
||||
{{#if this.topic.hasExcerpt}}
|
||||
<div class="topic-excerpt">
|
||||
{{html-safe topic.excerpt}}
|
||||
{{#if topic.excerptTruncated}}
|
||||
{{#unless topic.canClearPin}}<a href={{topic.url}}>{{i18n
|
||||
{{html-safe this.topic.excerpt}}
|
||||
{{#if this.topic.excerptTruncated}}
|
||||
{{#unless this.topic.canClearPin}}<a href={{this.topic.url}}>{{i18n
|
||||
"read_more"
|
||||
}}</a>{{/unless}}
|
||||
{{/if}}
|
||||
{{#if topic.canClearPin}}
|
||||
{{#if this.topic.canClearPin}}
|
||||
<a
|
||||
href
|
||||
{{action "clearPin" topic}}
|
||||
{{action "clearPin" this.topic}}
|
||||
title={{i18n "topic.clear_pin.help"}}
|
||||
>{{i18n "topic.clear_pin.title"}}</a>
|
||||
{{/if}}
|
||||
|
@ -27,43 +27,49 @@
|
|||
{{/if}}
|
||||
</div>
|
||||
<div class="pull-right topic-list-num">
|
||||
{{#if topic.assigned_to_user}}
|
||||
{{#if this.topic.assigned_to_user}}
|
||||
<AssignActionsDropdown
|
||||
@topic={{topic}}
|
||||
@assignee={{topic.assigned_to_user.username}}
|
||||
@unassign={{unassign}}
|
||||
@reassign={{reassign}}
|
||||
@topic={{this.topic}}
|
||||
@assignee={{this.topic.assigned_to_user.username}}
|
||||
@unassign={{this.unassign}}
|
||||
@reassign={{this.reassign}}
|
||||
/>
|
||||
{{else if topic.assigned_to_group}}
|
||||
{{else if this.topic.assigned_to_group}}
|
||||
<AssignActionsDropdown
|
||||
@topic={{topic}}
|
||||
@assignee={{topic.assigned_to_group.name}}
|
||||
@topic={{this.topic}}
|
||||
@assignee={{this.topic.assigned_to_group.name}}
|
||||
@group={{true}}
|
||||
@unassign={{unassign}}
|
||||
@reassign={{reassign}}
|
||||
@unassign={{this.unassign}}
|
||||
@reassign={{this.reassign}}
|
||||
/>
|
||||
{{else}}
|
||||
<AssignActionsDropdown @topic={{topic}} @unassign={{unassign}} />
|
||||
<AssignActionsDropdown
|
||||
@topic={{this.topic}}
|
||||
@unassign={{this.unassign}}
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<div class="topic-item-stats clearfix">
|
||||
{{discourse-tags topic mode="list" tagsForUser=tagsForUser}}
|
||||
{{discourse-tags this.topic mode="list" tagsForUser=this.tagsForUser}}
|
||||
<div class="pull-right topic-list-num">
|
||||
{{raw
|
||||
"list/activity-column"
|
||||
topic=topic
|
||||
topic=this.topic
|
||||
tagName="div"
|
||||
class="num activity last"
|
||||
}}
|
||||
<a
|
||||
href={{topic.lastPostUrl}}
|
||||
title="{{i18n 'last_post'}}: {{html-safe raw-date topic.bumped_at}}"
|
||||
>{{topic.last_poster_username}}</a>
|
||||
href={{this.topic.lastPostUrl}}
|
||||
title="{{i18n 'last_post'}}: {{html-safe
|
||||
raw-date
|
||||
this.topic.bumped_at
|
||||
}}"
|
||||
>{{this.topic.last_poster_username}}</a>
|
||||
</div>
|
||||
{{#unless hideCategory}}
|
||||
{{#unless this.hideCategory}}
|
||||
<div class="category">
|
||||
{{category-link topic.category}}
|
||||
{{category-link this.topic.category}}
|
||||
</div>
|
||||
{{/unless}}
|
||||
<div class="clearfix"></div>
|
||||
|
|
|
@ -1,29 +1,33 @@
|
|||
<ConditionalLoadingSpinner @condition={{loading}}>
|
||||
{{#if hasIncoming}}
|
||||
<ConditionalLoadingSpinner @condition={{this.loading}}>
|
||||
{{#if this.hasIncoming}}
|
||||
<div class="show-mores">
|
||||
<a href class="alert alert-info clickable" {{action showInserted}}>
|
||||
<a
|
||||
href
|
||||
class="alert alert-info clickable"
|
||||
{{on "click" this.showInserted}}
|
||||
>
|
||||
<CountI18n
|
||||
@key="topic_count_"
|
||||
@suffix="latest"
|
||||
@count={{incomingCount}}
|
||||
@count={{this.incomingCount}}
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if topics}}
|
||||
{{#if this.topics}}
|
||||
<table class="topic-list assigned-topic-list">
|
||||
<tbody class="topic-list-body assigned-topic-list-body">
|
||||
{{#each topics as |t|}}
|
||||
{{#each this.topics as |topic|}}
|
||||
<AssignedTopicListItem
|
||||
@topic={{t}}
|
||||
@expandGloballyPinned={{expandGloballyPinned}}
|
||||
@expandAllPinned={{expandAllPinned}}
|
||||
@lastVisitedTopic={{lastVisitedTopic}}
|
||||
@selected={{selected}}
|
||||
@tagsForUser={{tagsForUser}}
|
||||
@unassign={{unassign}}
|
||||
@reassign={{reassign}}
|
||||
@topic={{topic}}
|
||||
@expandGloballyPinned={{this.expandGloballyPinned}}
|
||||
@expandAllPinned={{this.expandAllPinned}}
|
||||
@lastVisitedTopic={{this.lastVisitedTopic}}
|
||||
@selected={{this.selected}}
|
||||
@tagsForUser={{this.tagsForUser}}
|
||||
@unassign={{this.unassign}}
|
||||
@reassign={{this.reassign}}
|
||||
/>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
|
|
|
@ -4,22 +4,22 @@
|
|||
<label>{{i18n "discourse_assign.assign_modal.assignee_label"}}</label>
|
||||
<AssigneeChooser
|
||||
autocomplete="off"
|
||||
@value={{assigneeName}}
|
||||
@value={{this.assigneeName}}
|
||||
@onChange={{action "assignUsername"}}
|
||||
autofocus="autofocus"
|
||||
@showUserStatus={{true}}
|
||||
@options={{hash
|
||||
mobilePlacementStrategy="absolute"
|
||||
filterPlaceholder=placeholderKey
|
||||
filterPlaceholder=this.placeholderKey
|
||||
includeGroups=true
|
||||
customSearchOptions=(hash
|
||||
assignableGroups=true defaultSearchResults=this.assignSuggestions
|
||||
)
|
||||
groupMembersOf=allowedGroups
|
||||
groupMembersOf=this.allowedGroups
|
||||
maximum=1
|
||||
autofocus=autofocus
|
||||
autofocus=this.autofocus
|
||||
tabindex=1
|
||||
expandedOnInsert=(not assigneeName)
|
||||
expandedOnInsert=(not this.assigneeName)
|
||||
caretUpIcon="search"
|
||||
caretDownIcon="search"
|
||||
}}
|
||||
|
@ -37,9 +37,9 @@
|
|||
<label>{{i18n "discourse_assign.assign_modal.status_label"}}</label>
|
||||
<ComboBox
|
||||
@id="assign-status"
|
||||
@content={{availableStatuses}}
|
||||
@value={{status}}
|
||||
@onChange={{action (mut model.status)}}
|
||||
@content={{this.availableStatuses}}
|
||||
@value={{this.status}}
|
||||
@onChange={{action (mut this.model.status)}}
|
||||
/>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
@ -51,8 +51,8 @@
|
|||
>{{i18n "discourse_assign.assign_modal.optional_label"}}</span>
|
||||
</label>
|
||||
<Textarea
|
||||
id={{"assign-modal-note"}}
|
||||
@value={{model.note}}
|
||||
id="assign-modal-note"
|
||||
@value={{this.model.note}}
|
||||
{{! template-lint-disable no-down-event-binding }}
|
||||
{{on "keydown" (action "handleTextAreaKeydown")}}
|
||||
/>
|
||||
|
@ -63,14 +63,14 @@
|
|||
<div class="modal-footer">
|
||||
<DButton
|
||||
@label={{if
|
||||
model.reassign
|
||||
this.model.reassign
|
||||
"discourse_assign.reassign.title"
|
||||
"discourse_assign.assign_modal.assign"
|
||||
}}
|
||||
@icon={{inviteIcon}}
|
||||
@icon={{this.inviteIcon}}
|
||||
@action={{this.assign}}
|
||||
class="btn-primary"
|
||||
@disabled={{disabled}}
|
||||
@disabled={{this.disabled}}
|
||||
/>
|
||||
<DModalCancel @close={{route-action "closeModal"}} />
|
||||
</div>
|
|
@ -1,18 +1,18 @@
|
|||
{{#if doesntHaveAssignments}}
|
||||
{{#if this.doesntHaveAssignments}}
|
||||
<EmptyState
|
||||
@title={{i18n "user.no_assignments_title"}}
|
||||
@body={{emptyStateBody}}
|
||||
@body={{this.emptyStateBody}}
|
||||
/>
|
||||
{{else}}
|
||||
<div class="topic-search-div">
|
||||
<div class="inline-form full-width">
|
||||
<Input
|
||||
class="no-blur"
|
||||
@value={{readonly search}}
|
||||
placeholder={{i18n "discourse_assign.topic_search_placeholder"}}
|
||||
autocomplete="off"
|
||||
@value={{readonly this.search}}
|
||||
@type="search"
|
||||
{{on "input" (action "onChangeFilter" value="target.value")}}
|
||||
class="no-blur"
|
||||
placeholder={{i18n "discourse_assign.topic_search_placeholder"}}
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -23,22 +23,22 @@
|
|||
@action={{action "loadMore"}}
|
||||
>
|
||||
<BasicAssignedTopicList
|
||||
@topicList={{model}}
|
||||
@hideCategory={{hideCategory}}
|
||||
@topicList={{this.model}}
|
||||
@hideCategory={{this.hideCategory}}
|
||||
@showPosters={{true}}
|
||||
@bulkSelectEnabled={{bulkSelectEnabled}}
|
||||
@selected={{selected}}
|
||||
@hasIncoming={{hasIncoming}}
|
||||
@incomingCount={{incomingCount}}
|
||||
@showInserted={{action "showInserted"}}
|
||||
@tagsForUser={{tagsForUser}}
|
||||
@changeSort={{action "changeSort"}}
|
||||
@unassign={{action "unassign"}}
|
||||
@reassign={{action "reassign"}}
|
||||
@onScroll={{saveScrollPosition}}
|
||||
@bulkSelectEnabled={{this.bulkSelectEnabled}}
|
||||
@selected={{this.selected}}
|
||||
@hasIncoming={{this.hasIncoming}}
|
||||
@incomingCount={{this.incomingCount}}
|
||||
@showInserted={{this.showInserted}}
|
||||
@tagsForUser={{this.tagsForUser}}
|
||||
@changeSort={{this.changeSort}}
|
||||
@unassign={{this.unassign}}
|
||||
@reassign={{this.reassign}}
|
||||
@onScroll={{this.saveScrollPosition}}
|
||||
@scrollOnLoad={{true}}
|
||||
/>
|
||||
|
||||
<ConditionalLoadingSpinner @condition={{model.loadingMore}} />
|
||||
<ConditionalLoadingSpinner @condition={{this.model.loadingMore}} />
|
||||
</LoadMore>
|
||||
{{/if}}
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "discourse",
|
||||
"version": "1.0.0",
|
||||
"repository": "git@github.com:discourse/discourse-assign.git",
|
||||
"version": "1.0.1",
|
||||
"repository": "https://github.com/discourse/discourse-assign",
|
||||
"author": "Discourse",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
# version: 1.0.1
|
||||
# authors: Sam Saffron
|
||||
# url: https://github.com/discourse/discourse-assign
|
||||
# transpile_js: true
|
||||
|
||||
enabled_site_setting :assign_enabled
|
||||
|
||||
|
|
|
@ -14,6 +14,6 @@ acceptance("Discourse Assign | Assign disabled mobile", function (needs) {
|
|||
const menu = selectKit(".topic-footer-mobile-dropdown");
|
||||
await menu.expand();
|
||||
|
||||
assert.notOk(menu.rowByValue("assign").exists());
|
||||
assert.false(menu.rowByValue("assign").exists());
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,7 +3,6 @@ import { cloneJSON } from "discourse-common/lib/object";
|
|||
import userFixtures from "discourse/tests/fixtures/user-fixtures";
|
||||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
updateCurrentUser,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { click, visit } from "@ember/test-helpers";
|
||||
|
@ -43,9 +42,9 @@ acceptance("Discourse Assign | Assign mobile", function (needs) {
|
|||
const menu = selectKit(".topic-footer-mobile-dropdown");
|
||||
await menu.expand();
|
||||
|
||||
assert.ok(menu.rowByValue("assign").exists());
|
||||
assert.true(menu.rowByValue("assign").exists());
|
||||
await menu.selectRowByValue("assign");
|
||||
assert.ok(exists(".assign.modal-body"), "assign modal opens");
|
||||
assert.dom(".assign.modal-body").exists("assign modal opens");
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -81,25 +80,23 @@ acceptance("Discourse Assign | Assign desktop", function (needs) {
|
|||
test("Post contains hidden assign button", async function (assert) {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
|
||||
assert.ok(
|
||||
!exists("#post_2 .extra-buttons .d-icon-user-plus"),
|
||||
"assign to post button is hidden"
|
||||
);
|
||||
assert
|
||||
.dom("#post_2 .extra-buttons .d-icon-user-plus")
|
||||
.doesNotExist("assign to post button is hidden");
|
||||
await click("#post_2 button.show-more-actions");
|
||||
|
||||
assert.ok(
|
||||
exists("#post_2 .extra-buttons .d-icon-user-plus"),
|
||||
"assign to post button exists"
|
||||
);
|
||||
assert
|
||||
.dom("#post_2 .extra-buttons .d-icon-user-plus")
|
||||
.exists("assign to post button exists");
|
||||
await click("#post_2 .extra-buttons .d-icon-user-plus");
|
||||
assert.ok(exists(".assign.modal-body"), "assign modal opens");
|
||||
assert.dom(".assign.modal-body").exists("assign modal opens");
|
||||
});
|
||||
|
||||
test("Footer dropdown contains button", async function (assert) {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click("#topic-footer-button-assign");
|
||||
|
||||
assert.ok(exists(".assign.modal-body"), "assign modal opens");
|
||||
assert.dom(".assign.modal-body").exists("assign modal opens");
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -140,10 +137,9 @@ acceptance("Discourse Assign | Assign Status enabled", function (needs) {
|
|||
await visit("/t/internationalization-localization/280");
|
||||
await click("#topic-footer-button-assign");
|
||||
|
||||
assert.ok(
|
||||
exists(".assign.modal-body #assign-status"),
|
||||
"assign status dropdown exists"
|
||||
);
|
||||
assert
|
||||
.dom(".assign.modal-body #assign-status")
|
||||
.exists("assign status dropdown exists");
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -180,10 +176,9 @@ acceptance("Discourse Assign | Assign Status disabled", function (needs) {
|
|||
await visit("/t/internationalization-localization/280");
|
||||
await click("#topic-footer-button-assign");
|
||||
|
||||
assert.notOk(
|
||||
exists(".assign.modal-body #assign-status"),
|
||||
"assign status dropdown doesn't exists"
|
||||
);
|
||||
assert
|
||||
.dom(".assign.modal-body #assign-status")
|
||||
.doesNotExist("assign status dropdown doesn't exists");
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { test } from "qunit";
|
||||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
query,
|
||||
updateCurrentUser,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
|
@ -99,62 +98,59 @@ acceptance("Discourse Assign | Assigned topic", function (needs) {
|
|||
updateCurrentUser({ can_assign: true });
|
||||
await visit("/t/assignment-topic/44");
|
||||
|
||||
assert.strictEqual(
|
||||
query("#topic-title .assigned-to").innerText.trim(),
|
||||
"eviltrout",
|
||||
"shows assignment in the header"
|
||||
);
|
||||
assert.strictEqual(
|
||||
query("#post_1 .assigned-to").innerText,
|
||||
"Assigned topic to eviltrout#2 to Developers",
|
||||
"shows assignment and indirect assignments in the first post"
|
||||
);
|
||||
assert.ok(exists("#post_1 .assigned-to svg.d-icon-user-plus"));
|
||||
assert.strictEqual(
|
||||
query(".discourse-tags .assigned-to[href='/t/28830'] span").title,
|
||||
"Shark Doododooo",
|
||||
"shows topic assign notes"
|
||||
);
|
||||
assert.strictEqual(
|
||||
query(".discourse-tags .assigned-to[href='/p/2'] span").title,
|
||||
'<script>alert("xss")</script>',
|
||||
"shows indirect assign notes"
|
||||
);
|
||||
assert.ok(
|
||||
exists("#topic-footer-dropdown-reassign"),
|
||||
"shows reassign dropdown at the bottom of the topic"
|
||||
);
|
||||
assert
|
||||
.dom("#topic-title .assigned-to")
|
||||
.hasText("eviltrout", "shows assignment in the header");
|
||||
assert
|
||||
.dom("#post_1 .assigned-to")
|
||||
.hasText(
|
||||
"Assigned topic to eviltrout#2 to Developers",
|
||||
"shows assignment and indirect assignments in the first post"
|
||||
);
|
||||
assert.dom("#post_1 .assigned-to svg.d-icon-user-plus").exists();
|
||||
assert
|
||||
.dom(".discourse-tags .assigned-to[href='/t/28830'] span")
|
||||
.hasAttribute("title", "Shark Doododooo", "shows topic assign notes");
|
||||
assert
|
||||
.dom(".discourse-tags .assigned-to[href='/p/2'] span")
|
||||
.hasAttribute(
|
||||
"title",
|
||||
'<script>alert("xss")</script>',
|
||||
"shows indirect assign notes"
|
||||
);
|
||||
assert
|
||||
.dom("#topic-footer-dropdown-reassign")
|
||||
.exists("shows reassign dropdown at the bottom of the topic");
|
||||
});
|
||||
|
||||
test("Shows group assignment info", async function (assert) {
|
||||
updateCurrentUser({ can_assign: true });
|
||||
await visit("/t/assignment-topic/45");
|
||||
|
||||
assert.strictEqual(
|
||||
query("#topic-title .assigned-to").innerText.trim(),
|
||||
"Developers",
|
||||
"shows assignment in the header"
|
||||
);
|
||||
assert.strictEqual(
|
||||
query("#post_1 .assigned-to--group").innerText.trim(),
|
||||
"Assigned topic to Developers",
|
||||
"shows assignment in the first post"
|
||||
);
|
||||
assert.ok(exists("#post_1 .assigned-to svg.d-icon-group-plus"));
|
||||
assert.ok(
|
||||
exists("#topic-footer-dropdown-reassign"),
|
||||
"shows reassign dropdown at the bottom of the topic"
|
||||
);
|
||||
assert
|
||||
.dom("#topic-title .assigned-to")
|
||||
.hasText("Developers", "shows assignment in the header");
|
||||
assert
|
||||
.dom("#post_1 .assigned-to--group")
|
||||
.hasText(
|
||||
"Assigned topic to Developers",
|
||||
"shows assignment in the first post"
|
||||
);
|
||||
assert.dom("#post_1 .assigned-to svg.d-icon-group-plus").exists();
|
||||
assert
|
||||
.dom("#topic-footer-dropdown-reassign")
|
||||
.exists("shows reassign dropdown at the bottom of the topic");
|
||||
});
|
||||
|
||||
test("User without assign ability cannot see footer button", async function (assert) {
|
||||
updateCurrentUser({ can_assign: false, admin: false, moderator: false });
|
||||
await visit("/t/assignment-topic/45");
|
||||
|
||||
assert.notOk(
|
||||
exists("#topic-footer-dropdown-reassign"),
|
||||
"does not show reassign dropdown at the bottom of the topic"
|
||||
);
|
||||
assert
|
||||
.dom("#topic-footer-dropdown-reassign")
|
||||
.doesNotExist(
|
||||
"does not show reassign dropdown at the bottom of the topic"
|
||||
);
|
||||
});
|
||||
|
||||
test("Shows assignment notification", async function (assert) {
|
||||
|
@ -166,7 +162,7 @@ acceptance("Discourse Assign | Assigned topic", function (needs) {
|
|||
"section.user-content ul.notifications li.item.notification"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
assert.true(
|
||||
notification.children[0].classList.contains("assigned"),
|
||||
"with correct assigned class"
|
||||
);
|
||||
|
@ -201,9 +197,9 @@ acceptance("Discourse Assign | Reassign topic", function (needs) {
|
|||
await visit("/t/assignment-topic/44");
|
||||
await menu.expand();
|
||||
|
||||
assert.ok(menu.rowByValue("unassign").exists());
|
||||
assert.ok(menu.rowByValue("reassign").exists());
|
||||
assert.ok(menu.rowByValue("reassign-self").exists());
|
||||
assert.true(menu.rowByValue("unassign").exists());
|
||||
assert.true(menu.rowByValue("reassign").exists());
|
||||
assert.true(menu.rowByValue("reassign-self").exists());
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -225,9 +221,9 @@ acceptance("Discourse Assign | Reassign topic | mobile", function (needs) {
|
|||
await visit("/t/assignment-topic/44");
|
||||
await menu.expand();
|
||||
|
||||
assert.ok(menu.rowByValue("unassign-mobile").exists());
|
||||
assert.ok(menu.rowByValue("reassign-mobile").exists());
|
||||
assert.ok(menu.rowByValue("reassign-self-mobile").exists());
|
||||
assert.true(menu.rowByValue("unassign-mobile").exists());
|
||||
assert.true(menu.rowByValue("reassign-mobile").exists());
|
||||
assert.true(menu.rowByValue("reassign-self-mobile").exists());
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -248,6 +244,6 @@ acceptance("Discourse Assign | Reassign topic conditionals", function (needs) {
|
|||
await visit("/t/assignment-topic/44");
|
||||
await menu.expand();
|
||||
|
||||
assert.notOk(menu.rowByValue("reassign-self").exists());
|
||||
assert.false(menu.rowByValue("reassign-self").exists());
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
query,
|
||||
queryAll,
|
||||
updateCurrentUser,
|
||||
|
@ -211,7 +210,7 @@ acceptance(
|
|||
test("the assigns tab is not shown", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
assert.notOk(exists("#user-menu-button-assign-list"));
|
||||
assert.dom("#user-menu-button-assign-list").doesNotExist();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@ -229,7 +228,7 @@ acceptance(
|
|||
test("the assigns tab is not shown", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
assert.notOk(exists("#user-menu-button-assign-list"));
|
||||
assert.dom("#user-menu-button-assign-list").doesNotExist();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@ -284,31 +283,24 @@ acceptance("Discourse Assign | user menu", function (needs) {
|
|||
test("assigns tab", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".d-header-icons .current-user");
|
||||
assert.ok(exists("#user-menu-button-assign-list"), "assigns tab exists");
|
||||
assert.ok(
|
||||
exists("#user-menu-button-assign-list .d-icon-user-plus"),
|
||||
"assigns tab has the user-plus icon"
|
||||
);
|
||||
assert.strictEqual(
|
||||
query(
|
||||
"#user-menu-button-assign-list .badge-notification"
|
||||
).textContent.trim(),
|
||||
"173",
|
||||
"assigns tab has a count badge"
|
||||
);
|
||||
assert.dom("#user-menu-button-assign-list").exists("assigns tab exists");
|
||||
assert
|
||||
.dom("#user-menu-button-assign-list .d-icon-user-plus")
|
||||
.exists("assigns tab has the user-plus icon");
|
||||
assert
|
||||
.dom("#user-menu-button-assign-list .badge-notification")
|
||||
.hasText("173", "assigns tab has a count badge");
|
||||
|
||||
updateCurrentUser({
|
||||
grouped_unread_notifications: {},
|
||||
});
|
||||
|
||||
assert.notOk(
|
||||
exists("#user-menu-button-assign-list .badge-notification"),
|
||||
"badge count disappears when it goes to zero"
|
||||
);
|
||||
assert.ok(
|
||||
exists("#user-menu-button-assign-list"),
|
||||
"assigns tab still exists"
|
||||
);
|
||||
assert
|
||||
.dom("#user-menu-button-assign-list .badge-notification")
|
||||
.doesNotExist("badge count disappears when it goes to zero");
|
||||
assert
|
||||
.dom("#user-menu-button-assign-list")
|
||||
.exists("assigns tab still exists");
|
||||
});
|
||||
|
||||
test("clicking on the assign tab when it's already selected navigates to the user's assignments page", async function (assert) {
|
||||
|
@ -335,11 +327,11 @@ acceptance("Discourse Assign | user menu", function (needs) {
|
|||
1,
|
||||
"there is one unread notification"
|
||||
);
|
||||
assert.ok(
|
||||
assert.true(
|
||||
notifications[0].classList.contains("unread"),
|
||||
"the notification is unread"
|
||||
);
|
||||
assert.ok(
|
||||
assert.true(
|
||||
notifications[0].classList.contains("assigned"),
|
||||
"the notification is of type assigned"
|
||||
);
|
||||
|
@ -358,13 +350,13 @@ acceptance("Discourse Assign | user menu", function (needs) {
|
|||
"group assign has the right icon"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
assert.true(
|
||||
userAssign
|
||||
.querySelector("a")
|
||||
.href.endsWith("/t/howdy-this-a-test-topic/209/3"),
|
||||
"user assign links to the first unread post (last read post + 1)"
|
||||
);
|
||||
assert.ok(
|
||||
assert.true(
|
||||
groupAssign
|
||||
.querySelector("a")
|
||||
.href.endsWith(
|
||||
|
@ -382,7 +374,7 @@ acceptance("Discourse Assign | user menu", function (needs) {
|
|||
userAssign.querySelector(".item-description img.emoji"),
|
||||
"emojis are rendered in user assign"
|
||||
);
|
||||
assert.ok(
|
||||
assert.strictEqual(
|
||||
userAssign.querySelector(".item-description b").textContent.trim(),
|
||||
"my test topic",
|
||||
"user assign topic title is trusted"
|
||||
|
@ -423,13 +415,12 @@ acceptance("Discourse Assign | user menu", function (needs) {
|
|||
await click(".d-header-icons .current-user");
|
||||
await click("#user-menu-button-assign-list");
|
||||
|
||||
assert.ok(
|
||||
exists("#user-menu-button-assign-list .badge-notification"),
|
||||
"badge count is visible before dismissing"
|
||||
);
|
||||
assert
|
||||
.dom("#user-menu-button-assign-list .badge-notification")
|
||||
.exists("badge count is visible before dismissing");
|
||||
|
||||
await click(".notifications-dismiss");
|
||||
assert.notOk(markRead, "mark-read request isn't sent");
|
||||
assert.false(markRead, "mark-read request isn't sent");
|
||||
assert.strictEqual(
|
||||
query(".dismiss-notification-confirmation.modal-body").textContent.trim(),
|
||||
I18n.t("notifications.dismiss_confirmation.body.assigns", { count: 173 }),
|
||||
|
@ -437,12 +428,11 @@ acceptance("Discourse Assign | user menu", function (needs) {
|
|||
);
|
||||
|
||||
await click(".modal-footer .btn-primary");
|
||||
assert.ok(markRead, "mark-read request is sent");
|
||||
assert.notOk(exists(".notifications-dismiss"), "dismiss button is gone");
|
||||
assert.notOk(
|
||||
exists("#user-menu-button-assign-list .badge-notification"),
|
||||
"badge count is gone after dismissing"
|
||||
);
|
||||
assert.true(markRead, "mark-read request is sent");
|
||||
assert.dom(".notifications-dismiss").doesNotExist("dismiss button is gone");
|
||||
assert
|
||||
.dom("#user-menu-button-assign-list .badge-notification")
|
||||
.doesNotExist("badge count is gone after dismissing");
|
||||
assert.strictEqual(
|
||||
requestBody,
|
||||
"dismiss_types=assigned",
|
||||
|
@ -456,21 +446,20 @@ acceptance("Discourse Assign | user menu", function (needs) {
|
|||
await click(".d-header-icons .current-user");
|
||||
await click("#user-menu-button-assign-list");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".empty-state-title").textContent.trim(),
|
||||
I18n.t("user.no_assignments_title"),
|
||||
"empty state title is rendered"
|
||||
);
|
||||
const emptyStateBody = query(".empty-state-body");
|
||||
assert.ok(emptyStateBody, "empty state body exists");
|
||||
assert.ok(
|
||||
emptyStateBody.querySelector(".d-icon-user-plus"),
|
||||
"empty state body has user-plus icon"
|
||||
);
|
||||
assert.ok(
|
||||
emptyStateBody
|
||||
.querySelector("a")
|
||||
.href.endsWith("/my/preferences/notifications"),
|
||||
assert
|
||||
.dom(".empty-state-title")
|
||||
.hasText(
|
||||
I18n.t("user.no_assignments_title"),
|
||||
"empty state title is rendered"
|
||||
);
|
||||
assert.dom(".empty-state-body").exists("empty state body exists");
|
||||
assert
|
||||
.dom(".empty-state-body .d-icon-user-plus")
|
||||
.exists("empty state body has user-plus icon");
|
||||
assert.true(
|
||||
query(".empty-state-body a").href.endsWith(
|
||||
"/my/preferences/notifications"
|
||||
),
|
||||
"empty state body has user-plus icon"
|
||||
);
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { acceptance, exists } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
import I18n from "I18n";
|
||||
|
@ -40,7 +40,7 @@ acceptance(
|
|||
await visit("/c/test");
|
||||
|
||||
const title = I18n.t("filters.unassigned.help");
|
||||
assert.ok(exists(`#navigation-bar li[title='${title}']`));
|
||||
assert.dom(`#navigation-bar li[title='${title}']`).exists();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@ -60,7 +60,7 @@ acceptance(
|
|||
await visit("/c/test");
|
||||
|
||||
const title = I18n.t("filters.unassigned.help");
|
||||
assert.ok(!exists(`#navigation-bar li[title='${title}']`));
|
||||
assert.dom(`#navigation-bar li[title='${title}']`).doesNotExist();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@ -80,7 +80,7 @@ acceptance(
|
|||
await visit("/c/test");
|
||||
|
||||
const title = I18n.t("filters.unassigned.help");
|
||||
assert.ok(exists(`#navigation-bar li[title='${title}']`));
|
||||
assert.dom(`#navigation-bar li[title='${title}']`).exists();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@ -100,7 +100,7 @@ acceptance(
|
|||
await visit("/c/test");
|
||||
|
||||
const title = I18n.t("filters.unassigned.help");
|
||||
assert.ok(!exists(`#navigation-bar li[title='${title}']`));
|
||||
assert.dom(`#navigation-bar li[title='${title}']`).doesNotExist();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { acceptance, count } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { visit } from "@ember/test-helpers";
|
||||
import AssignedTopics from "../fixtures/assigned-group-assignments-fixtures";
|
||||
import GroupMembers from "../fixtures/group-members-fixtures";
|
||||
|
@ -21,11 +21,11 @@ acceptance("Discourse Assign | GroupAssignments", function (needs) {
|
|||
|
||||
test("Group Assignments Everyone", async function (assert) {
|
||||
await visit("/g/discourse/assigned");
|
||||
assert.strictEqual(count(".topic-list-item"), 1);
|
||||
assert.dom(".topic-list-item").exists({ count: 1 });
|
||||
});
|
||||
|
||||
test("Group Assignments Ahmedgagan", async function (assert) {
|
||||
await visit("/g/discourse/assigned/ahmedgagan6");
|
||||
assert.strictEqual(count(".topic-list-item"), 1);
|
||||
assert.dom(".topic-list-item").exists({ count: 1 });
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { test } from "qunit";
|
||||
import {
|
||||
acceptance,
|
||||
query,
|
||||
updateCurrentUser,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { visit } from "@ember/test-helpers";
|
||||
|
@ -48,10 +47,11 @@ acceptance(
|
|||
|
||||
await visit("/t/assignment-topic/44");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".topic-notifications-button .reason span.text").innerText,
|
||||
"You will receive notifications because you are watching this topic."
|
||||
);
|
||||
assert
|
||||
.dom(".topic-notifications-button .reason span.text")
|
||||
.hasText(
|
||||
"You will receive notifications because you are watching this topic."
|
||||
);
|
||||
});
|
||||
|
||||
test("Show user assign reason when user never tracks topics", async function (assert) {
|
||||
|
@ -61,10 +61,11 @@ acceptance(
|
|||
|
||||
await visit("/t/assignment-topic/45");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".topic-notifications-button .reason span.text").innerText,
|
||||
"You will see a count of new replies because this topic was assigned to you."
|
||||
);
|
||||
assert
|
||||
.dom(".topic-notifications-button .reason span.text")
|
||||
.hasText(
|
||||
"You will see a count of new replies because this topic was assigned to you."
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import { acceptance, query } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { fillIn, visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
|
||||
|
@ -28,11 +28,12 @@ acceptance("Discourse Assign | Search - Full Page", function (needs) {
|
|||
await fillIn(".search-query", "none");
|
||||
await inSelector.expand();
|
||||
await inSelector.selectRowByValue("assigned");
|
||||
assert.strictEqual(
|
||||
query(".search-query").value,
|
||||
"none in:assigned",
|
||||
'has updated search term to "none in:assigned"'
|
||||
);
|
||||
assert
|
||||
.dom(".search-query")
|
||||
.hasValue(
|
||||
"none in:assigned",
|
||||
'has updated search term to "none in:assigned"'
|
||||
);
|
||||
});
|
||||
|
||||
test("update in:unassigned filter through advanced search ui", async function (assert) {
|
||||
|
@ -43,11 +44,12 @@ acceptance("Discourse Assign | Search - Full Page", function (needs) {
|
|||
await fillIn(".search-query", "none");
|
||||
await inSelector.expand();
|
||||
await inSelector.selectRowByValue("unassigned");
|
||||
assert.strictEqual(
|
||||
query(".search-query").value,
|
||||
"none in:unassigned",
|
||||
'has updated search term to "none in:unassigned"'
|
||||
);
|
||||
assert
|
||||
.dom(".search-query")
|
||||
.hasValue(
|
||||
"none in:unassigned",
|
||||
'has updated search term to "none in:unassigned"'
|
||||
);
|
||||
});
|
||||
|
||||
test("update assigned to through advanced search ui", async function (assert) {
|
||||
|
@ -67,10 +69,11 @@ acceptance("Discourse Assign | Search - Full Page", function (needs) {
|
|||
'has "admin" filled in'
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
query(".search-query").value,
|
||||
"none assigned:admin",
|
||||
'has updated search term to "none assigned:admin"'
|
||||
);
|
||||
assert
|
||||
.dom(".search-query")
|
||||
.hasValue(
|
||||
"none assigned:admin",
|
||||
'has updated search term to "none assigned:admin"'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import {
|
||||
acceptance,
|
||||
count,
|
||||
exists,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { visit } from "@ember/test-helpers";
|
||||
import AssignedTopics from "../fixtures/assigned-topics-fixtures";
|
||||
import { cloneJSON } from "discourse-common/lib/object";
|
||||
|
@ -26,8 +22,8 @@ acceptance(
|
|||
await visit("/u/eviltrout/activity/assigned");
|
||||
await options.expand();
|
||||
|
||||
assert.strictEqual(count("li[data-value='unassign']"), 1);
|
||||
assert.strictEqual(count("li[data-value='reassign']"), 1);
|
||||
assert.dom("li[data-value='unassign']").exists({ count: 1 });
|
||||
assert.dom("li[data-value='reassign']").exists({ count: 1 });
|
||||
});
|
||||
}
|
||||
);
|
||||
|
@ -49,12 +45,12 @@ acceptance(
|
|||
|
||||
test("It renders the empty state panel", async function (assert) {
|
||||
await visit("/u/eviltrout/activity/assigned");
|
||||
assert.ok(exists("div.empty-state"));
|
||||
assert.dom("div.empty-state").exists();
|
||||
});
|
||||
|
||||
test("It does not render the search form", async function (assert) {
|
||||
await visit("/u/eviltrout/activity/assigned");
|
||||
assert.notOk(exists("div.topic-search-div"));
|
||||
assert.dom("div.topic-search-div").doesNotExist();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import { module, test } from "qunit";
|
||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
import EmberObject from "@ember/object";
|
||||
import pretender, { response } from "discourse/tests/helpers/create-pretender";
|
||||
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import { getOwner } from "discourse-common/lib/get-owner";
|
||||
|
||||
module("Unit | Controller | assign-user", function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
discourseModule("Unit | Controller | assign-user", function () {
|
||||
test("assigning a user via suggestions makes API call and closes the modal", async function (assert) {
|
||||
pretender.get("/assign/suggestions", () =>
|
||||
response({
|
||||
|
@ -16,7 +19,8 @@ discourseModule("Unit | Controller | assign-user", function () {
|
|||
pretender.put("/assign/assign", () => response({}));
|
||||
|
||||
let modalClosed = false;
|
||||
const controller = this.getController("assign-user", {
|
||||
const controller = getOwner(this).lookup("controller:assign-user");
|
||||
controller.setProperties({
|
||||
model: {
|
||||
target: EmberObject.create({}),
|
||||
},
|
||||
|
@ -29,7 +33,7 @@ discourseModule("Unit | Controller | assign-user", function () {
|
|||
|
||||
await controller.assignUser("nat");
|
||||
|
||||
assert.strictEqual(modalClosed, true);
|
||||
assert.true(modalClosed);
|
||||
});
|
||||
|
||||
test("assigning a user by selector does not close the modal", async function (assert) {
|
||||
|
@ -42,7 +46,8 @@ discourseModule("Unit | Controller | assign-user", function () {
|
|||
);
|
||||
|
||||
let modalClosed = false;
|
||||
const controller = this.getController("assign-user", {
|
||||
const controller = getOwner(this).lookup("controller:assign-user");
|
||||
controller.setProperties({
|
||||
model: {
|
||||
target: EmberObject.create({}),
|
||||
},
|
||||
|
@ -55,6 +60,6 @@ discourseModule("Unit | Controller | assign-user", function () {
|
|||
|
||||
await controller.assignUsername("nat");
|
||||
|
||||
assert.strictEqual(modalClosed, false);
|
||||
assert.false(modalClosed);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import { module, test } from "qunit";
|
||||
import { setupTest } from "ember-qunit";
|
||||
import sinon from "sinon";
|
||||
import * as showModal from "discourse/lib/show-modal";
|
||||
import pretender, { response } from "discourse/tests/helpers/create-pretender";
|
||||
import { getOwner } from "discourse-common/lib/get-owner";
|
||||
|
||||
module("Unit | Service | task-actions", function (hooks) {
|
||||
setupTest(hooks);
|
||||
|
||||
discourseModule("Unit | Service | task-actions", function () {
|
||||
test("assign", function (assert) {
|
||||
const stub = sinon.stub(showModal, "default").returns("the modal");
|
||||
const service = this.container.lookup("service:task-actions");
|
||||
const service = getOwner(this).lookup("service:task-actions");
|
||||
const target = {
|
||||
assigned_to_user: { username: "tomtom" },
|
||||
assigned_to_group: { name: "cats" },
|
||||
|
@ -17,7 +20,7 @@ discourseModule("Unit | Service | task-actions", function () {
|
|||
const modalCall = stub.getCall(0).args;
|
||||
|
||||
assert.strictEqual(modal, "the modal");
|
||||
assert.deepEqual(modalCall[0], "assign-user");
|
||||
assert.strictEqual(modalCall[0], "assign-user");
|
||||
assert.deepEqual(modalCall[1], {
|
||||
title: "discourse_assign.assign_modal.title",
|
||||
model: {
|
||||
|
@ -32,7 +35,7 @@ discourseModule("Unit | Service | task-actions", function () {
|
|||
});
|
||||
|
||||
test("reassignUserToTopic", async function (assert) {
|
||||
const service = this.container.lookup("service:task-actions");
|
||||
const service = getOwner(this).lookup("service:task-actions");
|
||||
const target = { id: 1 };
|
||||
const user = { username: "tomtom" };
|
||||
let assignRequest;
|
Loading…
Reference in New Issue