From 195dcc92cb3bab9dd7b7457efb7beca06959baae Mon Sep 17 00:00:00 2001 From: Jarek Radosz Date: Mon, 28 Jun 2021 17:37:27 +0200 Subject: [PATCH] DEV: Post-release cleanup (#163) Included: * DEV: Post-release cleanup * DEV: Tests cleanup * DEV: Import cleanup * DEV: Drop a compatibility fix * DEV: Use index_by * DEV: Use ember imports * DEV: Use discourseDebounce * DEV: Use @action * DEV: Use the optional chaining operator * DEV: Fix an invalid test * DEV: Use `discourseModule` * DEV: Add .prettierrc * DEV: Sync up the version number --- .prettierrc | 1 + .../discourse_assign/assign_controller.rb | 12 +- .../assigned-advanced-search.js.es6 | 17 +-- .../assign-settings.js.es6 | 15 +-- .../controllers/assign-user.js.es6 | 87 +++++++------- .../controllers/group-assigned-show.js.es6 | 73 ++++++----- .../controllers/group-assigned.js.es6 | 4 +- .../controllers/user-activity-assigned.js.es6 | 59 +++++---- .../initializers/extend-for-assigns.js.es6 | 5 +- .../extend-category-for-assign.js.es6 | 9 +- .../routes/group-assigned.js.es6 | 8 +- .../routes/user-activity-assigned.js.es6 | 8 +- .../components/assign-actions-dropdown.js.es6 | 22 ++-- .../discourse/components/assigned-to.js.es6 | 4 +- .../assigned-topic-list-item.js.es6 | 31 +---- .../discourse/components/claim-topic.js.es6 | 83 ++++++------- .../components/flagged-topic-listener.js.es6 | 7 +- .../group-assigned-menu-item.js.es6 | 4 +- .../remind-assigns-frequency.js.es6 | 3 +- .../discourse/services/task-actions.js.es6 | 3 +- assets/javascripts/lib/debounce.js.es6 | 10 -- lib/pending_assigns_reminder.rb | 8 +- plugin.rb | 113 +++++++----------- .../acceptance/group-assignments-test.js.es6 | 10 +- .../quick-access-assignments-test.js.es6 | 21 +--- .../un-assign-from-list-test.js.es6 | 8 +- .../group-assigned-filter-test.js.es6 | 72 +++++------ 27 files changed, 324 insertions(+), 373 deletions(-) create mode 100644 .prettierrc delete mode 100644 assets/javascripts/lib/debounce.js.es6 diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/.prettierrc @@ -0,0 +1 @@ +{} diff --git a/app/controllers/discourse_assign/assign_controller.rb b/app/controllers/discourse_assign/assign_controller.rb index 9e9521c..612a3b2 100644 --- a/app/controllers/discourse_assign/assign_controller.rb +++ b/app/controllers/discourse_assign/assign_controller.rb @@ -98,21 +98,13 @@ module DiscourseAssign Topic.preload_custom_fields(topics, TopicList.preloaded_custom_fields) - # TODO Drop AvatarLookup after Discourse 2.6.0 release - lookup_columns = defined?(UserLookup) ? UserLookup.lookup_columns : AvatarLookup.lookup_columns - users = User .where("users.id IN (SELECT value::int FROM topic_custom_fields WHERE name = 'assigned_to_id' AND topic_id IN (?))", topics.map(&:id)) .joins('join user_emails on user_emails.user_id = users.id AND user_emails.primary') - .select(lookup_columns) + .select(UserLookup.lookup_columns) .to_a - # TODO Drop after Discourse 2.6.0 release - if User.respond_to?(:allowed_user_custom_fields) - User.preload_custom_fields(users, User.allowed_user_custom_fields(guardian)) - else - User.preload_custom_fields(users, User.whitelisted_user_custom_fields(guardian)) - end + User.preload_custom_fields(users, User.allowed_user_custom_fields(guardian)) users = users.to_h { |u| [u.id, u] } topics.each do |t| diff --git a/assets/javascripts/discourse-assign/connectors/advanced-search-options-below/assigned-advanced-search.js.es6 b/assets/javascripts/discourse-assign/connectors/advanced-search-options-below/assigned-advanced-search.js.es6 index 9d58e2d..366dacd 100644 --- a/assets/javascripts/discourse-assign/connectors/advanced-search-options-below/assigned-advanced-search.js.es6 +++ b/assets/javascripts/discourse-assign/connectors/advanced-search-options-below/assigned-advanced-search.js.es6 @@ -1,15 +1,16 @@ +import { action } from "@ember/object"; + export default { shouldRender(args, component) { return component.currentUser && component.currentUser.can_assign; }, - actions: { - onChangeAssigned(value) { - if (this.onChangeSearchedTermField) { - this.onChangeSearchedTermField("assigned", "updateInRegex", value); - } else { - this.set("searchedTerms.assigned", value); - } - }, + @action + onChangeAssigned(value) { + if (this.onChangeSearchedTermField) { + this.onChangeSearchedTermField("assigned", "updateInRegex", value); + } else { + this.set("searchedTerms.assigned", value); + } }, }; diff --git a/assets/javascripts/discourse-assign/connectors/category-custom-settings/assign-settings.js.es6 b/assets/javascripts/discourse-assign/connectors/category-custom-settings/assign-settings.js.es6 index c85e99e..eaa312c 100644 --- a/assets/javascripts/discourse-assign/connectors/category-custom-settings/assign-settings.js.es6 +++ b/assets/javascripts/discourse-assign/connectors/category-custom-settings/assign-settings.js.es6 @@ -1,10 +1,11 @@ +import { action } from "@ember/object"; + export default { - actions: { - onChangeSetting(value) { - this.set( - "category.custom_fields.enable_unassigned_filter", - value ? "true" : "false" - ); - }, + @action + onChangeSetting(value) { + this.set( + "category.custom_fields.enable_unassigned_filter", + value ? "true" : "false" + ); }, }; diff --git a/assets/javascripts/discourse-assign/controllers/assign-user.js.es6 b/assets/javascripts/discourse-assign/controllers/assign-user.js.es6 index 198e9ee..1d6fa03 100644 --- a/assets/javascripts/discourse-assign/controllers/assign-user.js.es6 +++ b/assets/javascripts/discourse-assign/controllers/assign-user.js.es6 @@ -1,13 +1,16 @@ +import Controller, { inject as controller } from "@ember/controller"; +import { inject as service } from "@ember/service"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; -import { inject as controller } from "@ember/controller"; import { not } from "@ember/object/computed"; +import { isEmpty } from "@ember/utils"; +import { action } from "@ember/object"; -export default Ember.Controller.extend({ +export default Controller.extend({ topicBulkActions: controller(), assignSuggestions: null, allowedGroups: null, - taskActions: Ember.inject.service(), + taskActions: service(), autofocus: not("capabilities.touch"), init() { @@ -33,50 +36,50 @@ export default Ember.Controller.extend({ }); }, - actions: { - assignUser(user) { - if (this.isBulkAction) { - this.bulkAction(user.username); - return; - } - this.setProperties({ - "model.username": user.username, - "model.allowedGroups": this.taskActions.allowedGroups, - }); - this.send("assign"); - }, + @action + assignUser(user) { + if (this.isBulkAction) { + this.bulkAction(user.username); + return; + } + this.setProperties({ + "model.username": user.username, + "model.allowedGroups": this.taskActions.allowedGroups, + }); + this.send("assign"); + }, - assign() { - if (this.isBulkAction) { - this.bulkAction(this.model.username); - return; - } - let path = "/assign/assign"; + @action + assign() { + if (this.isBulkAction) { + this.bulkAction(this.model.username); + return; + } + let path = "/assign/assign"; - if (Ember.isEmpty(this.get("model.username"))) { - path = "/assign/unassign"; - this.set("model.assigned_to_user", null); - } + if (isEmpty(this.get("model.username"))) { + path = "/assign/unassign"; + this.set("model.assigned_to_user", null); + } - this.send("closeModal"); + this.send("closeModal"); - return ajax(path, { - type: "PUT", - data: { - username: this.get("model.username"), - topic_id: this.get("model.topic.id"), - }, + return ajax(path, { + type: "PUT", + data: { + username: this.get("model.username"), + topic_id: this.get("model.topic.id"), + }, + }) + .then(() => { + if (this.get("model.onSuccess")) { + this.get("model.onSuccess")(); + } }) - .then(() => { - if (this.get("model.onSuccess")) { - this.get("model.onSuccess")(); - } - }) - .catch(popupAjaxError); - }, + .catch(popupAjaxError); + }, - updateUsername(selected) { - this.set("model.username", selected.firstObject); - }, + updateUsername(selected) { + this.set("model.username", selected.firstObject); }, }); diff --git a/assets/javascripts/discourse-assign/controllers/group-assigned-show.js.es6 b/assets/javascripts/discourse-assign/controllers/group-assigned-show.js.es6 index b753c71..bdc5dfc 100644 --- a/assets/javascripts/discourse-assign/controllers/group-assigned-show.js.es6 +++ b/assets/javascripts/discourse-assign/controllers/group-assigned-show.js.es6 @@ -1,12 +1,15 @@ import UserTopicsList from "discourse/controllers/user-topics-list"; import { alias } from "@ember/object/computed"; import discourseComputed from "discourse-common/utils/decorators"; -import debounce from "discourse/plugins/discourse-assign/lib/debounce"; +import discourseDebounce from "discourse-common/lib/debounce"; import { INPUT_DELAY } from "discourse-common/config/environment"; +import { inject as controller } from "@ember/controller"; +import { inject as service } from "@ember/service"; +import { action } from "@ember/object"; export default UserTopicsList.extend({ - user: Ember.inject.controller(), - taskActions: Ember.inject.service(), + user: controller(), + taskActions: service(), order: "", ascending: false, search: "", @@ -43,33 +46,43 @@ export default UserTopicsList.extend({ }); }, - actions: { - unassign(topic) { - this.taskActions - .unassign(topic.get("id")) - .then(() => this.send("changeAssigned")); - }, - reassign(topic) { - const controller = this.taskActions.assign(topic); - controller.set("model.onSuccess", () => this.send("changeAssigned")); - }, - changeSort(sortBy) { - if (sortBy === this.order) { - this.toggleProperty("ascending"); - this.refreshModel(); - } else { - this.setProperties({ order: sortBy, ascending: false }); - this.refreshModel(); - } - }, - onChangeFilter(value) { - debounce(this, this._setSearchTerm, value, INPUT_DELAY * 2); - }, - toggleBulkSelect() { - this.toggleProperty("bulkSelectEnabled"); - }, - refresh() { + @action + unassign(topic) { + this.taskActions + .unassign(topic.get("id")) + .then(() => this.send("changeAssigned")); + }, + + @action + reassign(topic) { + this.taskActions + .assign(topic) + .set("model.onSuccess", () => this.send("changeAssigned")); + }, + + @action + changeSort(sortBy) { + if (sortBy === this.order) { + this.toggleProperty("ascending"); this.refreshModel(); - }, + } else { + 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(); }, }); diff --git a/assets/javascripts/discourse-assign/controllers/group-assigned.js.es6 b/assets/javascripts/discourse-assign/controllers/group-assigned.js.es6 index d1c204a..4d0a53a 100644 --- a/assets/javascripts/discourse-assign/controllers/group-assigned.js.es6 +++ b/assets/javascripts/discourse-assign/controllers/group-assigned.js.es6 @@ -3,7 +3,7 @@ import Controller, { inject as controller } from "@ember/controller"; import { action } from "@ember/object"; import { ajax } from "discourse/lib/ajax"; import discourseComputed from "discourse-common/utils/decorators"; -import debounce from "discourse/plugins/discourse-assign/lib/debounce"; +import discourseDebounce from "discourse-common/lib/debounce"; import { INPUT_DELAY } from "discourse-common/config/environment"; export default Controller.extend({ @@ -86,6 +86,6 @@ export default Controller.extend({ @action onChangeFilterName(value) { - debounce(this, this._setFilter, value, INPUT_DELAY * 2); + discourseDebounce(this, this._setFilter, value, INPUT_DELAY * 2); }, }); diff --git a/assets/javascripts/discourse-assign/controllers/user-activity-assigned.js.es6 b/assets/javascripts/discourse-assign/controllers/user-activity-assigned.js.es6 index 679cb24..ad09c5c 100644 --- a/assets/javascripts/discourse-assign/controllers/user-activity-assigned.js.es6 +++ b/assets/javascripts/discourse-assign/controllers/user-activity-assigned.js.es6 @@ -1,11 +1,14 @@ import UserTopicsList from "discourse/controllers/user-topics-list"; import discourseComputed from "discourse-common/utils/decorators"; -import debounce from "discourse/plugins/discourse-assign/lib/debounce"; +import discourseDebounce from "discourse-common/lib/debounce"; import { INPUT_DELAY } from "discourse-common/config/environment"; +import { inject as controller } from "@ember/controller"; +import { inject as service } from "@ember/service"; +import { action } from "@ember/object"; export default UserTopicsList.extend({ - user: Ember.inject.controller(), - taskActions: Ember.inject.service(), + user: controller(), + taskActions: service(), queryParams: ["order", "ascending", "search"], order: "", ascending: false, @@ -38,27 +41,33 @@ export default UserTopicsList.extend({ }); }, - actions: { - unassign(topic) { - this.taskActions - .unassign(topic.get("id")) - .then(() => this.send("changeAssigned")); - }, - reassign(topic) { - const controller = this.taskActions.assign(topic); - controller.set("model.onSuccess", () => this.send("changeAssigned")); - }, - changeSort(sortBy) { - if (sortBy === this.order) { - this.toggleProperty("ascending"); - this.refreshModel(); - } else { - this.setProperties({ order: sortBy, ascending: false }); - this.refreshModel(); - } - }, - onChangeFilter(value) { - debounce(this, this._setSearchTerm, value, INPUT_DELAY * 2); - }, + @action + unassign(topic) { + this.taskActions + .unassign(topic.get("id")) + .then(() => this.send("changeAssigned")); + }, + + @action + reassign(topic) { + this.taskActions + .assign(topic) + .set("model.onSuccess", () => this.send("changeAssigned")); + }, + + @action + changeSort(sortBy) { + if (sortBy === this.order) { + this.toggleProperty("ascending"); + this.refreshModel(); + } else { + this.setProperties({ order: sortBy, ascending: false }); + this.refreshModel(); + } + }, + + @action + onChangeFilter(value) { + discourseDebounce(this, this._setSearchTerm, value, INPUT_DELAY * 2); }, }); diff --git a/assets/javascripts/discourse-assign/initializers/extend-for-assigns.js.es6 b/assets/javascripts/discourse-assign/initializers/extend-for-assigns.js.es6 index 705f699..bb17ff8 100644 --- a/assets/javascripts/discourse-assign/initializers/extend-for-assigns.js.es6 +++ b/assets/javascripts/discourse-assign/initializers/extend-for-assigns.js.es6 @@ -13,6 +13,7 @@ import TopicButtonAction, { } from "discourse/controllers/topic-bulk-actions"; import { inject } from "@ember/controller"; import I18n from "I18n"; +import { get } from "@ember/object"; function titleForState(user) { if (user) { @@ -308,11 +309,11 @@ function initialize(api) { if (dec.attrs.post_number === 1) { const postModel = dec.getModel(); if (postModel) { - const assignedToUser = Ember.get(postModel, "topic.assigned_to_user"); + const assignedToUser = get(postModel, "topic.assigned_to_user"); if (assignedToUser) { return dec.widget.attach("assigned-to", { assignedToUser, - href: Ember.get(postModel, "topic.assignedToUserPath"), + href: get(postModel, "topic.assignedToUserPath"), }); } } diff --git a/assets/javascripts/discourse-assign/pre-initializers/extend-category-for-assign.js.es6 b/assets/javascripts/discourse-assign/pre-initializers/extend-category-for-assign.js.es6 index 5a81eb8..2df3b14 100644 --- a/assets/javascripts/discourse-assign/pre-initializers/extend-category-for-assign.js.es6 +++ b/assets/javascripts/discourse-assign/pre-initializers/extend-category-for-assign.js.es6 @@ -1,20 +1,17 @@ import Category from "discourse/models/category"; +import { computed } from "@ember/object"; export default { name: "extend-category-for-assign", - before: "inject-discourse-objects", initialize() { Category.reopen({ - enable_unassigned_filter: Ember.computed( + enable_unassigned_filter: computed( "custom_fields.enable_unassigned_filter", { get() { - if (this && this.custom_fields) { - return this.custom_fields.enable_unassigned_filter === "true"; - } - return false; + return this?.custom_fields?.enable_unassigned_filter === "true"; }, } ), diff --git a/assets/javascripts/discourse-assign/routes/group-assigned.js.es6 b/assets/javascripts/discourse-assign/routes/group-assigned.js.es6 index fb15464..8d2e7b8 100644 --- a/assets/javascripts/discourse-assign/routes/group-assigned.js.es6 +++ b/assets/javascripts/discourse-assign/routes/group-assigned.js.es6 @@ -1,5 +1,6 @@ import DiscourseRoute from "discourse/routes/discourse"; import { ajax } from "discourse/lib/ajax"; +import { action } from "@ember/object"; export default DiscourseRoute.extend({ model() { @@ -25,9 +26,8 @@ export default DiscourseRoute.extend({ } }, - actions: { - changeAssigned() { - this.refresh(); - }, + @action + changeAssigned() { + this.refresh(); }, }); diff --git a/assets/javascripts/discourse-assign/routes/user-activity-assigned.js.es6 b/assets/javascripts/discourse-assign/routes/user-activity-assigned.js.es6 index 4aa5324..e8f8613 100644 --- a/assets/javascripts/discourse-assign/routes/user-activity-assigned.js.es6 +++ b/assets/javascripts/discourse-assign/routes/user-activity-assigned.js.es6 @@ -1,6 +1,7 @@ import I18n from "I18n"; import UserTopicListRoute from "discourse/routes/user-topic-list"; import cookie from "discourse/lib/cookie"; +import { action } from "@ember/object"; export default UserTopicListRoute.extend({ userActionType: 16, @@ -42,9 +43,8 @@ export default UserTopicListRoute.extend({ controller.set("model", model); }, - actions: { - changeAssigned() { - this.refresh(); - }, + @action + changeAssigned() { + this.refresh(); }, }); diff --git a/assets/javascripts/discourse/components/assign-actions-dropdown.js.es6 b/assets/javascripts/discourse/components/assign-actions-dropdown.js.es6 index f3d10b1..1a89c47 100644 --- a/assets/javascripts/discourse/components/assign-actions-dropdown.js.es6 +++ b/assets/javascripts/discourse/components/assign-actions-dropdown.js.es6 @@ -1,5 +1,6 @@ import I18n from "I18n"; import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box"; +import { action } from "@ember/object"; export default DropdownSelectBoxComponent.extend({ classNames: ["assign-actions-dropdown"], @@ -27,16 +28,15 @@ export default DropdownSelectBoxComponent.extend({ ]; }, - actions: { - onSelect(id) { - switch (id) { - case "unassign": - this.unassign(this.topic, this.user); - break; - case "reassign": - this.reassign(this.topic, this.user); - break; - } - }, + @action + onSelect(id) { + switch (id) { + case "unassign": + this.unassign(this.topic, this.user); + break; + case "reassign": + this.reassign(this.topic, this.user); + break; + } }, }); diff --git a/assets/javascripts/discourse/components/assigned-to.js.es6 b/assets/javascripts/discourse/components/assigned-to.js.es6 index c4e6f2b..5769179 100644 --- a/assets/javascripts/discourse/components/assigned-to.js.es6 +++ b/assets/javascripts/discourse/components/assigned-to.js.es6 @@ -1,3 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; + +export default Component.extend({ classNames: ["assigned-to-user"], }); diff --git a/assets/javascripts/discourse/components/assigned-topic-list-item.js.es6 b/assets/javascripts/discourse/components/assigned-topic-list-item.js.es6 index 2203ee5..3e8d84c 100644 --- a/assets/javascripts/discourse/components/assigned-topic-list-item.js.es6 +++ b/assets/javascripts/discourse/components/assigned-topic-list-item.js.es6 @@ -1,27 +1,6 @@ -import { - ListItemDefaults, - default as TopicListItem, -} from "discourse/components/topic-list-item"; +import TopicListItem from "discourse/components/topic-list-item"; +import { equal } from "@ember/object/computed"; -// This is a backward compatible fix so that this change: -// https://github.com/discourse/discourse/pull/8589 -// in discourse core doesn't break this plugin. -let assignedTopicListItem = null; - -if (ListItemDefaults) { - assignedTopicListItem = Ember.Component.extend(ListItemDefaults, { - isPrivateMessage: Ember.computed.equal( - "topic.archetype", - "private_message" - ), - }); -} else { - assignedTopicListItem = TopicListItem.extend({ - isPrivateMessage: Ember.computed.equal( - "topic.archetype", - "private_message" - ), - }); -} - -export default assignedTopicListItem; +export default TopicListItem.extend({ + isPrivateMessage: equal("topic.archetype", "private_message"), +}); diff --git a/assets/javascripts/discourse/components/claim-topic.js.es6 b/assets/javascripts/discourse/components/claim-topic.js.es6 index 9640f5d..a307893 100644 --- a/assets/javascripts/discourse/components/claim-topic.js.es6 +++ b/assets/javascripts/discourse/components/claim-topic.js.es6 @@ -1,52 +1,55 @@ +import Component from "@ember/component"; import { ajax } from "discourse/lib/ajax"; import { popupAjaxError } from "discourse/lib/ajax-error"; +import { action } from "@ember/object"; -export default Ember.Component.extend({ +export default Component.extend({ tagName: "", claiming: false, unassigning: false, - actions: { - unassign() { - this.set("unassigning", true); - return ajax("/assign/unassign", { - type: "PUT", - data: { topic_id: this.get("topic.id") }, - }) - .then(() => { - this.set("topic.assigned_to_user", null); - }) - .catch(popupAjaxError) - .finally(() => { - this.set("unassigning", false); - }); - }, + @action + unassign() { + this.set("unassigning", true); - claim() { - this.set("claiming", true); - - let topic = this.topic; - ajax(`/assign/claim/${topic.id}`, { - method: "PUT", + return ajax("/assign/unassign", { + type: "PUT", + data: { topic_id: this.get("topic.id") }, + }) + .then(() => { + this.set("topic.assigned_to_user", null); }) - .then(() => { - this.set("topic.assigned_to_user", this.currentUser); - }) - .catch((e) => { - if (e.jqXHR && e.jqXHR.responseJSON) { - let json = e.jqXHR.responseJSON; - if (json && json.extras) { - this.set("topic.assigned_to_user", json.extras.assigned_to); - } + .catch(popupAjaxError) + .finally(() => { + this.set("unassigning", false); + }); + }, + + @action + claim() { + this.set("claiming", true); + + let topic = this.topic; + ajax(`/assign/claim/${topic.id}`, { + method: "PUT", + }) + .then(() => { + this.set("topic.assigned_to_user", this.currentUser); + }) + .catch((e) => { + if (e.jqXHR && e.jqXHR.responseJSON) { + let json = e.jqXHR.responseJSON; + if (json && json.extras) { + this.set("topic.assigned_to_user", json.extras.assigned_to); } - return popupAjaxError(e); - }) - .finally(() => { - if (this.isDestroying || this.isDestroyed) { - return; - } - this.set("claiming", false); - }); - }, + } + return popupAjaxError(e); + }) + .finally(() => { + if (this.isDestroying || this.isDestroyed) { + return; + } + this.set("claiming", false); + }); }, }); diff --git a/assets/javascripts/discourse/components/flagged-topic-listener.js.es6 b/assets/javascripts/discourse/components/flagged-topic-listener.js.es6 index da96bc5..95f2c6e 100644 --- a/assets/javascripts/discourse/components/flagged-topic-listener.js.es6 +++ b/assets/javascripts/discourse/components/flagged-topic-listener.js.es6 @@ -1,10 +1,13 @@ +import Component from "@ember/component"; +import { set } from "@ember/object"; + function assignIfEqual(topic, data) { if (topic && topic.id === data.topic_id) { - Ember.set(topic, "assigned_to_user", data.assigned_to); + set(topic, "assigned_to_user", data.assigned_to); } } -export default Ember.Component.extend({ +export default Component.extend({ didInsertElement() { this._super(); this.messageBus.subscribe("/staff/topic-assignment", (data) => { diff --git a/assets/javascripts/discourse/components/group-assigned-menu-item.js.es6 b/assets/javascripts/discourse/components/group-assigned-menu-item.js.es6 index eed7fd0..4449440 100644 --- a/assets/javascripts/discourse/components/group-assigned-menu-item.js.es6 +++ b/assets/javascripts/discourse/components/group-assigned-menu-item.js.es6 @@ -1,3 +1,5 @@ -export default Ember.Component.extend({ +import Component from "@ember/component"; + +export default Component.extend({ tagName: "", }); diff --git a/assets/javascripts/discourse/components/remind-assigns-frequency.js.es6 b/assets/javascripts/discourse/components/remind-assigns-frequency.js.es6 index 7cac81f..47aa8e7 100644 --- a/assets/javascripts/discourse/components/remind-assigns-frequency.js.es6 +++ b/assets/javascripts/discourse/components/remind-assigns-frequency.js.es6 @@ -1,8 +1,9 @@ +import Component from "@ember/component"; import I18n from "I18n"; import { or } from "@ember/object/computed"; import discourseComputed from "discourse-common/utils/decorators"; -export default Ember.Component.extend({ +export default Component.extend({ selectedFrequency: or( "user.custom_fields.remind_assigns_frequency", "siteSettings.remind_assigns_frequency" diff --git a/assets/javascripts/discourse/services/task-actions.js.es6 b/assets/javascripts/discourse/services/task-actions.js.es6 index 90b37f6..7ee0688 100644 --- a/assets/javascripts/discourse/services/task-actions.js.es6 +++ b/assets/javascripts/discourse/services/task-actions.js.es6 @@ -1,7 +1,8 @@ +import Service from "@ember/service"; import { ajax } from "discourse/lib/ajax"; import showModal from "discourse/lib/show-modal"; -export default Ember.Service.extend({ +export default Service.extend({ unassign(topicId) { return ajax("/assign/unassign", { type: "PUT", diff --git a/assets/javascripts/lib/debounce.js.es6 b/assets/javascripts/lib/debounce.js.es6 deleted file mode 100644 index 42abef9..0000000 --- a/assets/javascripts/lib/debounce.js.es6 +++ /dev/null @@ -1,10 +0,0 @@ -import { debounce } from "@ember/runloop"; - -// TODO: Remove this file and use discouseDebounce after the 2.7 release. -let debounceFunction = debounce; - -try { - debounceFunction = require("discourse-common/lib/debounce").default; -} catch (_) {} - -export default debounceFunction; diff --git a/lib/pending_assigns_reminder.rb b/lib/pending_assigns_reminder.rb index 8a807c8..d4fcb43 100644 --- a/lib/pending_assigns_reminder.rb +++ b/lib/pending_assigns_reminder.rb @@ -87,12 +87,6 @@ class PendingAssignsReminder def update_last_reminded(user) update_last_reminded = { REMINDED_AT => DateTime.now } - # New API in Discouse that's better under concurrency - if user.respond_to?(:upsert_custom_fields) - user.upsert_custom_fields(update_last_reminded) - else - user.custom_fields.merge!(update_last_reminded) - user.save_custom_fields - end + user.upsert_custom_fields(update_last_reminded) end end diff --git a/plugin.rb b/plugin.rb index 05d36a8..8282e6b 100644 --- a/plugin.rb +++ b/plugin.rb @@ -2,7 +2,7 @@ # name: discourse-assign # about: Assign users to topics -# version: 0.1 +# version: 1.0.0 # authors: Sam Saffron # url: https://github.com/discourse/discourse-assign @@ -11,8 +11,8 @@ enabled_site_setting :assign_enabled register_asset 'stylesheets/assigns.scss' register_asset 'stylesheets/mobile/assigns.scss', :mobile -register_svg_icon "user-plus" if respond_to?(:register_svg_icon) -register_svg_icon "user-times" if respond_to?(:register_svg_icon) +register_svg_icon "user-plus" +register_svg_icon "user-times" load File.expand_path('../lib/discourse_assign/engine.rb', __FILE__) load File.expand_path('../lib/discourse_assign/helpers.rb', __FILE__) @@ -128,25 +128,19 @@ after_initialize do end TopicList.preloaded_custom_fields << TopicAssigner::ASSIGNED_TO_ID - Site.preloaded_category_custom_fields << "enable_unassigned_filter" if Site.respond_to? :preloaded_category_custom_fields - Search.preloaded_topic_custom_fields << TopicAssigner::ASSIGNED_TO_ID if Search.respond_to? :preloaded_topic_custom_fields + Site.preloaded_category_custom_fields << "enable_unassigned_filter" + Search.preloaded_topic_custom_fields << TopicAssigner::ASSIGNED_TO_ID - if defined? BookmarkQuery - if BookmarkQuery.respond_to?(:preloaded_custom_fields) && BookmarkQuery.respond_to?(:on_preload) - BookmarkQuery.preloaded_custom_fields << TopicAssigner::ASSIGNED_TO_ID - BookmarkQuery.on_preload do |bookmarks, bookmark_query| - if SiteSetting.assign_enabled? - assigned_user_ids = bookmarks.map(&:topic).map { |topic| topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID] }.compact.uniq - assigned_users = {} - User.where(id: assigned_user_ids).each do |user| - assigned_users[user.id] = user - end - bookmarks.each do |bookmark| - bookmark.topic.preload_assigned_to_user( - assigned_users[bookmark.topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID]] - ) - end - end + BookmarkQuery.preloaded_custom_fields << TopicAssigner::ASSIGNED_TO_ID + BookmarkQuery.on_preload do |bookmarks, bookmark_query| + if SiteSetting.assign_enabled? + assigned_user_ids = bookmarks.map(&:topic).map { |topic| topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID] }.compact.uniq + assigned_users = User.where(id: assigned_user_ids).index_by(&:id) + + bookmarks.each do |bookmark| + bookmark.topic.preload_assigned_to_user( + assigned_users[bookmark.topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID]] + ) end end end @@ -156,47 +150,40 @@ after_initialize do can_assign = topic_list.current_user && topic_list.current_user.can_assign? allowed_access = SiteSetting.assigns_public || can_assign - # TODO Drop AvatarLookup after Discourse 2.6.0 release - lookup_columns = defined?(UserLookup) ? UserLookup.lookup_columns : AvatarLookup.lookup_columns - if allowed_access && topics.length > 0 - users = User.where("users.id in ( + users = User + .where(<<~SQL, topic_ids: topics.map(&:id)) + users.id in ( SELECT value::int FROM topic_custom_fields - WHERE name = 'assigned_to_id' AND topic_id IN (?) - )", topics.map(&:id)) - .select(lookup_columns) + WHERE name = 'assigned_to_id' AND topic_id IN (:topic_ids) + ) + SQL + .select(UserLookup.lookup_columns) - if !defined?(UserLookup) # Remove after Discourse 2.6.0 - users = users.joins('join user_emails on user_emails.user_id = users.id AND user_emails.primary') - end - - map = {} - users.each { |u| map[u.id] = u } + users_map = users.index_by(&:id) topics.each do |t| if id = t.custom_fields[TopicAssigner::ASSIGNED_TO_ID] - t.preload_assigned_to_user(map[id.to_i]) + t.preload_assigned_to_user(users_map[id.to_i]) end end end end end - if Search.respond_to?(:on_preload) - Search.on_preload do |results, search| - if SiteSetting.assign_enabled? - can_assign = search.guardian&.can_assign? - allowed_access = SiteSetting.assigns_public || can_assign + Search.on_preload do |results, search| + if SiteSetting.assign_enabled? + can_assign = search.guardian&.can_assign? + allowed_access = SiteSetting.assigns_public || can_assign - if allowed_access && results.posts.length > 0 - assigned_user_ids = results.posts.map(&:topic).map { |topic| topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID] }.compact.uniq - assigned_users = User.where(id: assigned_user_ids).index_by(&:id) - results.posts.each do |post| - post.topic.preload_assigned_to_user( - assigned_users[post.topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID]] - ) - end + if allowed_access && results.posts.length > 0 + assigned_user_ids = results.posts.map(&:topic).map { |topic| topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID] }.compact.uniq + assigned_users = User.where(id: assigned_user_ids).index_by(&:id) + results.posts.each do |post| + post.topic.preload_assigned_to_user( + assigned_users[post.topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID]] + ) end end end @@ -206,9 +193,7 @@ after_initialize do TopicQuery.add_custom_filter(:assigned) do |results, topic_query| if topic_query.guardian.can_assign? || SiteSetting.assigns_public username = topic_query.options[:assigned] - user_id = topic_query.guardian.user.id if username == "me" - special = ["*", "nobody"].include?(username) if username.present? && !special @@ -216,14 +201,12 @@ after_initialize do end if user_id || special - if username == "nobody" results = results.joins("LEFT JOIN topic_custom_fields tc_assign ON topics.id = tc_assign.topic_id AND tc_assign.name = 'assigned_to_id'") .where("tc_assign.name IS NULL") else - if username == "*" filter = "AND tc_assign.value IS NOT NULL" else @@ -393,24 +376,20 @@ after_initialize do end end - if defined? register_permitted_bulk_action_parameter - register_permitted_bulk_action_parameter :username + register_permitted_bulk_action_parameter :username + + add_to_class(:user_bookmark_serializer, :assigned_to_user_id) do + id = topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID] + # a bit messy but race conditions can give us an array here, avoid + id && id.to_i rescue nil end - if defined? UserBookmarkSerializer - add_to_class(:user_bookmark_serializer, :assigned_to_user_id) do - id = topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID] - # a bit messy but race conditions can give us an array here, avoid - id && id.to_i rescue nil - end + add_to_serializer(:user_bookmark, :assigned_to_user, false) do + topic.assigned_to_user + end - add_to_serializer(:user_bookmark, :assigned_to_user, false) do - topic.assigned_to_user - end - - add_to_serializer(:user_bookmark, 'include_assigned_to_user?') do - (SiteSetting.assigns_public || scope.can_assign?) && topic.assigned_to_user - end + add_to_serializer(:user_bookmark, 'include_assigned_to_user?') do + (SiteSetting.assigns_public || scope.can_assign?) && topic.assigned_to_user end add_to_serializer(:current_user, :can_assign) do diff --git a/test/javascripts/acceptance/group-assignments-test.js.es6 b/test/javascripts/acceptance/group-assignments-test.js.es6 index af61164..6fc53c5 100644 --- a/test/javascripts/acceptance/group-assignments-test.js.es6 +++ b/test/javascripts/acceptance/group-assignments-test.js.es6 @@ -1,6 +1,6 @@ -import { acceptance } from "discourse/tests/helpers/qunit-helpers"; -import { default as AssignedTopics } from "../fixtures/assigned-group-assignments-fixtures"; -import { default as GroupMembers } from "../fixtures/group-members-fixtures"; +import { acceptance, count } from "discourse/tests/helpers/qunit-helpers"; +import AssignedTopics from "../fixtures/assigned-group-assignments-fixtures"; +import GroupMembers from "../fixtures/group-members-fixtures"; acceptance("GroupAssignments", function (needs) { needs.user(); @@ -20,12 +20,12 @@ acceptance("GroupAssignments", function (needs) { test("Group Assignments Everyone", async (assert) => { await visit("/g/discourse/assigned"); assert.equal(currentPath(), "group.assigned.show"); - assert.ok(find(".topic-list-item").length === 1); + assert.equal(count(".topic-list-item"), 1); }); test("Group Assignments Ahmedgagan", async (assert) => { await visit("/g/discourse/assigned/ahmedgagan6"); assert.equal(currentPath(), "group.assigned.show"); - assert.ok(find(".topic-list-item").length === 1); + assert.equal(count(".topic-list-item"), 1); }); }); diff --git a/test/javascripts/acceptance/quick-access-assignments-test.js.es6 b/test/javascripts/acceptance/quick-access-assignments-test.js.es6 index 86e2c58..cdf8f31 100644 --- a/test/javascripts/acceptance/quick-access-assignments-test.js.es6 +++ b/test/javascripts/acceptance/quick-access-assignments-test.js.es6 @@ -1,11 +1,9 @@ import { acceptance, - queryAll, + query, updateCurrentUser, } from "discourse/tests/helpers/qunit-helpers"; -import { default as AssignedTopics } from "../fixtures/assigned-topics-fixtures"; - -const USER_MENU = "#current-user.header-dropdown-toggle"; +import AssignedTopics from "../fixtures/assigned-topics-fixtures"; acceptance("Quick access assignments panel", function (needs) { needs.user(); @@ -21,22 +19,15 @@ acceptance("Quick access assignments panel", function (needs) { updateCurrentUser({ can_assign: true }); await visit("/"); - await click(USER_MENU); + await click("#current-user.header-dropdown-toggle"); - // TODO: Remove when 2.7 gets released - let quickAccessAssignmentsTab = ".widget-button.assigned"; - - if (queryAll(quickAccessAssignmentsTab).length === 0) { - quickAccessAssignmentsTab = ".widget-link.assigned"; - } - - await click(quickAccessAssignmentsTab); - const assignment = find(".quick-access-panel li a")[0]; + await click(".widget-button.assigned"); + const assignment = query(".quick-access-panel li a"); assert.ok(assignment.innerText.includes("Greetings!")); assert.ok(assignment.href.includes("/t/greetings/10/5")); - await click(quickAccessAssignmentsTab); + await click(".widget-button.assigned"); assert.equal( currentPath(), "user.userActivity.assigned", diff --git a/test/javascripts/acceptance/un-assign-from-list-test.js.es6 b/test/javascripts/acceptance/un-assign-from-list-test.js.es6 index 26ae33e..97d902f 100644 --- a/test/javascripts/acceptance/un-assign-from-list-test.js.es6 +++ b/test/javascripts/acceptance/un-assign-from-list-test.js.es6 @@ -1,6 +1,6 @@ import selectKit from "discourse/tests/helpers/select-kit-helper"; -import { acceptance } from "discourse/tests/helpers/qunit-helpers"; -import { default as AssignedTopics } from "../fixtures/assigned-topics-fixtures"; +import { acceptance, count } from "discourse/tests/helpers/qunit-helpers"; +import AssignedTopics from "../fixtures/assigned-topics-fixtures"; acceptance("UnAssign/Re-assign from the topics list", function (needs) { needs.user(); @@ -17,7 +17,7 @@ acceptance("UnAssign/Re-assign from the topics list", function (needs) { await visit("/u/eviltrout/activity/assigned"); await options.expand(); - assert.equal(find("li[data-value='unassign']").length, 1); - assert.equal(find("li[data-value='reassign']").length, 1); + assert.equal(count("li[data-value='unassign']"), 1); + assert.equal(count("li[data-value='reassign']"), 1); }); }); diff --git a/test/javascripts/components/group-assigned-filter-test.js.es6 b/test/javascripts/components/group-assigned-filter-test.js.es6 index e0ed162..2bb95b9 100644 --- a/test/javascripts/components/group-assigned-filter-test.js.es6 +++ b/test/javascripts/components/group-assigned-filter-test.js.es6 @@ -1,46 +1,34 @@ -import componentTest from "discourse/tests/helpers/component-test"; +import componentTest, { + setupRenderingTest, +} from "discourse/tests/helpers/component-test"; +import { discourseModule, query } from "discourse/tests/helpers/qunit-helpers"; -moduleForComponent("group-assigned-filter", { integration: true }); +discourseModule( + "Integration | Component | group-assigned-filter", + function (hooks) { + setupRenderingTest(hooks); -componentTest("display username", { - template: "{{group-assigned-filter show-avatar=true filter=filter}}", + componentTest("displays username and name", { + template: "{{group-assigned-filter show-avatar=true filter=filter}}", - beforeEach() { - this.siteSettings.prioritize_username_in_ux = true; - this.set("filter", { - id: 2, - username: "Ahmed", - name: "Ahmed Gagan", - avatar_template: "/letter_avatar_proxy/v4/letter/a/8c91f0/{size}.png", - title: "trust_level_0", - last_posted_at: "2020-06-22T10:15:54.532Z", - last_seen_at: "2020-07-07T11:55:59.437Z", - added_at: "2020-06-22T09:55:31.692Z", - timezone: "Asia/Calcutta", + beforeEach() { + this.set("filter", { + id: 2, + username: "Ahmed", + name: "Ahmed Gagan", + avatar_template: "/letter_avatar_proxy/v4/letter/a/8c91f0/{size}.png", + title: "trust_level_0", + last_posted_at: "2020-06-22T10:15:54.532Z", + last_seen_at: "2020-07-07T11:55:59.437Z", + added_at: "2020-06-22T09:55:31.692Z", + timezone: "Asia/Calcutta", + }); + }, + + test(assert) { + assert.equal(query(".assign-username").innerText, "Ahmed"); + assert.equal(query(".assign-name").innerText, "Ahmed Gagan"); + }, }); - }, - async test(assert) { - assert.ok(find("li")[0].innerText.trim(), "Ahmed"); - }, -}); -componentTest("display name", { - template: "{{group-assigned-filter show-avatar=true filter=filter}}", - - beforeEach() { - this.siteSettings.prioritize_username_in_ux = true; - this.set("filter", { - id: 2, - username: "Ahmed", - name: "Ahmed Gagan", - avatar_template: "/letter_avatar_proxy/v4/letter/a/8c91f0/{size}.png", - title: "trust_level_0", - last_posted_at: "2020-06-22T10:15:54.532Z", - last_seen_at: "2020-07-07T11:55:59.437Z", - added_at: "2020-06-22T09:55:31.692Z", - timezone: "Asia/Calcutta", - }); - }, - async test(assert) { - assert.ok(find("li")[0].innerText.trim(), "Ahmed Gagan"); - }, -}); + } +);