diff --git a/app/assets/javascripts/discourse/components/edit-topic-timer-form.js b/app/assets/javascripts/discourse/components/edit-topic-timer-form.js index 4d2be762d3d..361a2acbf28 100644 --- a/app/assets/javascripts/discourse/components/edit-topic-timer-form.js +++ b/app/assets/javascripts/discourse/components/edit-topic-timer-form.js @@ -1,18 +1,15 @@ -import { isEmpty } from "@ember/utils"; import { equal, or, readOnly } from "@ember/object/computed"; import { schedule } from "@ember/runloop"; import Component from "@ember/component"; -import discourseComputed, { - observes, - on -} from "discourse-common/utils/decorators"; +import discourseComputed, { observes } from "discourse-common/utils/decorators"; import { PUBLISH_TO_CATEGORY_STATUS_TYPE, OPEN_STATUS_TYPE, DELETE_STATUS_TYPE, REMINDER_TYPE, CLOSE_STATUS_TYPE, - BUMP_TYPE + BUMP_TYPE, + DELETE_REPLIES_TYPE } from "discourse/controllers/edit-topic-timer"; export default Component.extend({ @@ -23,15 +20,18 @@ export default Component.extend({ autoBump: equal("selection", BUMP_TYPE), publishToCategory: equal("selection", PUBLISH_TO_CATEGORY_STATUS_TYPE), reminder: equal("selection", REMINDER_TYPE), + autoDeleteReplies: equal("selection", DELETE_REPLIES_TYPE), showTimeOnly: or("autoOpen", "autoDelete", "reminder", "autoBump"), - - @discourseComputed( - "topicTimer.updateTime", + showFutureDateInput: or( + "showTimeOnly", "publishToCategory", - "topicTimer.category_id" - ) - saveDisabled(updateTime, publishToCategory, topicTimerCategoryId) { - return isEmpty(updateTime) || (publishToCategory && !topicTimerCategoryId); + "autoClose", + "autoDeleteReplies" + ), + + @discourseComputed("autoDeleteReplies") + durationType(autoDeleteReplies) { + return autoDeleteReplies ? "days" : "hours"; }, @discourseComputed("topic.visible") @@ -39,25 +39,6 @@ export default Component.extend({ if (visible) return this.get("topic.category_id"); }, - @on("init") - @observes("topicTimer", "topicTimer.execute_at", "topicTimer.duration") - _setUpdateTime() { - let time = null; - const executeAt = this.get("topicTimer.execute_at"); - - if (executeAt && this.get("topicTimer.based_on_last_post")) { - time = this.get("topicTimer.duration"); - } else if (executeAt) { - const closeTime = moment(executeAt); - - if (closeTime > moment()) { - time = closeTime.format("YYYY-MM-DD HH:mm"); - } - } - - this.set("topicTimer.updateTime", time); - }, - @observes("selection") _updateBasedOnLastPost() { if (!this.autoClose) { @@ -79,11 +60,5 @@ export default Component.extend({ ); } }); - }, - - actions: { - onChangeTimerType(value) { - this.set("topicTimer.status_type", value); - } } }); diff --git a/app/assets/javascripts/discourse/components/future-date-input.js b/app/assets/javascripts/discourse/components/future-date-input.js index d84ab3c3340..d54e68e7826 100644 --- a/app/assets/javascripts/discourse/components/future-date-input.js +++ b/app/assets/javascripts/discourse/components/future-date-input.js @@ -1,5 +1,5 @@ import { isEmpty } from "@ember/utils"; -import { equal, and, empty } from "@ember/object/computed"; +import { equal, and, empty, or } from "@ember/object/computed"; import Component from "@ember/component"; import discourseComputed, { observes } from "discourse-common/utils/decorators"; import { FORMAT } from "select-kit/components/future-date-input-selector"; @@ -10,10 +10,13 @@ export default Component.extend({ date: null, time: null, includeDateTime: true, + duration: null, + durationType: "hours", isCustom: equal("selection", "pick_date_and_time"), isBasedOnLastPost: equal("selection", "set_based_on_last_post"), displayDateAndTimePicker: and("includeDateTime", "isCustom"), displayLabel: null, + displayNumberInput: or("isBasedOnLastPost", "isBasedOnDuration"), init() { this._super(...arguments); @@ -21,6 +24,8 @@ export default Component.extend({ if (this.input) { if (this.basedOnLastPost) { this.set("selection", "set_based_on_last_post"); + } else if (this.isBasedOnDuration) { + this.set("selection", null); } else { const datetime = moment(this.input); this.setProperties({ @@ -57,28 +62,44 @@ export default Component.extend({ this.set("basedOnLastPost", this.isBasedOnLastPost); }, - @discourseComputed("input", "isBasedOnLastPost") - duration(input, isBasedOnLastPost) { - const now = moment(); - - if (isBasedOnLastPost) { - return parseFloat(input); - } else { - return moment(input) - now; - } + @observes("duration") + _updateDuration() { + this.attrs.onChangeDuration && + this.attrs.onChangeDuration(parseInt(this.duration, 0)); }, - @discourseComputed("input", "isBasedOnLastPost") - executeAt(input, isBasedOnLastPost) { - if (isBasedOnLastPost) { - return moment() - .add(input, "hours") + @discourseComputed( + "input", + "duration", + "isBasedOnLastPost", + "isBasedOnDuration", + "durationType" + ) + executeAt( + input, + duration, + isBasedOnLastPost, + isBasedOnDuration, + durationType + ) { + if (isBasedOnLastPost || isBasedOnDuration) { + return moment(input) + .add(parseInt(duration, 0), durationType) .format(FORMAT); } else { return input; } }, + @discourseComputed("durationType") + durationLabel(durationType) { + return I18n.t( + `topic.topic_status_update.num_of_${ + durationType === "hours" ? "hours" : "days" + }` + ); + }, + didReceiveAttrs() { this._super(...arguments); @@ -92,7 +113,9 @@ export default Component.extend({ "date", "time", "willCloseImmediately", - "categoryId" + "categoryId", + "displayNumberInput", + "duration" ) showTopicStatusInfo( statusType, @@ -101,7 +124,9 @@ export default Component.extend({ date, time, willCloseImmediately, - categoryId + categoryId, + displayNumberInput, + duration ) { if (!statusType || willCloseImmediately) return false; @@ -114,6 +139,8 @@ export default Component.extend({ return moment(`${date}${time ? " " + time : ""}`).isAfter(moment()); } return time; + } else if (displayNumberInput) { + return duration; } else { return input; } diff --git a/app/assets/javascripts/discourse/components/topic-timer-info.js b/app/assets/javascripts/discourse/components/topic-timer-info.js index 66663b062dd..30eb177ca39 100644 --- a/app/assets/javascripts/discourse/components/topic-timer-info.js +++ b/app/assets/javascripts/discourse/components/topic-timer-info.js @@ -3,7 +3,10 @@ import { cancel, later } from "@ember/runloop"; import Component from "@ember/component"; import { iconHTML } from "discourse-common/lib/icon-library"; import Category from "discourse/models/category"; -import { REMINDER_TYPE } from "discourse/controllers/edit-topic-timer"; +import { + REMINDER_TYPE, + DELETE_REPLIES_TYPE +} from "discourse/controllers/edit-topic-timer"; import ENV from "discourse-common/config/environment"; export default Component.extend({ @@ -28,7 +31,13 @@ export default Component.extend({ }, renderTopicTimer() { - if (!this.executeAt || this.executeAt < moment()) { + const isDeleteRepliesType = this.statusType === DELETE_REPLIES_TYPE; + + if ( + !isDeleteRepliesType && + !this.basedOnLastPost && + (!this.executeAt || this.executeAt < moment()) + ) { this.set("showTopicTimer", null); return; } @@ -40,7 +49,7 @@ export default Component.extend({ const statusUpdateAt = moment(this.executeAt); const duration = moment.duration(statusUpdateAt - moment()); const minutesLeft = duration.asMinutes(); - if (minutesLeft > 0) { + if (minutesLeft > 0 || isDeleteRepliesType || this.basedOnLastPost) { let rerenderDelay = 1000; if (minutesLeft > 2160) { rerenderDelay = 12 * 60 * 60000; @@ -51,11 +60,15 @@ export default Component.extend({ } else if (minutesLeft > 2) { rerenderDelay = 60000; } - let autoCloseHours = this.duration || 0; + let durationHours = parseInt(this.duration, 0) || 0; + + if (isDeleteRepliesType) { + durationHours *= 24; + } let options = { timeLeft: duration.humanize(true), - duration: moment.duration(autoCloseHours, "hours").humanize() + duration: moment.duration(durationHours, "hours").humanize() }; const categoryId = this.categoryId; diff --git a/app/assets/javascripts/discourse/controllers/edit-topic-timer.js b/app/assets/javascripts/discourse/controllers/edit-topic-timer.js index e9117532f05..461fa3c64d1 100644 --- a/app/assets/javascripts/discourse/controllers/edit-topic-timer.js +++ b/app/assets/javascripts/discourse/controllers/edit-topic-timer.js @@ -4,6 +4,7 @@ import discourseComputed from "discourse-common/utils/decorators"; import ModalFunctionality from "discourse/mixins/modal-functionality"; import TopicTimer from "discourse/models/topic-timer"; import { popupAjaxError } from "discourse/lib/ajax-error"; +import { FORMAT } from "select-kit/components/future-date-input-selector"; export const CLOSE_STATUS_TYPE = "close"; export const OPEN_STATUS_TYPE = "open"; @@ -11,6 +12,7 @@ export const PUBLISH_TO_CATEGORY_STATUS_TYPE = "publish_to_category"; export const DELETE_STATUS_TYPE = "delete"; export const REMINDER_TYPE = "reminder"; export const BUMP_TYPE = "bump"; +export const DELETE_REPLIES_TYPE = "delete_replies"; export default Controller.extend(ModalFunctionality, { loading: false, @@ -41,10 +43,16 @@ export default Controller.extend(ModalFunctionality, { } ]; if (this.currentUser.get("staff")) { - types.push({ - id: DELETE_STATUS_TYPE, - name: I18n.t("topic.auto_delete.title") - }); + types.push( + { + id: DELETE_STATUS_TYPE, + name: I18n.t("topic.auto_delete.title") + }, + { + id: DELETE_REPLIES_TYPE, + name: I18n.t("topic.auto_delete_replies.title") + } + ); } return types; }, @@ -68,7 +76,7 @@ export default Controller.extend(ModalFunctionality, { return "true" === isPublic ? publicTopicTimer : privateTopicTimer; }, - _setTimer(time, statusType) { + _setTimer(time, duration, statusType) { this.set("loading", true); TopicTimer.updateStatus( @@ -76,10 +84,11 @@ export default Controller.extend(ModalFunctionality, { time, this.get("topicTimer.based_on_last_post"), statusType, - this.get("topicTimer.category_id") + this.get("topicTimer.category_id"), + duration ) .then(result => { - if (time) { + if (time || duration) { this.send("closeModal"); setProperties(this.topicTimer, { @@ -103,17 +112,39 @@ export default Controller.extend(ModalFunctionality, { .finally(() => this.set("loading", false)); }, + onShow() { + let time = null; + const executeAt = this.get("topicTimer.execute_at"); + + if (executeAt) { + const closeTime = moment(executeAt); + + if (closeTime > moment()) { + time = closeTime.format(FORMAT); + } + } + + this.send("onChangeInput", time); + }, + actions: { onChangeStatusType(value) { this.set("topicTimer.status_type", value); }, - onChangeUpdateTime(value) { + onChangeInput(value) { this.set("topicTimer.updateTime", value); }, + onChangeDuration(value) { + this.set("topicTimer.duration", value); + }, + saveTimer() { - if (!this.get("topicTimer.updateTime")) { + if ( + !this.get("topicTimer.updateTime") && + !this.get("topicTimer.duration") + ) { this.flash( I18n.t("topic.topic_status_update.time_frame_required"), "alert-error" @@ -123,12 +154,13 @@ export default Controller.extend(ModalFunctionality, { this._setTimer( this.get("topicTimer.updateTime"), + this.get("topicTimer.duration"), this.get("topicTimer.status_type") ); }, removeTimer() { - this._setTimer(null, this.get("topicTimer.status_type")); + this._setTimer(null, null, this.get("topicTimer.status_type")); } } }); diff --git a/app/assets/javascripts/discourse/models/topic-timer.js b/app/assets/javascripts/discourse/models/topic-timer.js index 31b51ae9003..1afe0e92dc3 100644 --- a/app/assets/javascripts/discourse/models/topic-timer.js +++ b/app/assets/javascripts/discourse/models/topic-timer.js @@ -4,7 +4,14 @@ import RestModel from "discourse/models/rest"; const TopicTimer = RestModel.extend({}); TopicTimer.reopenClass({ - updateStatus(topicId, time, basedOnLastPost, statusType, categoryId) { + updateStatus( + topicId, + time, + basedOnLastPost, + statusType, + categoryId, + duration + ) { let data = { time, status_type: statusType @@ -12,6 +19,7 @@ TopicTimer.reopenClass({ if (basedOnLastPost) data.based_on_last_post = basedOnLastPost; if (categoryId) data.category_id = categoryId; + if (duration) data.duration = duration; return ajax({ url: `/t/${topicId}/timer`, diff --git a/app/assets/javascripts/discourse/templates/components/edit-topic-timer-form.hbs b/app/assets/javascripts/discourse/templates/components/edit-topic-timer-form.hbs index 1fbfa3f9797..e5ad76f9794 100644 --- a/app/assets/javascripts/discourse/templates/components/edit-topic-timer-form.hbs +++ b/app/assets/javascripts/discourse/templates/components/edit-topic-timer-form.hbs @@ -7,46 +7,32 @@ value=selection }} - -