diff --git a/app/assets/javascripts/discourse/app/controllers/tag-show.js b/app/assets/javascripts/discourse/app/controllers/tag-show.js index be4cbdd6692..c3339debfcf 100644 --- a/app/assets/javascripts/discourse/app/controllers/tag-show.js +++ b/app/assets/javascripts/discourse/app/controllers/tag-show.js @@ -1,177 +1,144 @@ -import Controller, { inject as controller } from "@ember/controller"; +import DiscoverySortableController from "discourse/controllers/discovery-sortable"; +import { inject as controller } from "@ember/controller"; import discourseComputed, { observes } from "discourse-common/utils/decorators"; import BulkTopicSelection from "discourse/mixins/bulk-topic-selection"; import FilterModeMixin from "discourse/mixins/filter-mode"; import I18n from "I18n"; import NavItem from "discourse/models/nav-item"; import Topic from "discourse/models/topic"; -import { alias } from "@ember/object/computed"; +import { readOnly } from "@ember/object/computed"; import bootbox from "bootbox"; -import { queryParams } from "discourse/controllers/discovery-sortable"; import { endWith } from "discourse/lib/computed"; +import { action } from "@ember/object"; -export default Controller.extend(BulkTopicSelection, FilterModeMixin, { - application: controller(), +export default DiscoverySortableController.extend( + BulkTopicSelection, + FilterModeMixin, + { + application: controller(), - tag: null, - additionalTags: null, - list: null, - canAdminTag: alias("currentUser.staff"), - navMode: "latest", - loading: false, - canCreateTopic: false, - order: "default", - ascending: false, - status: null, - state: null, - search: null, - max_posts: null, - q: null, - showInfo: false, - top: endWith("list.filter", "top"), - period: alias("list.for_period"), + tag: null, + additionalTags: null, + list: null, + canAdminTag: readOnly("currentUser.staff"), + navMode: "latest", + loading: false, + canCreateTopic: false, + showInfo: false, + top: endWith("list.filter", "top"), - @discourseComputed( - "canCreateTopic", - "category", - "canCreateTopicOnCategory", - "tag", - "canCreateTopicOnTag" - ) - createTopicDisabled( - canCreateTopic, - category, - canCreateTopicOnCategory, - tag, - canCreateTopicOnTag - ) { - return ( - !canCreateTopic || - (category && !canCreateTopicOnCategory) || - (tag && !canCreateTopicOnTag) - ); - }, + @discourseComputed( + "canCreateTopic", + "category", + "canCreateTopicOnCategory", + "tag", + "canCreateTopicOnTag" + ) + createTopicDisabled( + canCreateTopic, + category, + canCreateTopicOnCategory, + tag, + canCreateTopicOnTag + ) { + return ( + !canCreateTopic || + (category && !canCreateTopicOnCategory) || + (tag && !canCreateTopicOnTag) + ); + }, - queryParams: Object.keys(queryParams), - - @discourseComputed("category", "tag.id", "filterType", "noSubcategories") - navItems(category, tagId, filterType, noSubcategories) { - return NavItem.buildList(category, { - tagId, - filterType, - noSubcategories, - siteSettings: this.siteSettings, - }); - }, - - @discourseComputed("category") - showTagFilter() { - return true; - }, - - @observes("list.canLoadMore") - _showFooter() { - this.set("application.showFooter", !this.get("list.canLoadMore")); - }, - - @discourseComputed("navMode", "list.topics.length", "loading") - footerMessage(navMode, listTopicsLength, loading) { - if (loading) { - return; - } - - if (listTopicsLength === 0) { - return I18n.t(`tagging.topics.none.${navMode}`, { - tag: this.get("tag.id"), + @discourseComputed("category", "tag.id", "filterType", "noSubcategories") + navItems(category, tagId, filterType, noSubcategories) { + return NavItem.buildList(category, { + tagId, + filterType, + noSubcategories, + siteSettings: this.siteSettings, }); - } else { - return I18n.t(`topics.bottom.tag`, { - tag: this.get("tag.id"), - }); - } - }, + }, - @discourseComputed("list.filter", "list.topics.length") - showDismissRead(filter, topicsLength) { - return this._isFilterPage(filter, "unread") && topicsLength > 0; - }, + @observes("list.canLoadMore") + _showFooter() { + this.set("application.showFooter", !this.list?.canLoadMore); + }, - @discourseComputed("list.filter", "list.topics.length") - showResetNew(filter, topicsLength) { - return this._isFilterPage(filter, "new") && topicsLength > 0; - }, + @discourseComputed("navMode", "list.topics.length", "loading") + footerMessage(navMode, listTopicsLength, loading) { + if (loading) { + return; + } - actions: { + if (listTopicsLength === 0) { + return I18n.t(`tagging.topics.none.${navMode}`, { + tag: this.tag?.id, + }); + } else { + return I18n.t("topics.bottom.tag", { + tag: this.tag?.id, + }); + } + }, + + @discourseComputed("list.filter", "list.topics.length") + showDismissRead(filter, topicsLength) { + return this._isFilterPage(filter, "unread") && topicsLength > 0; + }, + + @discourseComputed("list.filter", "list.topics.length") + showResetNew(filter, topicsLength) { + return this._isFilterPage(filter, "new") && topicsLength > 0; + }, + + @action resetNew() { const tracked = (this.router.currentRoute.queryParams["f"] || this.router.currentRoute.queryParams["filter"]) === "tracked"; - let topicIds = this.selected - ? this.selected.map((topic) => topic.id) - : null; + let topicIds = this.selected ? this.selected.mapBy("id") : null; Topic.resetNew(this.category, !this.noSubcategories, { tracked, tag: this.tag, topicIds, }).then(() => - this.send( - "refresh", - tracked ? { skipResettingParams: ["filter", "f"] } : {} - ) + this.refresh(tracked ? { skipResettingParams: ["filter", "f"] } : {}) ); }, + @action showInserted() { const tracker = this.topicTrackingState; - this.list.loadBefore(tracker.get("newIncoming"), true); + this.list.loadBefore(tracker.newIncoming, true); tracker.resetTracking(); return false; }, + @action changeSort(order) { if (order === this.order) { this.toggleProperty("ascending"); } else { this.setProperties({ order, ascending: false }); } - - let params = { order, ascending: this.ascending }; - if (this.period) { - params.period = this.period; - } - - this.transitionToRoute({ - queryParams: params, - }); }, + @action changePeriod(p) { this.set("period", p); - - let params = { period: this.period }; - - if (!(this.order === "default" && this.ascending === false)) { - params = Object.assign(params, { - order: this.order, - ascending: this.ascending, - }); - } - - this.transitionToRoute({ - queryParams: params, - }); }, + @action toggleInfo() { this.toggleProperty("showInfo"); }, + @action refresh() { return this.store .findFiltered("topicList", { - filter: this.get("list.filter"), + filter: this.list?.filter, }) .then((list) => { this.set("list", list); @@ -179,6 +146,7 @@ export default Controller.extend(BulkTopicSelection, FilterModeMixin, { }); }, + @action deleteTag(tagInfo) { const numTopics = this.get("list.topic_list.tags.firstObject.topic_count") || 0; @@ -208,6 +176,7 @@ export default Controller.extend(BulkTopicSelection, FilterModeMixin, { }); }, + @action changeTagNotificationLevel(notificationLevel) { this.tagNotification .update({ notification_level: notificationLevel }) @@ -222,5 +191,5 @@ export default Controller.extend(BulkTopicSelection, FilterModeMixin, { ); }); }, - }, -}); + } +); diff --git a/app/assets/javascripts/discourse/app/routes/tag-show.js b/app/assets/javascripts/discourse/app/routes/tag-show.js index 8f4965dae2a..71afbf1ea35 100644 --- a/app/assets/javascripts/discourse/app/routes/tag-show.js +++ b/app/assets/javascripts/discourse/app/routes/tag-show.js @@ -23,63 +23,56 @@ export default DiscourseRoute.extend(FilterModeMixin, { queryParams, - renderTemplate() { - const controller = this.controllerFor("tag.show"); - this.render("tags.show", { controller }); - }, + controllerName: "tag.show", + templateName: "tag.show", - model(params) { - const tag = this.store.createRecord("tag", { - id: escapeExpression(params.tag_id), - }); - if (params.additional_tags) { - this.set( - "additionalTags", - params.additional_tags.split("/").map((t) => { - return this.store.createRecord("tag", { - id: escapeExpression(t), - }).id; - }) - ); - } else { - this.set("additionalTags", null); - } - - this.set("filterType", this.navMode.split("/")[0]); - - this.set("categorySlugPathWithID", params.category_slug_path_with_id); - - if (tag && tag.get("id") !== "none" && this.currentUser) { - // If logged in, we should get the tag's user settings - return this.store - .find("tagNotification", tag.get("id").toLowerCase()) - .then((tn) => { - this.set("tagNotification", tn); - return tag; - }); - } - - return tag; - }, - - afterModel(tag, transition) { + beforeModel() { const controller = this.controllerFor("tag.show"); controller.setProperties({ loading: true, showInfo: false, }); + }, - const params = filterQueryParams(transition.to.queryParams, {}); - const category = this.categorySlugPathWithID - ? Category.findBySlugPathWithID(this.categorySlugPathWithID) + async model(params, transition) { + const tag = this.store.createRecord("tag", { + id: escapeExpression(params.tag_id), + }); + + let additionalTags; + + if (params.additional_tags) { + additionalTags = params.additional_tags.split("/").map((t) => { + return this.store.createRecord("tag", { + id: escapeExpression(t), + }).id; + }); + } + + const filterType = this.navMode.split("/")[0]; + + let tagNotification; + if (tag && tag.id !== "none" && this.currentUser) { + // If logged in, we should get the tag's user settings + tagNotification = await this.store.find( + "tagNotification", + tag.id.toLowerCase() + ); + } + + const category = params.category_slug_path_with_id + ? Category.findBySlugPathWithID(params.category_slug_path_with_id) : null; + const filteredQueryParams = filterQueryParams( + transition.to.queryParams, + {} + ); const topicFilter = this.navMode; const tagId = tag ? tag.id.toLowerCase() : "none"; let filter; if (category) { category.setupGroupsAndPermissions(); - this.set("category", category); filter = `tags/c/${Category.slugFor(category)}/${category.id}`; if (this.noSubcategories) { @@ -87,36 +80,55 @@ export default DiscourseRoute.extend(FilterModeMixin, { } filter += `/${tagId}/l/${topicFilter}`; - } else if (this.additionalTags) { - this.set("category", null); - filter = `tags/intersection/${tagId}/${this.additionalTags.join("/")}`; + } else if (additionalTags) { + filter = `tags/intersection/${tagId}/${additionalTags.join("/")}`; } else { - this.set("category", null); filter = `tag/${tagId}/l/${topicFilter}`; } - return findTopicList(this.store, this.topicTrackingState, filter, params, { - cached: this.isPoppedState(transition), - }).then((list) => { - if (list.topic_list.tags && list.topic_list.tags.length === 1) { - // Update name of tag (case might be different) - tag.setProperties({ - id: list.topic_list.tags[0].name, - staff: list.topic_list.tags[0].staff, - }); + const list = await findTopicList( + this.store, + this.topicTrackingState, + filter, + filteredQueryParams, + { + cached: this.isPoppedState(transition), } + ); - setTopicList(list); - - controller.setProperties({ - list, - canCreateTopic: list.get("can_create_topic"), - loading: false, - canCreateTopicOnCategory: - this.get("category.permission") === PermissionType.FULL, - canCreateTopicOnTag: !tag.get("staff") || this.get("currentUser.staff"), + if (list.topic_list.tags && list.topic_list.tags.length === 1) { + // Update name of tag (case might be different) + tag.setProperties({ + id: list.topic_list.tags[0].name, + staff: list.topic_list.tags[0].staff, }); + } + + setTopicList(list); + + return { + tag, + category, + list, + additionalTags, + filterType, + tagNotification, + canCreateTopic: list.can_create_topic, + canCreateTopicOnCategory: category?.permission === PermissionType.FULL, + canCreateTopicOnTag: !tag.staff || this.currentUser?.staff, + }; + }, + + setupController(controller, model) { + this.controllerFor("tag.show").setProperties({ + model: model.tag, + ...model, + period: model.list.for_period, + navMode: this.navMode, + noSubcategories: this.noSubcategories, + loading: false, }); + this.searchService.set("searchContext", model.tag.searchContext); }, titleToken() { @@ -125,24 +137,24 @@ export default DiscourseRoute.extend(FilterModeMixin, { ); const controller = this.controllerFor("tag.show"); - if (controller.get("model.id")) { - if (this.category) { + if (controller.tag?.id) { + if (controller.category) { return I18n.t("tagging.filters.with_category", { filter: filterText, - tag: controller.get("model.id"), - category: this.get("category.name"), + tag: controller.tag.id, + category: controller.category.name, }); } else { return I18n.t("tagging.filters.without_category", { filter: filterText, - tag: controller.get("model.id"), + tag: controller.tag.id, }); } } else { - if (this.category) { + if (controller.category) { return I18n.t("tagging.filters.untagged_with_category", { filter: filterText, - category: this.get("category.name"), + category: controller.category.name, }); } else { return I18n.t("tagging.filters.untagged_without_category", { @@ -152,20 +164,6 @@ export default DiscourseRoute.extend(FilterModeMixin, { } }, - setupController(controller, model) { - this.controllerFor("tag.show").setProperties({ - model, - tag: model, - additionalTags: this.additionalTags, - category: this.category, - filterType: this.filterType, - navMode: this.navMode, - tagNotification: this.tagNotification, - noSubcategories: this.noSubcategories, - }); - this.searchService.set("searchContext", model.get("searchContext")); - }, - deactivate() { this._super(...arguments); this.searchService.set("searchContext", null); @@ -178,21 +176,21 @@ export default DiscourseRoute.extend(FilterModeMixin, { @action createTopic() { - if (this.get("currentUser.has_topic_draft")) { + if (this.currentUser?.has_topic_draft) { this.openTopicDraft(); } else { const controller = this.controllerFor("tag.show"); const composerController = this.controllerFor("composer"); composerController .open({ - categoryId: controller.get("category.id"), + categoryId: controller.category?.id, action: Composer.CREATE_TOPIC, draftKey: Composer.NEW_TOPIC_KEY, }) .then(() => { // Pre-fill the tags input field - if (composerController.canEditTags && controller.get("model.id")) { - const composerModel = this.controllerFor("composer").get("model"); + if (composerController.canEditTags && controller.tag?.id) { + const composerModel = this.controllerFor("composer").model; composerModel.set( "tags", [ @@ -215,9 +213,9 @@ export default DiscourseRoute.extend(FilterModeMixin, { dismissRead(operationType) { const controller = this.controllerFor("tags-show"); let options = { - tagName: controller.get("tag.id"), + tagName: controller.tag?.id, }; - const categoryId = controller.get("category.id"); + const categoryId = controller.category?.id; if (categoryId) { options = Object.assign({}, options, { diff --git a/app/assets/javascripts/discourse/app/templates/tags/show.hbs b/app/assets/javascripts/discourse/app/templates/tag/show.hbs similarity index 100% rename from app/assets/javascripts/discourse/app/templates/tags/show.hbs rename to app/assets/javascripts/discourse/app/templates/tag/show.hbs