diff --git a/app/assets/javascripts/discourse/app/components/edit-category-settings.js b/app/assets/javascripts/discourse/app/components/edit-category-settings.js index f04ffa6721a..e7d2914f1f5 100644 --- a/app/assets/javascripts/discourse/app/components/edit-category-settings.js +++ b/app/assets/javascripts/discourse/app/components/edit-category-settings.js @@ -5,6 +5,7 @@ import { SEARCH_PRIORITIES } from "discourse/lib/constants"; import { buildCategoryPanel } from "discourse/components/edit-category-panel"; import discourseComputed from "discourse-common/utils/decorators"; import { setting } from "discourse/lib/computed"; +import { action } from "@ember/object"; const categorySortCriteria = []; export function addCategorySortCriteria(criteria) { @@ -126,4 +127,15 @@ export default buildCategoryPanel("settings", { { name: I18n.t("category.sort_descending"), value: false }, ]; }, + + @discourseComputed + hiddenRelativeIntervals() { + return ["mins"]; + }, + + @action + onAutoCloseDurationChange(minutes) { + let hours = minutes / 60; + this.set("category.auto_close_hours", hours); + }, }); diff --git a/app/assets/javascripts/discourse/app/components/edit-topic-timer-form.js b/app/assets/javascripts/discourse/app/components/edit-topic-timer-form.js index 4c35310ab86..2e10a86a762 100644 --- a/app/assets/javascripts/discourse/app/components/edit-topic-timer-form.js +++ b/app/assets/javascripts/discourse/app/components/edit-topic-timer-form.js @@ -153,7 +153,7 @@ export default Component.extend({ "useDuration", "topicTimer.duration_minutes" ) - showTopicStatusInfo( + showTopicTimerInfo( statusType, isCustom, updateTime, diff --git a/app/assets/javascripts/discourse/app/components/relative-time-picker.js b/app/assets/javascripts/discourse/app/components/relative-time-picker.js index 554947f279b..45e04d50719 100644 --- a/app/assets/javascripts/discourse/app/components/relative-time-picker.js +++ b/app/assets/javascripts/discourse/app/components/relative-time-picker.js @@ -8,11 +8,53 @@ export default Component.extend({ tagName: "", selectedInterval: "mins", durationMinutes: null, + durationHours: null, duration: null, + hiddenIntervals: null, @on("init") cloneDuration() { let mins = this.durationMinutes; + let hours = this.durationHours; + + if (hours && mins) { + throw new Error( + "relative-time needs initial duration in hours OR minutes, both are not supported" + ); + } + + if (hours) { + this._setInitialDurationFromHours(hours); + } else { + this._setInitialDurationFromMinutes(mins); + } + }, + + @on("init") + setHiddenIntervals() { + this.hiddenIntervals = this.hiddenIntervals || []; + }, + + _setInitialDurationFromHours(hours) { + if (hours >= 730) { + this.setProperties({ + duration: Math.floor(hours / 30 / 24), + selectedInterval: "months", + }); + } else if (hours >= 24) { + this.setProperties({ + duration: Math.floor(hours / 24), + selectedInterval: "days", + }); + } else { + this.setProperties({ + duration: hours, + selectedInterval: "hours", + }); + } + }, + + _setInitialDurationFromMinutes(mins) { if (mins >= 43800) { this.setProperties({ duration: Math.floor(mins / 30 / 60 / 24), @@ -36,6 +78,16 @@ export default Component.extend({ } }, + @discourseComputed("selectedInterval") + durationMin(selectedInterval) { + return selectedInterval === "mins" ? 1 : 0.1; + }, + + @discourseComputed("selectedInterval") + durationStep(selectedInterval) { + return selectedInterval === "mins" ? 1 : 0.05; + }, + @discourseComputed("duration") intervals(duration) { const count = duration ? parseFloat(duration) : 0; @@ -57,7 +109,7 @@ export default Component.extend({ id: "months", name: I18n.t("relative_time_picker.months", { count }), }, - ]; + ].filter((interval) => !this.hiddenIntervals.includes(interval.id)); }, @discourseComputed("selectedInterval", "duration") @@ -68,7 +120,8 @@ export default Component.extend({ switch (interval) { case "mins": - mins = duration; + // we round up here in case the user manually inputted a step < 1 + mins = Math.ceil(duration); break; case "hours": mins = duration * 60; diff --git a/app/assets/javascripts/discourse/app/components/topic-timer-info.js b/app/assets/javascripts/discourse/app/components/topic-timer-info.js index ea3e1dc1a0b..0eb2edd7489 100644 --- a/app/assets/javascripts/discourse/app/components/topic-timer-info.js +++ b/app/assets/javascripts/discourse/app/components/topic-timer-info.js @@ -3,28 +3,46 @@ import Category from "discourse/models/category"; import Component from "@ember/component"; import { DELETE_REPLIES_TYPE } from "discourse/controllers/edit-topic-timer"; import I18n from "I18n"; -import discourseComputed from "discourse-common/utils/decorators"; +import discourseComputed, { on } from "discourse-common/utils/decorators"; import { iconHTML } from "discourse-common/lib/icon-library"; import { isTesting } from "discourse-common/config/environment"; export default Component.extend({ - classNames: ["topic-status-info"], + classNames: ["topic-timer-info"], _delayedRerender: null, clockIcon: `${iconHTML("far-clock")}`.htmlSafe(), - trashCanIcon: `${iconHTML("trash-alt")}`.htmlSafe(), - trashCanTitle: I18n.t("post.controls.remove_timer"), + trashLabel: I18n.t("post.controls.remove_timer"), title: null, notice: null, showTopicTimer: null, + showTopicTimerModal: null, + removeTopicTimer: null, + + @on("didReceiveAttrs") + setupRenderer() { + this.renderTopicTimer(); + }, + + @on("willDestroyElement") + cancelDelayedRenderer() { + if (this._delayedRerender) { + cancel(this._delayedRerender); + } + }, @discourseComputed - canRemoveTimer() { + canModifyTimer() { return this.currentUser && this.currentUser.get("canManageTopic"); }, - @discourseComputed("canRemoveTimer", "removeTopicTimer") - showTrashCan(canRemoveTimer, removeTopicTimer) { - return canRemoveTimer && removeTopicTimer; + @discourseComputed("canModifyTimer", "removeTopicTimer") + showTrashCan(canModifyTimer, removeTopicTimer) { + return canModifyTimer && removeTopicTimer; + }, + + @discourseComputed("canModifyTimer", "showTopicTimerModal") + showEdit(canModifyTimer, showTopicTimerModal) { + return canModifyTimer && showTopicTimerModal; }, renderTopicTimer() { @@ -102,31 +120,6 @@ export default Component.extend({ } }, - didReceiveAttrs() { - this._super(...arguments); - this.renderTopicTimer(); - }, - - didInsertElement() { - this._super(...arguments); - - if (this.removeTopicTimer) { - $(this.element).on( - "click.topic-timer-remove", - "button", - this.removeTopicTimer - ); - } - }, - - willDestroyElement() { - $(this.element).off("click.topic-timer-remove", this.removeTopicTimer); - - if (this._delayedRerender) { - cancel(this._delayedRerender); - } - }, - _noticeKey() { let statusType = this.statusType; if (statusType === "silent_close") { diff --git a/app/assets/javascripts/discourse/app/controllers/edit-topic-timer.js b/app/assets/javascripts/discourse/app/controllers/edit-topic-timer.js index a60f541d4fd..01c0286b134 100644 --- a/app/assets/javascripts/discourse/app/controllers/edit-topic-timer.js +++ b/app/assets/javascripts/discourse/app/controllers/edit-topic-timer.js @@ -29,14 +29,16 @@ export default Controller.extend(ModalFunctionality, { closed ? "topic.temp_open.title" : "topic.auto_close.title" ), }, - { + ]; + + if (!closed) { + types.push({ id: CLOSE_AFTER_LAST_POST_STATUS_TYPE, - name: I18n.t( - closed - ? "topic.temp_open.title" - : "topic.auto_close_after_last_post.title" - ), - }, + name: I18n.t("topic.auto_close_after_last_post.title"), + }); + } + + types.push( { id: OPEN_STATUS_TYPE, name: I18n.t( @@ -50,8 +52,9 @@ export default Controller.extend(ModalFunctionality, { { id: BUMP_TYPE, name: I18n.t("topic.auto_bump.title"), - }, - ]; + } + ); + if (this.currentUser.get("staff")) { types.push( { diff --git a/app/assets/javascripts/discourse/app/routes/topic.js b/app/assets/javascripts/discourse/app/routes/topic.js index 06c1351a859..ae9974569fa 100644 --- a/app/assets/javascripts/discourse/app/routes/topic.js +++ b/app/assets/javascripts/discourse/app/routes/topic.js @@ -105,7 +105,7 @@ const TopicRoute = DiscourseRoute.extend({ }); }, - showTopicStatusUpdate() { + showTopicTimerModal() { const model = this.modelFor("topic"); const topicTimer = model.get("topic_timer"); diff --git a/app/assets/javascripts/discourse/app/templates/components/edit-category-settings.hbs b/app/assets/javascripts/discourse/app/templates/components/edit-category-settings.hbs index 33e59c3a3b6..8a8512bbf3a 100644 --- a/app/assets/javascripts/discourse/app/templates/components/edit-category-settings.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/edit-category-settings.hbs @@ -114,7 +114,13 @@ - {{text-field value=category.auto_close_hours id="topic-auto-close" type="number"}} +
+ {{relative-time-picker + id="topic-auto-close" + durationHours=category.auto_close_hours + hiddenIntervals=hiddenRelativeIntervals + onChange=(action "onAutoCloseDurationChange")}} +