DEV: Convert edit-topic-timer-form to glimmer (#25995)

This commit is contained in:
Jarek Radosz 2024-03-06 21:13:38 +01:00 committed by GitHub
parent d96b7b14ce
commit e01f75cb32
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 170 additions and 200 deletions

View File

@ -1,61 +1,66 @@
<form>
<div class="control-group">
<ComboBox
@onChange={{this.onChangeStatusType}}
@content={{this.timerTypes}}
@onChange={{@onChangeStatusType}}
@content={{@timerTypes}}
@value={{this.statusType}}
class="timer-type"
/>
</div>
{{#if this.publishToCategory}}
<div class="control-group">
<label class="control-label">{{i18n
"topic.topic_status_update.publish_to"
}}</label>
<label class="control-label">
{{i18n "topic.topic_status_update.publish_to"}}
</label>
<CategoryChooser
@value={{this.topicTimer.category_id}}
@onChange={{fn (mut this.topicTimer.category_id)}}
@value={{@topicTimer.category_id}}
@onChange={{fn (mut @topicTimer.category_id)}}
@options={{hash excludeCategoryId=this.excludeCategoryId}}
/>
</div>
{{/if}}
{{#if this.showFutureDateInput}}
<label class="control-label">{{i18n
"topic.topic_status_update.when"
}}</label>
<label class="control-label">
{{i18n "topic.topic_status_update.when"}}
</label>
<TimeShortcutPicker
@timeShortcuts={{this.timeOptions}}
@prefilledDatetime={{this.topicTimer.execute_at}}
@prefilledDatetime={{@topicTimer.execute_at}}
@onTimeSelected={{this.onTimeSelected}}
@hiddenOptions={{this.hiddenTimeShortcutOptions}}
@_itsatrap={{this._itsatrap}}
/>
{{/if}}
{{#if this.useDuration}}
<div class="controls">
<label class="control-label">{{i18n
"topic.topic_status_update.duration"
}}</label>
<label class="control-label">
{{i18n "topic.topic_status_update.duration"}}
</label>
<RelativeTimePicker
@onChange={{action "durationChanged"}}
@durationMinutes={{readonly this.topicTimer.duration_minutes}}
@onChange={{this.changeDuration}}
@durationMinutes={{readonly @topicTimer.duration_minutes}}
/>
</div>
{{/if}}
{{#if this.willCloseImmediately}}
<div class="warning">
{{d-icon "exclamation-triangle"}}
{{this.willCloseI18n}}
</div>
{{/if}}
{{#if this.showTopicTimerInfo}}
<div class="alert alert-info modal-topic-timer-info">
<TopicTimerInfo
@statusType={{this.statusType}}
@executeAt={{this.executeAt}}
@basedOnLastPost={{this.topicTimer.based_on_last_post}}
@durationMinutes={{this.topicTimer.duration_minutes}}
@categoryId={{this.topicTimer.category_id}}
@basedOnLastPost={{@topicTimer.based_on_last_post}}
@durationMinutes={{@topicTimer.duration_minutes}}
@categoryId={{@topicTimer.category_id}}
/>
</div>
{{/if}}

View File

@ -1,6 +1,7 @@
import Component from "@ember/component";
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object";
import { equal, or, readOnly } from "@ember/object/computed";
import { inject as service } from "@ember/service";
import { isEmpty } from "@ember/utils";
import ItsATrap from "@discourse/itsatrap";
import {
@ -17,73 +18,71 @@ import {
TIME_SHORTCUT_TYPES,
timeShortcuts,
} from "discourse/lib/time-shortcut";
import discourseComputed from "discourse-common/utils/decorators";
import I18n from "discourse-i18n";
import { FORMAT } from "select-kit/components/future-date-input-selector";
export default Component.extend({
statusType: readOnly("topicTimer.status_type"),
autoOpen: equal("statusType", OPEN_STATUS_TYPE),
autoClose: equal("statusType", CLOSE_STATUS_TYPE),
autoCloseAfterLastPost: equal(
"statusType",
CLOSE_AFTER_LAST_POST_STATUS_TYPE
),
autoDelete: equal("statusType", DELETE_STATUS_TYPE),
autoBump: equal("statusType", BUMP_TYPE),
publishToCategory: equal("statusType", PUBLISH_TO_CATEGORY_STATUS_TYPE),
autoDeleteReplies: equal("statusType", DELETE_REPLIES_TYPE),
showTimeOnly: or("autoOpen", "autoDelete", "autoBump"),
showFutureDateInput: or("showTimeOnly", "publishToCategory", "autoClose"),
useDuration: or(
"isBasedOnLastPost",
"autoDeleteReplies",
"autoCloseAfterLastPost"
),
duration: null,
_itsatrap: null,
export default class EditTopicTimerForm extends Component {
@service currentUser;
init() {
this._super(...arguments);
@tracked timerType;
constructor() {
super(...arguments);
KeyboardShortcuts.pause();
this.set("_itsatrap", new ItsATrap());
this.set("duration", this.initialDuration);
},
get initialDuration() {
if (!this.useDuration || !this.topicTimer.duration_minutes) {
return null;
} else if (this.durationType === "days") {
return this.topicTimer.duration_minutes / 60 / 24;
} else {
return this.topicTimer.duration_minutes / 60;
this._itsatrap = new ItsATrap();
}
},
willDestroyElement() {
this._super(...arguments);
willDestroy() {
super.willDestroy(...arguments);
this._itsatrap.destroy();
this.set("_itsatrap", null);
KeyboardShortcuts.unpause();
},
@discourseComputed("autoDeleteReplies")
durationType(autoDeleteReplies) {
return autoDeleteReplies ? "days" : "hours";
},
@discourseComputed("topic.visible")
excludeCategoryId(visible) {
if (visible) {
return this.get("topic.category_id");
}
},
@discourseComputed()
timeOptions() {
get showTimeOnly() {
return (
this.statusType === OPEN_STATUS_TYPE ||
this.statusType === DELETE_STATUS_TYPE ||
this.statusType === BUMP_TYPE
);
}
get showFutureDateInput() {
return (
this.showTimeOnly ||
this.publishToCategory ||
this.statusType === CLOSE_STATUS_TYPE
);
}
get useDuration() {
return this.autoCloseAfterLastPost || this.autoDeleteReplies;
}
get autoCloseAfterLastPost() {
return this.statusType === CLOSE_AFTER_LAST_POST_STATUS_TYPE;
}
get publishToCategory() {
return this.statusType === PUBLISH_TO_CATEGORY_STATUS_TYPE;
}
get autoDeleteReplies() {
return this.statusType === DELETE_REPLIES_TYPE;
}
get statusType() {
return this.args.topicTimer.status_type;
}
get excludeCategoryId() {
if (this.args.topic.visible) {
return this.args.topic.category_id;
}
}
get timeOptions() {
const timezone = this.currentUser.user_option.timezone;
const shortcuts = timeShortcuts(timezone);
@ -97,106 +96,85 @@ export default Component.extend({
shortcuts.nextMonth(),
shortcuts.sixMonths(),
];
},
}
@discourseComputed
hiddenTimeShortcutOptions() {
get hiddenTimeShortcutOptions() {
return [
TIME_SHORTCUT_TYPES.NONE,
TIME_SHORTCUT_TYPES.LATER_TODAY,
TIME_SHORTCUT_TYPES.LATER_THIS_WEEK,
];
},
isCustom: equal("timerType", "custom"),
isBasedOnLastPost: equal("statusType", "close_after_last_post"),
@discourseComputed(
"topicTimer.updateTime",
"topicTimer.duration_minutes",
"useDuration"
)
executeAt(updateTime, duration, useDuration) {
if (useDuration) {
return moment().add(parseFloat(duration), "minutes").format(FORMAT);
} else {
return updateTime;
}
},
@discourseComputed(
"isBasedOnLastPost",
"topicTimer.duration_minutes",
"topic.last_posted_at"
)
willCloseImmediately(isBasedOnLastPost, duration, lastPostedAt) {
if (isBasedOnLastPost && duration) {
let closeDate = moment(lastPostedAt);
closeDate = closeDate.add(duration, "minutes");
get executeAt() {
if (this.useDuration) {
return moment()
.add(parseFloat(this.args.topicTimer.duration_minutes), "minutes")
.format(FORMAT);
} else {
return this.args.topicTimer.updateTime;
}
}
get willCloseImmediately() {
if (this.autoCloseAfterLastPost && this.args.topicTimer.duration_minutes) {
const closeDate = moment(this.args.topic.last_posted_at).add(
this.args.topicTimer.duration_minutes,
"minutes"
);
return closeDate < moment();
}
},
}
@discourseComputed("isBasedOnLastPost", "topic.last_posted_at")
willCloseI18n(isBasedOnLastPost, lastPostedAt) {
if (isBasedOnLastPost) {
get willCloseI18n() {
if (this.autoCloseAfterLastPost) {
const diff = Math.round(
(new Date() - new Date(lastPostedAt)) / (1000 * 60 * 60)
(new Date() - new Date(this.args.topic.last_posted_at)) /
(1000 * 60 * 60)
);
return I18n.t("topic.auto_close_momentarily", { count: diff });
}
},
}
@discourseComputed("durationType")
durationLabel(durationType) {
return I18n.t(`topic.topic_status_update.num_of_${durationType}`);
},
get durationLabel() {
return I18n.t(
`topic.topic_status_update.num_of_${
this.autoDeleteReplies ? "days" : "hours"
}`
);
}
@discourseComputed(
"statusType",
"isCustom",
"topicTimer.updateTime",
"willCloseImmediately",
"topicTimer.category_id",
"useDuration",
"topicTimer.duration_minutes"
)
showTopicTimerInfo(
statusType,
isCustom,
updateTime,
willCloseImmediately,
categoryId,
useDuration,
duration
get showTopicTimerInfo() {
if (!this.statusType || this.willCloseImmediately) {
return false;
}
if (
this.statusType === PUBLISH_TO_CATEGORY_STATUS_TYPE &&
isEmpty(this.args.topicTimer.category_id)
) {
if (!statusType || willCloseImmediately) {
return false;
}
if (statusType === PUBLISH_TO_CATEGORY_STATUS_TYPE && isEmpty(categoryId)) {
if (this.timerType === "custom" && this.args.topicTimer.updateTime) {
if (moment(this.args.topicTimer.updateTime) < moment()) {
return false;
}
if (isCustom && updateTime) {
if (moment(updateTime) < moment()) {
return false;
}
} else if (useDuration) {
return duration;
} else if (this.useDuration) {
return this.args.topicTimer.duration_minutes;
}
return updateTime;
},
return this.args.topicTimer.updateTime;
}
@action
onTimeSelected(type, time) {
this.set("timerType", type);
this.onChangeInput(type, time);
},
this.timerType = type;
this.args.onChangeInput(type, time);
}
@action
durationChanged(newDurationMins) {
this.set("topicTimer.duration_minutes", newDurationMins);
},
});
changeDuration(newDurationMins) {
this.args.topicTimer.set("duration_minutes", newDurationMins);
}
}

View File

@ -3,7 +3,6 @@ import { test } from "qunit";
import topicFixtures from "discourse/tests/fixtures/topic";
import {
acceptance,
exists,
fakeTime,
loggedInUser,
query,
@ -54,11 +53,9 @@ acceptance("Topic - Edit timer", function (needs) {
await click("#tap_tile_start_of_next_business_week");
const regex = /will automatically close in/g;
const html = query(
".edit-topic-timer-modal .topic-timer-info"
).innerHTML.trim();
assert.ok(regex.test(html));
assert
.dom(".edit-topic-timer-modal .topic-timer-info")
.matchesText(/will automatically close in/g);
});
test("autoclose", async function (assert) {
@ -70,20 +67,16 @@ acceptance("Topic - Edit timer", function (needs) {
await click("#tap_tile_start_of_next_business_week");
const regex1 = /will automatically close in/g;
const html1 = query(
".edit-topic-timer-modal .topic-timer-info"
).innerHTML.trim();
assert.ok(regex1.test(html1));
assert
.dom(".edit-topic-timer-modal .topic-timer-info")
.matchesText(/will automatically close in/g);
await click("#tap_tile_custom");
await fillIn(".tap-tile-date-input .date-picker", "2100-11-24");
const regex2 = /will automatically close in/g;
const html2 = query(
".edit-topic-timer-modal .topic-timer-info"
).innerHTML.trim();
assert.ok(regex2.test(html2));
assert
.dom(".edit-topic-timer-modal .topic-timer-info")
.matchesText(/will automatically close in/g);
const timerType = selectKit(".select-kit.timer-type");
await timerType.expand();
@ -94,9 +87,9 @@ acceptance("Topic - Edit timer", function (needs) {
await interval.selectRowByValue("hours");
await fillIn(".relative-time-duration", "2");
const regex3 = /last post in the topic is already/g;
const html3 = query(".edit-topic-timer-modal .warning").innerHTML.trim();
assert.ok(regex3.test(html3));
assert
.dom(".edit-topic-timer-modal .warning")
.matchesText(/last post in the topic is already/g);
});
test("close temporarily", async function (assert) {
@ -112,20 +105,16 @@ acceptance("Topic - Edit timer", function (needs) {
await click("#tap_tile_start_of_next_business_week");
const regex1 = /will automatically open in/g;
const html1 = query(
".edit-topic-timer-modal .topic-timer-info"
).innerHTML.trim();
assert.ok(regex1.test(html1));
assert
.dom(".edit-topic-timer-modal .topic-timer-info")
.matchesText(/will automatically open in/g);
await click("#tap_tile_custom");
await fillIn(".tap-tile-date-input .date-picker", "2100-11-24");
const regex2 = /will automatically open in/g;
const html2 = query(
".edit-topic-timer-modal .topic-timer-info"
).innerHTML.trim();
assert.ok(regex2.test(html2));
assert
.dom(".edit-topic-timer-modal .topic-timer-info")
.matchesText(/will automatically open in/g);
});
test("schedule publish to category - visible for a PM", async function (assert) {
@ -257,8 +246,9 @@ acceptance("Topic - Edit timer", function (needs) {
await click(".toggle-admin-menu");
await click(".admin-topic-timer-update button");
assert.notOk(
exists("#tap_tile_last_custom"),
assert
.dom("#tap_tile_last_custom")
.doesNotExist(
"it does not show last custom if the custom date and time was not filled before"
);
@ -273,13 +263,11 @@ acceptance("Topic - Edit timer", function (needs) {
await click(".toggle-admin-menu");
await click(".admin-topic-timer-update button");
assert.ok(
exists("#tap_tile_last_custom"),
"it show last custom because the custom date and time was valid"
);
const text = query("#tap_tile_last_custom").innerText.trim();
const regex = /Nov 24, 10:30 am/g;
assert.ok(regex.test(text));
assert
.dom("#tap_tile_last_custom")
.exists("it show last custom because the custom date and time was valid");
assert.dom("#tap_tile_last_custom").matchesText(/Nov 24, 10:30 am/g);
});
test("schedule publish to category - does not show for a public topic", async function (assert) {
@ -291,7 +279,7 @@ acceptance("Topic - Edit timer", function (needs) {
await click(".admin-topic-timer-update button");
await timerType.expand();
assert.notOk(
assert.false(
timerType.rowByValue("publish_to_category").exists(),
"publish to category is not shown for a public topic"
);
@ -308,7 +296,7 @@ acceptance("Topic - Edit timer", function (needs) {
await timerType.expand();
assert.ok(!timerType.rowByValue("delete").exists());
assert.false(timerType.rowByValue("delete").exists());
});
test("Category Moderator can auto-delete replies", async function (assert) {
@ -322,7 +310,7 @@ acceptance("Topic - Edit timer", function (needs) {
await timerType.expand();
assert.ok(timerType.rowByValue("delete_replies").exists());
assert.true(timerType.rowByValue("delete_replies").exists());
});
test("TL4 can't auto-delete replies", async function (assert) {
@ -336,7 +324,7 @@ acceptance("Topic - Edit timer", function (needs) {
await timerType.expand();
assert.ok(!timerType.rowByValue("delete_replies").exists());
assert.false(timerType.rowByValue("delete_replies").exists());
});
test("Category Moderator can auto-delete", async function (assert) {
@ -350,7 +338,7 @@ acceptance("Topic - Edit timer", function (needs) {
await timerType.expand();
assert.ok(timerType.rowByValue("delete").exists());
assert.true(timerType.rowByValue("delete").exists());
});
test("auto delete", async function (assert) {
@ -366,11 +354,9 @@ acceptance("Topic - Edit timer", function (needs) {
await click("#tap_tile_two_weeks");
const regex = /will be automatically deleted/g;
const html = query(
".edit-topic-timer-modal .topic-timer-info"
).innerHTML.trim();
assert.ok(regex.test(html));
assert
.dom(".edit-topic-timer-modal .topic-timer-info")
.matchesText(/will be automatically deleted/g);
});
test("Inline delete timer", async function (assert) {
@ -382,11 +368,12 @@ acceptance("Topic - Edit timer", function (needs) {
await click("#tap_tile_start_of_next_business_week");
await click(".edit-topic-timer-modal button.btn-primary");
const removeTimerButton = query(".topic-timer-info .topic-timer-remove");
assert.strictEqual(removeTimerButton.getAttribute("title"), "remove timer");
assert
.dom(".topic-timer-info .topic-timer-remove")
.hasAttribute("title", "remove timer");
await click(".topic-timer-info .topic-timer-remove");
assert.ok(!exists(".topic-timer-info .topic-timer-remove"));
assert.dom(".topic-timer-info .topic-timer-remove").doesNotExist();
});
test("Shows correct time frame options", async function (assert) {
@ -424,7 +411,7 @@ acceptance("Topic - Edit timer", function (needs) {
await timerType.expand();
await timerType.selectRowByValue("close_after_last_post");
assert.notOk(exists(".topic-timer-heading"));
assert.dom(".topic-timer-heading").doesNotExist();
});
test("Close timer removed after manual close", async function (assert) {
@ -439,7 +426,7 @@ acceptance("Topic - Edit timer", function (needs) {
await click(".toggle-admin-menu");
await click(".topic-admin-close button");
assert.notOk(exists(".topic-timer-heading"));
assert.dom(".topic-timer-heading").doesNotExist();
});
test("Open timer removed after manual open", async function (assert) {
@ -457,7 +444,7 @@ acceptance("Topic - Edit timer", function (needs) {
await click(".toggle-admin-menu");
await click(".topic-admin-open button");
assert.notOk(exists(".topic-timer-heading"));
assert.dom(".topic-timer-heading").doesNotExist();
});
test("timer removed after manual toggle close and open", async function (assert) {
@ -475,6 +462,6 @@ acceptance("Topic - Edit timer", function (needs) {
await click(".toggle-admin-menu");
await click(".topic-admin-open button");
assert.notOk(exists(".topic-timer-heading"));
assert.dom(".topic-timer-heading").doesNotExist();
});
});