mirror of
https://github.com/discourse/discourse.git
synced 2025-01-18 13:52:50 +08:00
DEV: make API of future-date-input more customizable and aligned with the API of time-shortcut-picker (#16502)
This commit is contained in:
parent
3e23bd4745
commit
c9b2374299
|
@ -12,7 +12,6 @@
|
|||
{{future-date-input
|
||||
class="silence-until"
|
||||
label="admin.user.silence_duration"
|
||||
includeFarFuture=true
|
||||
clearable=false
|
||||
input=silenceUntil
|
||||
onChangeInput=(action (mut silenceUntil))
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
{{future-date-input
|
||||
class="suspend-until"
|
||||
label="admin.user.suspend_duration"
|
||||
includeFarFuture=true
|
||||
clearable=false
|
||||
input=suspendUntil
|
||||
onChangeInput=(action (mut suspendUntil))
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
import Component from "@ember/component";
|
||||
import { action } from "@ember/object";
|
||||
import { and, empty, equal } from "@ember/object/computed";
|
||||
import buildTimeframes from "discourse/lib/timeframes-builder";
|
||||
import I18n from "I18n";
|
||||
import { FORMAT } from "select-kit/components/future-date-input-selector";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import {
|
||||
TIME_SHORTCUT_TYPES,
|
||||
extendedDefaultTimeShortcuts,
|
||||
formatTime,
|
||||
hideDynamicTimeShortcuts,
|
||||
timeShortcuts,
|
||||
} from "discourse/lib/time-shortcut";
|
||||
|
||||
export default Component.extend({
|
||||
selection: null,
|
||||
|
@ -24,12 +31,12 @@ export default Component.extend({
|
|||
|
||||
if (this.input) {
|
||||
const dateTime = moment(this.input);
|
||||
const closestTimeframe = this.findClosestTimeframe(dateTime);
|
||||
if (closestTimeframe) {
|
||||
this.set("selection", closestTimeframe.id);
|
||||
const closestShortcut = this._findClosestShortcut(dateTime);
|
||||
if (closestShortcut) {
|
||||
this.set("selection", closestShortcut.id);
|
||||
} else {
|
||||
this.setProperties({
|
||||
selection: "custom",
|
||||
selection: TIME_SHORTCUT_TYPES.CUSTOM,
|
||||
_date: dateTime.format("YYYY-MM-DD"),
|
||||
_time: dateTime.format("HH:mm"),
|
||||
});
|
||||
|
@ -45,6 +52,36 @@ export default Component.extend({
|
|||
}
|
||||
},
|
||||
|
||||
@discourseComputed("customShortcuts")
|
||||
shortcuts(customShortcuts) {
|
||||
let shortcuts;
|
||||
if (customShortcuts && customShortcuts.length) {
|
||||
shortcuts = customShortcuts;
|
||||
} else {
|
||||
shortcuts = extendedDefaultTimeShortcuts(this.userTimezone);
|
||||
}
|
||||
|
||||
const shortcutsFactory = timeShortcuts(this.userTimezone);
|
||||
if (this.includeDateTime) {
|
||||
shortcuts.push(shortcutsFactory.custom());
|
||||
}
|
||||
if (this.includeNow) {
|
||||
shortcuts.push(shortcutsFactory.now());
|
||||
}
|
||||
|
||||
shortcuts = hideDynamicTimeShortcuts(shortcuts, this.userTimezone);
|
||||
|
||||
return shortcuts.map((s) => {
|
||||
return {
|
||||
id: s.id,
|
||||
name: I18n.t(s.label),
|
||||
time: s.time,
|
||||
timeFormatted: formatTime(s),
|
||||
icon: s.icon,
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
@action
|
||||
onChangeDate(date) {
|
||||
if (!date) {
|
||||
|
@ -73,15 +110,8 @@ export default Component.extend({
|
|||
}
|
||||
},
|
||||
|
||||
findClosestTimeframe(dateTime) {
|
||||
const options = {
|
||||
includeWeekend: this.includeWeekend,
|
||||
includeFarFuture: this.includeFarFuture,
|
||||
includeDateTime: this.includeDateTime,
|
||||
canScheduleNow: this.includeNow || false,
|
||||
};
|
||||
|
||||
return buildTimeframes(this.userTimezone, options).find((tf) => {
|
||||
_findClosestShortcut(dateTime) {
|
||||
return this.shortcuts.find((tf) => {
|
||||
if (tf.time) {
|
||||
const diff = tf.time.diff(dateTime);
|
||||
return 0 <= diff && diff < 60 * 1000;
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
import {
|
||||
LATER_TODAY_CUTOFF_HOUR,
|
||||
MOMENT_FRIDAY,
|
||||
MOMENT_THURSDAY,
|
||||
START_OF_DAY_HOUR,
|
||||
laterToday,
|
||||
now,
|
||||
|
@ -10,6 +7,8 @@ import {
|
|||
import {
|
||||
TIME_SHORTCUT_TYPES,
|
||||
defaultTimeShortcuts,
|
||||
formatTime,
|
||||
hideDynamicTimeShortcuts,
|
||||
specialShortcutOptions,
|
||||
} from "discourse/lib/time-shortcut";
|
||||
import discourseComputed, {
|
||||
|
@ -183,7 +182,7 @@ export default Component.extend({
|
|||
} else {
|
||||
options = defaultTimeShortcuts(userTimezone);
|
||||
}
|
||||
this._hideDynamicOptions(options);
|
||||
options = hideDynamicTimeShortcuts(options, userTimezone);
|
||||
|
||||
let specialOptions = specialShortcutOptions();
|
||||
if (this.lastCustomDate && this.lastCustomTime) {
|
||||
|
@ -206,7 +205,7 @@ export default Component.extend({
|
|||
}
|
||||
|
||||
this._applyCustomLabels(options, customLabels);
|
||||
this._formatTime(options);
|
||||
options.forEach((o) => (o.timeFormatted = formatTime(o)));
|
||||
return options;
|
||||
},
|
||||
|
||||
|
@ -271,23 +270,4 @@ export default Component.extend({
|
|||
}
|
||||
});
|
||||
},
|
||||
|
||||
_hideDynamicOptions(options) {
|
||||
if (now(this.userTimezone).hour() >= LATER_TODAY_CUTOFF_HOUR) {
|
||||
this._hideOption(options, TIME_SHORTCUT_TYPES.LATER_TODAY);
|
||||
}
|
||||
|
||||
if (now(this.userTimezone).day() >= MOMENT_THURSDAY) {
|
||||
this._hideOption(options, TIME_SHORTCUT_TYPES.LATER_THIS_WEEK);
|
||||
}
|
||||
|
||||
if (now(this.userTimezone).day() >= MOMENT_FRIDAY) {
|
||||
this._hideOption(options, TIME_SHORTCUT_TYPES.THIS_WEEKEND);
|
||||
}
|
||||
},
|
||||
|
||||
_hideOption(options, optionId) {
|
||||
const option = options.findBy("id", optionId);
|
||||
option.hidden = true;
|
||||
},
|
||||
});
|
||||
|
|
|
@ -12,6 +12,7 @@ import Invite from "discourse/models/invite";
|
|||
import I18n from "I18n";
|
||||
import { FORMAT } from "select-kit/components/future-date-input-selector";
|
||||
import { sanitize } from "discourse/lib/text";
|
||||
import { timeShortcuts } from "discourse/lib/time-shortcut";
|
||||
|
||||
export default Controller.extend(
|
||||
ModalFunctionality,
|
||||
|
@ -177,6 +178,24 @@ export default Controller.extend(
|
|||
return staff || groups.any((g) => g.owner);
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
timeShortcuts() {
|
||||
const timezone = this.currentUser.resolvedTimezone(this.currentUser);
|
||||
const shortcuts = timeShortcuts(timezone);
|
||||
return [
|
||||
shortcuts.laterToday(),
|
||||
shortcuts.tomorrow(),
|
||||
shortcuts.laterThisWeek(),
|
||||
shortcuts.monday(),
|
||||
shortcuts.twoWeeks(),
|
||||
shortcuts.nextMonth(),
|
||||
shortcuts.twoMonths(),
|
||||
shortcuts.threeMonths(),
|
||||
shortcuts.fourMonths(),
|
||||
shortcuts.sixMonths(),
|
||||
];
|
||||
},
|
||||
|
||||
@action
|
||||
copied() {
|
||||
this.save({ sendEmail: false, copy: true });
|
||||
|
|
|
@ -7,6 +7,7 @@ import { action } from "@ember/object";
|
|||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { equal, or } from "@ember/object/computed";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { timeShortcuts } from "discourse/lib/time-shortcut";
|
||||
|
||||
export default Controller.extend(ModalFunctionality, {
|
||||
selectedSlowMode: null,
|
||||
|
@ -107,6 +108,24 @@ export default Controller.extend(ModalFunctionality, {
|
|||
: "topic.slow_mode_update.enable";
|
||||
},
|
||||
|
||||
@discourseComputed
|
||||
timeShortcuts() {
|
||||
const timezone = this.currentUser.resolvedTimezone(this.currentUser);
|
||||
const shortcuts = timeShortcuts(timezone);
|
||||
return [
|
||||
shortcuts.laterToday(),
|
||||
shortcuts.tomorrow(),
|
||||
shortcuts.laterThisWeek(),
|
||||
shortcuts.monday(),
|
||||
shortcuts.twoWeeks(),
|
||||
shortcuts.nextMonth(),
|
||||
shortcuts.twoMonths(),
|
||||
shortcuts.threeMonths(),
|
||||
shortcuts.fourMonths(),
|
||||
shortcuts.sixMonths(),
|
||||
];
|
||||
},
|
||||
|
||||
_setFromSeconds(seconds) {
|
||||
this.setProperties(fromSeconds(seconds));
|
||||
},
|
||||
|
|
|
@ -3,11 +3,35 @@ import I18n from "I18n";
|
|||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
import User from "discourse/models/user";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { timeShortcuts } from "discourse/lib/time-shortcut";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Controller.extend(ModalFunctionality, {
|
||||
loading: false,
|
||||
ignoredUntil: null,
|
||||
ignoredUsername: null,
|
||||
|
||||
@discourseComputed
|
||||
timeShortcuts() {
|
||||
const timezone = this.currentUser.resolvedTimezone(this.currentUser);
|
||||
const shortcuts = timeShortcuts(timezone);
|
||||
return [
|
||||
shortcuts.laterToday(),
|
||||
shortcuts.tomorrow(),
|
||||
shortcuts.laterThisWeek(),
|
||||
shortcuts.thisWeekend(),
|
||||
shortcuts.monday(),
|
||||
shortcuts.twoWeeks(),
|
||||
shortcuts.nextMonth(),
|
||||
shortcuts.twoMonths(),
|
||||
shortcuts.threeMonths(),
|
||||
shortcuts.fourMonths(),
|
||||
shortcuts.sixMonths(),
|
||||
shortcuts.oneYear(),
|
||||
shortcuts.forever(),
|
||||
];
|
||||
},
|
||||
|
||||
actions: {
|
||||
ignore() {
|
||||
if (!this.ignoredUntil || !this.ignoredUsername) {
|
||||
|
|
|
@ -2,10 +2,34 @@ import Controller from "@ember/controller";
|
|||
import I18n from "I18n";
|
||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { timeShortcuts } from "discourse/lib/time-shortcut";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
export default Controller.extend(ModalFunctionality, {
|
||||
loading: false,
|
||||
ignoredUntil: null,
|
||||
|
||||
@discourseComputed
|
||||
timeShortcuts() {
|
||||
const timezone = this.currentUser.resolvedTimezone(this.currentUser);
|
||||
const shortcuts = timeShortcuts(timezone);
|
||||
return [
|
||||
shortcuts.laterToday(),
|
||||
shortcuts.tomorrow(),
|
||||
shortcuts.laterThisWeek(),
|
||||
shortcuts.thisWeekend(),
|
||||
shortcuts.monday(),
|
||||
shortcuts.twoWeeks(),
|
||||
shortcuts.nextMonth(),
|
||||
shortcuts.twoMonths(),
|
||||
shortcuts.threeMonths(),
|
||||
shortcuts.fourMonths(),
|
||||
shortcuts.sixMonths(),
|
||||
shortcuts.oneYear(),
|
||||
shortcuts.forever(),
|
||||
];
|
||||
},
|
||||
|
||||
actions: {
|
||||
ignore() {
|
||||
if (!this.ignoredUntil) {
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import {
|
||||
LATER_TODAY_CUTOFF_HOUR,
|
||||
MOMENT_FRIDAY,
|
||||
MOMENT_MONDAY,
|
||||
MOMENT_SATURDAY,
|
||||
MOMENT_SUNDAY,
|
||||
MOMENT_THURSDAY,
|
||||
fourMonths,
|
||||
laterThisWeek,
|
||||
laterToday,
|
||||
|
@ -16,6 +20,7 @@ import {
|
|||
twoMonths,
|
||||
twoWeeks,
|
||||
} from "discourse/lib/time-utils";
|
||||
import I18n from "I18n";
|
||||
|
||||
export const TIME_SHORTCUT_TYPES = {
|
||||
LATER_TODAY: "later_today",
|
||||
|
@ -46,6 +51,24 @@ export function defaultTimeShortcuts(timezone) {
|
|||
];
|
||||
}
|
||||
|
||||
export function extendedDefaultTimeShortcuts(timezone) {
|
||||
const shortcuts = timeShortcuts(timezone);
|
||||
return [
|
||||
shortcuts.laterToday(),
|
||||
shortcuts.tomorrow(),
|
||||
shortcuts.laterThisWeek(),
|
||||
shortcuts.monday(),
|
||||
shortcuts.twoWeeks(),
|
||||
shortcuts.nextMonth(),
|
||||
shortcuts.twoMonths(),
|
||||
shortcuts.threeMonths(),
|
||||
shortcuts.fourMonths(),
|
||||
shortcuts.sixMonths(),
|
||||
shortcuts.oneYear(),
|
||||
shortcuts.forever(),
|
||||
];
|
||||
}
|
||||
|
||||
export function specialShortcutOptions() {
|
||||
const shortcuts = timeShortcuts();
|
||||
return [shortcuts.lastCustom(), shortcuts.custom(), shortcuts.none()];
|
||||
|
@ -210,3 +233,33 @@ export function timeShortcuts(timezone) {
|
|||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function hideDynamicTimeShortcuts(shortcuts, timezone) {
|
||||
const shortcutsToHide = new Set();
|
||||
const _now = now(timezone);
|
||||
if (_now.hour() >= LATER_TODAY_CUTOFF_HOUR) {
|
||||
shortcutsToHide.add(TIME_SHORTCUT_TYPES.LATER_TODAY);
|
||||
}
|
||||
|
||||
if (_now.day === MOMENT_SUNDAY || _now.day() >= MOMENT_THURSDAY) {
|
||||
shortcutsToHide.add(TIME_SHORTCUT_TYPES.LATER_THIS_WEEK);
|
||||
}
|
||||
|
||||
if (
|
||||
_now.day() === MOMENT_FRIDAY ||
|
||||
_now.day() === MOMENT_SATURDAY ||
|
||||
_now.day() === MOMENT_SUNDAY
|
||||
) {
|
||||
shortcutsToHide.add(TIME_SHORTCUT_TYPES.THIS_WEEKEND);
|
||||
}
|
||||
|
||||
return shortcuts.filter((s) => !shortcutsToHide.has(s.id));
|
||||
}
|
||||
|
||||
export function formatTime(shortcut) {
|
||||
if (!shortcut.time || !shortcut.timeFormatKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return shortcut.time.format(I18n.t(shortcut.timeFormatKey));
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ export const LATER_TODAY_CUTOFF_HOUR = 17;
|
|||
export const LATER_TODAY_MAX_HOUR = 18;
|
||||
export const MOMENT_SUNDAY = 0;
|
||||
export const MOMENT_MONDAY = 1;
|
||||
export const MOMENT_TUESDAY = 2;
|
||||
export const MOMENT_WEDNESDAY = 3;
|
||||
export const MOMENT_THURSDAY = 4;
|
||||
export const MOMENT_FRIDAY = 5;
|
||||
export const MOMENT_SATURDAY = 6;
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
import {
|
||||
TIME_SHORTCUT_TYPES,
|
||||
timeShortcuts,
|
||||
} from "discourse/lib/time-shortcut";
|
||||
import I18n from "I18n";
|
||||
|
||||
export default function buildTimeframes(timezone, options = {}) {
|
||||
const timeframes = allTimeframes(timezone);
|
||||
formatTime(timeframes);
|
||||
processDynamicTimeframes(timeframes, options, timezone);
|
||||
return timeframes.filter((t) => !t.hidden);
|
||||
}
|
||||
|
||||
function allTimeframes(timezone) {
|
||||
const shortcuts = timeShortcuts(timezone);
|
||||
|
||||
return [
|
||||
shortcuts.now(),
|
||||
shortcuts.laterToday(),
|
||||
shortcuts.tomorrow(),
|
||||
shortcuts.laterThisWeek(),
|
||||
shortcuts.thisWeekend(),
|
||||
shortcuts.monday(),
|
||||
shortcuts.twoWeeks(),
|
||||
shortcuts.nextMonth(),
|
||||
shortcuts.twoMonths(),
|
||||
shortcuts.threeMonths(),
|
||||
shortcuts.fourMonths(),
|
||||
shortcuts.sixMonths(),
|
||||
shortcuts.oneYear(),
|
||||
shortcuts.forever(),
|
||||
shortcuts.custom(),
|
||||
];
|
||||
}
|
||||
|
||||
function processDynamicTimeframes(timeframes, options, timezone) {
|
||||
const now = moment.tz(timezone);
|
||||
|
||||
if (
|
||||
!options.includeWeekend ||
|
||||
now.day() === 0 ||
|
||||
now.day() === 5 ||
|
||||
now.day() === 6
|
||||
) {
|
||||
hideTimeframe(timeframes, TIME_SHORTCUT_TYPES.THIS_WEEKEND);
|
||||
}
|
||||
|
||||
if (now.day() === 0) {
|
||||
hideTimeframe(timeframes, TIME_SHORTCUT_TYPES.START_OF_NEXT_BUSINESS_WEEK);
|
||||
}
|
||||
|
||||
if (now.date() === moment.tz(timezone).endOf("month").date()) {
|
||||
hideTimeframe(timeframes, TIME_SHORTCUT_TYPES.NEXT_MONTH);
|
||||
}
|
||||
|
||||
if (24 - now.hour() <= 6) {
|
||||
hideTimeframe(timeframes, TIME_SHORTCUT_TYPES.LATER_TODAY);
|
||||
}
|
||||
|
||||
if (now.day() === 0 || now.day() >= 4) {
|
||||
hideTimeframe(timeframes, TIME_SHORTCUT_TYPES.LATER_THIS_WEEK);
|
||||
}
|
||||
|
||||
if (!options.includeFarFuture) {
|
||||
hideTimeframe(timeframes, TIME_SHORTCUT_TYPES.ONE_YEAR);
|
||||
hideTimeframe(timeframes, TIME_SHORTCUT_TYPES.FOREVER);
|
||||
}
|
||||
|
||||
if (!options.includeDateTime) {
|
||||
hideTimeframe(timeframes, TIME_SHORTCUT_TYPES.CUSTOM);
|
||||
}
|
||||
|
||||
if (!options.canScheduleNow) {
|
||||
hideTimeframe(timeframes, TIME_SHORTCUT_TYPES.NOW);
|
||||
}
|
||||
}
|
||||
|
||||
function hideTimeframe(timeframes, timeframeId) {
|
||||
const timeframe = timeframes.findBy("id", timeframeId);
|
||||
timeframe.hidden = true;
|
||||
}
|
||||
|
||||
function formatTime(options) {
|
||||
options.forEach((option) => {
|
||||
if (option.time && option.timeFormatKey) {
|
||||
option.timeFormatted = option.time.format(I18n.t(option.timeFormatKey));
|
||||
}
|
||||
});
|
||||
}
|
|
@ -4,12 +4,8 @@
|
|||
{{#if displayLabelIcon}}{{d-icon displayLabelIcon}}{{/if}}{{displayLabel}}
|
||||
</label>
|
||||
{{future-date-input-selector
|
||||
statusType=statusType
|
||||
value=(readonly selection)
|
||||
includeDateTime=includeDateTime
|
||||
includeWeekend=includeWeekend
|
||||
includeFarFuture=includeFarFuture
|
||||
includeNow=includeNow
|
||||
content=shortcuts
|
||||
clearable=clearable
|
||||
onChangeInput=onChangeInput
|
||||
onChange=(action (mut selection))
|
||||
|
|
|
@ -124,8 +124,7 @@
|
|||
{{future-date-input
|
||||
displayLabelIcon="far-clock"
|
||||
displayLabel=(i18n "user.invited.invite.expires_at")
|
||||
statusType="close"
|
||||
includeDateTime=true
|
||||
customShortcuts=timeShortcuts
|
||||
clearable=true
|
||||
input=buffered.expires_at
|
||||
onChangeInput=(action (mut buffered.expires_at))
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
class="enabled-until"
|
||||
label="topic.slow_mode_update.enabled_until"
|
||||
labelClasses="slow-mode-label"
|
||||
includeFarFuture=false
|
||||
customShortcuts=timeShortcuts
|
||||
clearable=true
|
||||
input=model.slow_mode_enabled_until
|
||||
onChangeInput=(action (mut model.slow_mode_enabled_until))
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
<p class="with-validation">
|
||||
{{future-date-input
|
||||
class="pin-until"
|
||||
includeFarFuture=true
|
||||
clearable=true
|
||||
input=model.pinnedInCategoryUntil
|
||||
onChangeInput=(action (mut model.pinnedInCategoryUntil))
|
||||
|
@ -57,7 +56,6 @@
|
|||
{{d-icon "far-clock"}}
|
||||
{{future-date-input
|
||||
class="pin-until"
|
||||
includeFarFuture=true
|
||||
clearable=true
|
||||
input=model.pinnedInCategoryUntil
|
||||
onChangeInput=(action (mut model.pinnedInCategoryUntil))
|
||||
|
@ -93,7 +91,6 @@
|
|||
<p class="with-validation">
|
||||
{{future-date-input
|
||||
class="pin-until"
|
||||
includeFarFuture=true
|
||||
clearable=true
|
||||
input=model.pinnedGloballyUntil
|
||||
onChangeInput=(action (mut model.pinnedGloballyUntil))
|
||||
|
@ -107,7 +104,6 @@
|
|||
{{d-icon "far-clock"}}
|
||||
{{future-date-input
|
||||
class="pin-until"
|
||||
includeFarFuture=true
|
||||
clearable=true
|
||||
input=model.pinnedGloballyUntil
|
||||
onChangeInput=(action (mut model.pinnedGloballyUntil))
|
||||
|
|
|
@ -13,9 +13,8 @@
|
|||
{{future-date-input
|
||||
label="user.user_notifications.ignore_duration_when"
|
||||
input=(readonly ignoredUntil)
|
||||
includeWeekend=true
|
||||
customShortcuts=timeShortcuts
|
||||
includeDateTime=false
|
||||
includeFarFuture=true
|
||||
onChangeInput=(action (mut ignoredUntil))
|
||||
}}
|
||||
<p>{{i18n "user.user_notifications.ignore_duration_note"}}</p>
|
||||
|
|
|
@ -2,9 +2,8 @@
|
|||
{{future-date-input
|
||||
label="user.user_notifications.ignore_duration_when"
|
||||
input=ignoredUntil
|
||||
includeWeekend=true
|
||||
customShortcuts=timeShortcuts
|
||||
includeDateTime=false
|
||||
includeFarFuture=true
|
||||
onChangeInput=(action (mut ignoredUntil))
|
||||
}}
|
||||
<p>{{i18n "user.user_notifications.ignore_duration_note"}}</p>
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import componentTest, {
|
||||
setupRenderingTest,
|
||||
} from "discourse/tests/helpers/component-test";
|
||||
import {
|
||||
discourseModule,
|
||||
exists,
|
||||
queryAll,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import hbs from "htmlbars-inline-precompile";
|
||||
import I18n from "I18n";
|
||||
|
||||
discourseModule(
|
||||
"Unit | Lib | select-kit/future-date-input-selector",
|
||||
function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
this.set("subject", selectKit());
|
||||
});
|
||||
|
||||
hooks.afterEach(function () {
|
||||
if (this.clock) {
|
||||
this.clock.restore();
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("rendering and expanding", {
|
||||
template: hbs`
|
||||
{{future-date-input-selector
|
||||
options=(hash
|
||||
none="time_shortcut.select_timeframe"
|
||||
)
|
||||
}}
|
||||
`,
|
||||
|
||||
async test(assert) {
|
||||
assert.ok(
|
||||
exists(".future-date-input-selector"),
|
||||
"Selector is rendered"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
this.subject.header().label() ===
|
||||
I18n.t("time_shortcut.select_timeframe"),
|
||||
"Default text is rendered"
|
||||
);
|
||||
|
||||
await this.subject.expand();
|
||||
|
||||
assert.ok(
|
||||
exists(".select-kit-collection"),
|
||||
"List of options is rendered"
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("shows 'Custom date and time' if it's enabled", {
|
||||
template: hbs`
|
||||
{{future-date-input-selector
|
||||
includeDateTime=true
|
||||
}}
|
||||
`,
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
const options = getOptions();
|
||||
const customDateAndTime = I18n.t("time_shortcut.custom");
|
||||
|
||||
assert.ok(options.includes(customDateAndTime));
|
||||
},
|
||||
});
|
||||
|
||||
function getOptions() {
|
||||
return Array.from(
|
||||
queryAll(`.select-kit-collection .select-kit-row`).map(
|
||||
(_, span) => span.dataset.name
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
|
@ -0,0 +1,136 @@
|
|||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import componentTest, {
|
||||
setupRenderingTest,
|
||||
} from "discourse/tests/helpers/component-test";
|
||||
import {
|
||||
discourseModule,
|
||||
exists,
|
||||
fakeTime,
|
||||
queryAll,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import hbs from "htmlbars-inline-precompile";
|
||||
import I18n from "I18n";
|
||||
|
||||
discourseModule("Unit | Lib | select-kit/future-date-input", function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
this.set("subject", selectKit());
|
||||
});
|
||||
|
||||
hooks.afterEach(function () {
|
||||
if (this.clock) {
|
||||
this.clock.restore();
|
||||
}
|
||||
});
|
||||
|
||||
componentTest("rendering and expanding", {
|
||||
template: hbs`
|
||||
{{future-date-input
|
||||
options=(hash
|
||||
none="time_shortcut.select_timeframe"
|
||||
)
|
||||
}}
|
||||
`,
|
||||
|
||||
async test(assert) {
|
||||
assert.ok(exists(".future-date-input-selector"), "Selector is rendered");
|
||||
|
||||
assert.ok(
|
||||
this.subject.header().label() ===
|
||||
I18n.t("time_shortcut.select_timeframe"),
|
||||
"Default text is rendered"
|
||||
);
|
||||
|
||||
await this.subject.expand();
|
||||
|
||||
assert.ok(
|
||||
exists(".select-kit-collection"),
|
||||
"List of options is rendered"
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("renders default options", {
|
||||
template: hbs`{{future-date-input}}`,
|
||||
|
||||
beforeEach() {
|
||||
const monday = "2100-12-13T08:00:00";
|
||||
this.clock = fakeTime(monday, this.currentUser._timezone, true);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
const options = getOptions();
|
||||
const expected = [
|
||||
I18n.t("time_shortcut.later_today"),
|
||||
I18n.t("time_shortcut.tomorrow"),
|
||||
I18n.t("time_shortcut.later_this_week"),
|
||||
I18n.t("time_shortcut.start_of_next_business_week_alt"),
|
||||
I18n.t("time_shortcut.two_weeks"),
|
||||
I18n.t("time_shortcut.next_month"),
|
||||
I18n.t("time_shortcut.two_months"),
|
||||
I18n.t("time_shortcut.three_months"),
|
||||
I18n.t("time_shortcut.four_months"),
|
||||
I18n.t("time_shortcut.six_months"),
|
||||
I18n.t("time_shortcut.one_year"),
|
||||
I18n.t("time_shortcut.forever"),
|
||||
I18n.t("time_shortcut.custom"),
|
||||
];
|
||||
|
||||
assert.deepEqual(options, expected);
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("shows 'Custom date and time' by default", {
|
||||
template: hbs`{{future-date-input}}`,
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
const options = getOptions();
|
||||
const customDateAndTime = I18n.t("time_shortcut.custom");
|
||||
|
||||
assert.ok(options.includes(customDateAndTime));
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("doesn't show 'Custom date and time' if disabled", {
|
||||
template: hbs`
|
||||
{{future-date-input
|
||||
includeDateTime=false
|
||||
}}
|
||||
`,
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
const options = getOptions();
|
||||
const customDateAndTime = I18n.t("time_shortcut.custom");
|
||||
|
||||
assert.notOk(options.includes(customDateAndTime));
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("shows the now option if enabled", {
|
||||
template: hbs`
|
||||
{{future-date-input
|
||||
includeNow=true
|
||||
}}
|
||||
`,
|
||||
|
||||
async test(assert) {
|
||||
await this.subject.expand();
|
||||
const options = getOptions();
|
||||
const now = I18n.t("time_shortcut.now");
|
||||
|
||||
assert.ok(options.includes(now));
|
||||
},
|
||||
});
|
||||
|
||||
function getOptions() {
|
||||
return Array.from(
|
||||
queryAll(`.select-kit-collection .select-kit-row`).map(
|
||||
(_, span) => span.dataset.name
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
|
@ -0,0 +1,92 @@
|
|||
import { module, test } from "qunit";
|
||||
import { fakeTime } from "discourse/tests/helpers/qunit-helpers";
|
||||
import {
|
||||
defaultTimeShortcuts,
|
||||
hideDynamicTimeShortcuts,
|
||||
} from "discourse/lib/time-shortcut";
|
||||
|
||||
module(
|
||||
"Unit | Lib | time-shortcut | hideDynamicTimeShortcuts",
|
||||
function (hooks) {
|
||||
hooks.afterEach(function () {
|
||||
if (this.clock) {
|
||||
this.clock.restore();
|
||||
}
|
||||
});
|
||||
|
||||
test("hides 'Later Today' at the end of the day", function (assert) {
|
||||
const timezone = moment.tz.guess();
|
||||
const shortcuts = defaultTimeShortcuts(timezone);
|
||||
|
||||
this.clock = fakeTime("2100-04-19 08:00:00", timezone, true); // morning
|
||||
let result = hideDynamicTimeShortcuts(shortcuts, timezone).mapBy("id");
|
||||
assert.ok(
|
||||
result.includes("later_today"),
|
||||
"shows later_today in the morning"
|
||||
);
|
||||
|
||||
this.clock = fakeTime("2100-04-19 18:00:00", timezone, true); // evening
|
||||
result = hideDynamicTimeShortcuts(shortcuts, timezone).mapBy("id");
|
||||
assert.notOk(result.includes("doesn't show later_today in the evening"));
|
||||
});
|
||||
|
||||
test("hides 'Later This Week' starting from Thursday", function (assert) {
|
||||
const timezone = moment.tz.guess();
|
||||
const shortcuts = defaultTimeShortcuts(timezone);
|
||||
|
||||
this.clock = fakeTime("2100-04-21 18:00:00", timezone, true); // Wednesday
|
||||
let result = hideDynamicTimeShortcuts(shortcuts, timezone).mapBy("id");
|
||||
assert.ok(
|
||||
result.includes("later_this_week"),
|
||||
"shows later_this_week on Wednesdays"
|
||||
);
|
||||
|
||||
this.clock = fakeTime("2100-04-22 18:00:00", timezone, true); // Thursday
|
||||
result = hideDynamicTimeShortcuts(shortcuts, timezone).mapBy("id");
|
||||
assert.notOk(
|
||||
result.includes("later_this_week"),
|
||||
"doesn't show later_this_week on Thursdays"
|
||||
);
|
||||
|
||||
this.clock = fakeTime("2100-04-23 18:00:00", timezone, true); // Friday
|
||||
result = hideDynamicTimeShortcuts(shortcuts, timezone).mapBy("id");
|
||||
assert.notOk(
|
||||
result.includes("later_this_week"),
|
||||
"doesn't show later_this_week on Fridays"
|
||||
);
|
||||
});
|
||||
|
||||
test("hides 'This Weekend' on Fridays, Saturdays and Sundays", function (assert) {
|
||||
const timezone = moment.tz.guess();
|
||||
const shortcuts = defaultTimeShortcuts(timezone);
|
||||
|
||||
this.clock = fakeTime("2100-04-22 18:00:00", timezone, true); // Thursday
|
||||
let result = hideDynamicTimeShortcuts(shortcuts, timezone).mapBy("id");
|
||||
assert.ok(
|
||||
result.includes("this_weekend"),
|
||||
"shows this_weekend on Thursdays"
|
||||
);
|
||||
|
||||
this.clock = fakeTime("2100-04-23 18:00:00", timezone, true); // Friday
|
||||
result = hideDynamicTimeShortcuts(shortcuts, timezone).mapBy("id");
|
||||
assert.notOk(
|
||||
result.includes("this_weekend"),
|
||||
"doesn't show this_weekend on Fridays"
|
||||
);
|
||||
|
||||
this.clock = fakeTime("2100-04-24 18:00:00", timezone, true); // Saturday
|
||||
result = hideDynamicTimeShortcuts(shortcuts, timezone).mapBy("id");
|
||||
assert.notOk(
|
||||
result.includes("this_weekend"),
|
||||
"doesn't show this_weekend on Saturdays"
|
||||
);
|
||||
|
||||
this.clock = fakeTime("2100-04-25 18:00:00", timezone, true); // Sunday
|
||||
result = hideDynamicTimeShortcuts(shortcuts, timezone).mapBy("id");
|
||||
assert.notOk(
|
||||
result.includes("this_weekend"),
|
||||
"doesn't show this_weekend on Sundays"
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
|
@ -1,169 +0,0 @@
|
|||
import { module, test } from "qunit";
|
||||
import { fakeTime } from "discourse/tests/helpers/qunit-helpers";
|
||||
import buildTimeframes from "discourse/lib/timeframes-builder";
|
||||
|
||||
module("Unit | Lib | timeframes-builder", function (hooks) {
|
||||
hooks.afterEach(function () {
|
||||
if (this.clock) {
|
||||
this.clock.restore();
|
||||
}
|
||||
});
|
||||
|
||||
test("default options", function (assert) {
|
||||
const timezone = moment.tz.guess();
|
||||
this.clock = fakeTime("2100-06-07T08:00:00", timezone, true); // Monday
|
||||
|
||||
const expected = [
|
||||
"later_today",
|
||||
"tomorrow",
|
||||
"later_this_week",
|
||||
"start_of_next_business_week",
|
||||
"two_weeks",
|
||||
"next_month",
|
||||
"two_months",
|
||||
"three_months",
|
||||
"four_months",
|
||||
"six_months",
|
||||
];
|
||||
|
||||
assert.deepEqual(buildTimeframes(timezone).mapBy("id"), expected);
|
||||
});
|
||||
|
||||
test("doesn't output 'Next Week' on Sundays", function (assert) {
|
||||
const timezone = moment.tz.guess();
|
||||
this.clock = fakeTime("2100-06-13T08:00:00", timezone, true); // Sunday
|
||||
|
||||
assert.ok(
|
||||
!buildTimeframes(timezone)
|
||||
.mapBy("id")
|
||||
.includes("start_of_next_business_week")
|
||||
);
|
||||
});
|
||||
|
||||
test("outputs 'This Weekend' if it's enabled", function (assert) {
|
||||
const timezone = moment.tz.guess();
|
||||
this.clock = fakeTime("2100-06-07T08:00:00", timezone, true); // Monday
|
||||
|
||||
assert.ok(
|
||||
buildTimeframes(timezone, { includeWeekend: true })
|
||||
.mapBy("id")
|
||||
.includes("this_weekend")
|
||||
);
|
||||
});
|
||||
|
||||
test("doesn't output 'This Weekend' on Fridays", function (assert) {
|
||||
const timezone = moment.tz.guess();
|
||||
this.clock = fakeTime("2100-04-23 18:00:00", timezone, true); // Friday
|
||||
|
||||
assert.ok(
|
||||
!buildTimeframes(timezone, { includeWeekend: true })
|
||||
.mapBy("id")
|
||||
.includes("this_weekend")
|
||||
);
|
||||
});
|
||||
|
||||
test("doesn't show 'This Weekend' on Sundays", function (assert) {
|
||||
/*
|
||||
We need this test to avoid regressions.
|
||||
We tend to write such conditions and think that
|
||||
they mean the beginning of work week
|
||||
(Monday, Tuesday and Wednesday in this specific case):
|
||||
|
||||
if (date.day <= 3) {
|
||||
...
|
||||
}
|
||||
|
||||
In fact, Sunday will pass this check too, because
|
||||
in moment.js 0 stands for Sunday.
|
||||
*/
|
||||
|
||||
const timezone = moment.tz.guess();
|
||||
this.clock = fakeTime("2100-04-25 18:00:00", timezone, true); // Sunday
|
||||
|
||||
assert.ok(
|
||||
!buildTimeframes(timezone, { includeWeekend: true })
|
||||
.mapBy("id")
|
||||
.includes("this_weekend")
|
||||
);
|
||||
});
|
||||
|
||||
test("outputs 'Later This Week' instead of 'Later Today' at the end of the day", function (assert) {
|
||||
const timezone = moment.tz.guess();
|
||||
this.clock = fakeTime("2100-04-19 18:00:00", timezone, true); // Monday evening
|
||||
const timeframes = buildTimeframes(timezone).mapBy("id");
|
||||
|
||||
assert.notOk(timeframes.includes("later_today"));
|
||||
assert.ok(timeframes.includes("later_this_week"));
|
||||
});
|
||||
|
||||
test("doesn't output 'Later This Week' on Thursdays", function (assert) {
|
||||
const timezone = moment.tz.guess();
|
||||
this.clock = fakeTime("2100-04-22 18:00:00", timezone, true); // Thursday evening
|
||||
const timeframes = buildTimeframes(timezone).mapBy("id");
|
||||
|
||||
assert.notOk(timeframes.includes("later_this_week"));
|
||||
});
|
||||
|
||||
test("doesn't output 'Later This Week' on Sundays", function (assert) {
|
||||
/*
|
||||
We need this test to avoid regressions.
|
||||
We tend to write such conditions and think that
|
||||
they mean the beginning of business week
|
||||
(Monday, Tuesday and Wednesday in this specific case):
|
||||
|
||||
if (date.day < 3) {
|
||||
...
|
||||
}
|
||||
|
||||
In fact, Sunday will pass this check too, because
|
||||
in moment.js 0 stands for Sunday.
|
||||
*/
|
||||
const timezone = moment.tz.guess();
|
||||
this.clock = fakeTime("2100-04-25 18:00:00", timezone, true); // Sunday evening
|
||||
const timeframes = buildTimeframes(timezone).mapBy("id");
|
||||
|
||||
assert.notOk(timeframes.includes("later_this_week"));
|
||||
});
|
||||
|
||||
test("doesn't output 'Next Month' on the last day of the month", function (assert) {
|
||||
const timezone = moment.tz.guess();
|
||||
this.clock = fakeTime("2100-04-30 18:00:00", timezone, true); // The last day of April
|
||||
const timeframes = buildTimeframes(timezone).mapBy("id");
|
||||
|
||||
assert.notOk(timeframes.includes("next_month"));
|
||||
});
|
||||
|
||||
test("shows far future options if enabled", function (assert) {
|
||||
const timezone = moment.tz.guess();
|
||||
this.clock = fakeTime("2100-06-07T08:00:00", timezone, true); // Monday
|
||||
|
||||
const timeframes = buildTimeframes(timezone, {
|
||||
includeFarFuture: true,
|
||||
}).mapBy("id");
|
||||
|
||||
assert.ok(timeframes.includes("one_year"));
|
||||
assert.ok(timeframes.includes("forever"));
|
||||
});
|
||||
|
||||
test("shows the pick-date-and-time option if enabled", function (assert) {
|
||||
const timezone = moment.tz.guess();
|
||||
this.clock = fakeTime("2100-06-07T08:00:00", timezone, true); // Monday
|
||||
|
||||
const timeframes = buildTimeframes(timezone, {
|
||||
includeDateTime: true,
|
||||
}).mapBy("id");
|
||||
|
||||
assert.ok(timeframes.includes("custom"));
|
||||
});
|
||||
|
||||
test("shows the now option if enabled", function (assert) {
|
||||
const timezone = moment.tz.guess();
|
||||
this.clock = fakeTime("2100-06-07T08:00:00", timezone, true); // Monday
|
||||
|
||||
const timeframes = buildTimeframes(timezone, {
|
||||
canScheduleNow: true,
|
||||
}).mapBy("id");
|
||||
|
||||
assert.ok(timeframes.includes("now"));
|
||||
});
|
||||
});
|
|
@ -1,9 +1,6 @@
|
|||
import ComboBoxComponent from "select-kit/components/combo-box";
|
||||
import { computed } from "@ember/object";
|
||||
import { equal } from "@ember/object/computed";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
import buildTimeframes from "discourse/lib/timeframes-builder";
|
||||
import I18n from "I18n";
|
||||
|
||||
export const FORMAT = "YYYY-MM-DD HH:mmZ";
|
||||
|
||||
|
@ -28,25 +25,6 @@ export default ComboBoxComponent.extend({
|
|||
return "future-date-input-selector/future-date-input-selector-row";
|
||||
},
|
||||
|
||||
content: computed("statusType", function () {
|
||||
const opts = {
|
||||
includeWeekend: this.includeWeekend,
|
||||
includeFarFuture: this.includeFarFuture,
|
||||
includeDateTime: this.includeDateTime,
|
||||
canScheduleNow: this.includeNow || false,
|
||||
};
|
||||
|
||||
return buildTimeframes(this.userTimezone, opts).map((tf) => {
|
||||
return {
|
||||
id: tf.id,
|
||||
name: I18n.t(tf.label),
|
||||
time: tf.time,
|
||||
timeFormatted: tf.timeFormatted,
|
||||
icon: tf.icon,
|
||||
};
|
||||
});
|
||||
}),
|
||||
|
||||
actions: {
|
||||
onChange(value) {
|
||||
if (value !== "custom" && !isEmpty(value)) {
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
{{#styleguide-example title="future-date-input"}}
|
||||
{{future-date-input
|
||||
displayLabelIcon="far-clock"
|
||||
includeDateTime=true
|
||||
clearable=true
|
||||
}}
|
||||
{{/styleguide-example}}
|
||||
|
|
|
@ -58,7 +58,6 @@
|
|||
|
||||
{{#styleguide-example title="future-date-input-selector"}}
|
||||
{{future-date-input-selector
|
||||
statusType="open"
|
||||
input=dummy.topicTimerUpdateDate
|
||||
includeWeekend=true
|
||||
includeForever=true
|
||||
|
|
Loading…
Reference in New Issue
Block a user