diff --git a/app/assets/javascripts/admin/components/admin-report.js b/app/assets/javascripts/admin/components/admin-report.js
index 178bef98f28..97db7c9df72 100644
--- a/app/assets/javascripts/admin/components/admin-report.js
+++ b/app/assets/javascripts/admin/components/admin-report.js
@@ -1,7 +1,7 @@
import discourseComputed from "discourse-common/utils/decorators";
import { makeArray } from "discourse-common/lib/helpers";
-import { alias, or, and, reads, equal, notEmpty } from "@ember/object/computed";
-import EmberObject from "@ember/object";
+import { alias, or, and, equal, notEmpty } from "@ember/object/computed";
+import EmberObject, { computed, action } from "@ember/object";
import { next } from "@ember/runloop";
import Component from "@ember/component";
import ReportLoader from "discourse/lib/reports-loader";
@@ -9,6 +9,7 @@ import { exportEntity } from "discourse/lib/export-csv";
import { outputExportResult } from "discourse/lib/export-result";
import Report, { SCHEMA_VERSION } from "admin/models/report";
import ENV from "discourse-common/config/environment";
+import { isPresent } from "@ember/utils";
const TABLE_OPTIONS = {
perPage: 8,
@@ -69,8 +70,21 @@ export default Component.extend({
this._reports = [];
},
- startDate: reads("filters.startDate"),
- endDate: reads("filters.endDate"),
+ startDate: computed("filters.startDate", function() {
+ if (this.filters && isPresent(this.filters.startDate)) {
+ return moment(this.filters.startDate, "YYYY-MM-DD");
+ } else {
+ return moment();
+ }
+ }),
+
+ endDate: computed("filters.endDate", function() {
+ if (this.filters && isPresent(this.filters.endDate)) {
+ return moment(this.filters.endDate, "YYYY-MM-DD");
+ } else {
+ return moment();
+ }
+ }),
didReceiveAttrs() {
this._super(...arguments);
@@ -126,39 +140,18 @@ export default Component.extend({
return `admin-report-${currentMode.replace(/_/g, "-")}`;
},
- @discourseComputed("startDate")
- normalizedStartDate(startDate) {
- return startDate && typeof startDate.isValid === "function"
- ? moment
- .utc(startDate.toISOString())
- .locale("en")
- .format("YYYYMMDD")
- : moment(startDate)
- .locale("en")
- .format("YYYYMMDD");
- },
-
- @discourseComputed("endDate")
- normalizedEndDate(endDate) {
- return endDate && typeof endDate.isValid === "function"
- ? moment
- .utc(endDate.toISOString())
- .locale("en")
- .format("YYYYMMDD")
- : moment(endDate)
- .locale("en")
- .format("YYYYMMDD");
- },
-
@discourseComputed(
"dataSourceName",
- "normalizedStartDate",
- "normalizedEndDate",
+ "startDate",
+ "endDate",
"filters.customFilters"
)
reportKey(dataSourceName, startDate, endDate, customFilters) {
if (!dataSourceName || !startDate || !endDate) return null;
+ startDate = startDate.toISOString(true).split("T")[0];
+ endDate = endDate.toISOString(true).split("T")[0];
+
let reportKey = "reports:";
reportKey += [
dataSourceName,
@@ -179,74 +172,61 @@ export default Component.extend({
return reportKey;
},
- actions: {
- onChangeEndDate(date) {
- const startDate = moment(this.startDate);
- const newEndDate = moment(date).endOf("day");
+ @action
+ onChangeDateRange(range) {
+ this.send("refreshReport", {
+ startDate: range.from,
+ endDate: range.to
+ });
+ },
- if (newEndDate.isSameOrAfter(startDate)) {
- this.set("endDate", newEndDate.format("YYYY-MM-DD"));
- } else {
- this.set("endDate", startDate.endOf("day").format("YYYY-MM-DD"));
- }
+ @action
+ applyFilter(id, value) {
+ let customFilters = this.get("filters.customFilters") || {};
- this.send("refreshReport");
- },
-
- onChangeStartDate(date) {
- const endDate = moment(this.endDate);
- const newStartDate = moment(date).startOf("day");
-
- if (newStartDate.isSameOrBefore(endDate)) {
- this.set("startDate", newStartDate.format("YYYY-MM-DD"));
- } else {
- this.set("startDate", endDate.startOf("day").format("YYYY-MM-DD"));
- }
-
- this.send("refreshReport");
- },
-
- applyFilter(id, value) {
- let customFilters = this.get("filters.customFilters") || {};
-
- if (typeof value === "undefined") {
- delete customFilters[id];
- } else {
- customFilters[id] = value;
- }
-
- this.attrs.onRefresh({
- type: this.get("model.type"),
- startDate: this.startDate,
- endDate: this.endDate,
- filters: customFilters
- });
- },
-
- refreshReport() {
- this.attrs.onRefresh({
- type: this.get("model.type"),
- startDate: this.startDate,
- endDate: this.endDate,
- filters: this.get("filters.customFilters")
- });
- },
-
- exportCsv() {
- const customFilters = this.get("filters.customFilters") || {};
-
- exportEntity("report", {
- name: this.get("model.type"),
- start_date: this.startDate,
- end_date: this.endDate,
- category_id: customFilters.category,
- group_id: customFilters.group
- }).then(outputExportResult);
- },
-
- changeMode(mode) {
- this.set("currentMode", mode);
+ if (typeof value === "undefined") {
+ delete customFilters[id];
+ } else {
+ customFilters[id] = value;
}
+
+ this.send("refreshReport", {
+ filters: customFilters
+ });
+ },
+
+ @action
+ refreshReport(options = {}) {
+ this.attrs.onRefresh({
+ type: this.get("model.type"),
+ startDate:
+ typeof options.startDate === "undefined"
+ ? this.startDate
+ : options.startDate,
+ endDate:
+ typeof options.endDate === "undefined" ? this.endDate : options.endDate,
+ filters:
+ typeof options.filters === "undefined"
+ ? this.get("filters.customFilters")
+ : options.filters
+ });
+ },
+
+ @action
+ exportCsv() {
+ const customFilters = this.get("filters.customFilters") || {};
+ exportEntity("report", {
+ name: this.get("model.type"),
+ start_date: this.startDate.toISOString(true).split("T")[0],
+ end_date: this.endDate.toISOString(true).split("T")[0],
+ category_id: customFilters.category,
+ group_id: customFilters.group
+ }).then(outputExportResult);
+ },
+
+ @action
+ changeMode(mode) {
+ this.set("currentMode", mode);
},
_computeReport() {
@@ -276,10 +256,8 @@ export default Component.extend({
if (!this.startDate || !this.endDate) {
report = sort(filteredReports)[0];
} else {
- const reportKey = this.reportKey;
-
report = sort(
- filteredReports.filter(r => r.report_key.includes(reportKey))
+ filteredReports.filter(r => r.report_key.includes(this.reportKey))
)[0];
if (!report) return;
@@ -339,15 +317,15 @@ export default Component.extend({
let payload = { data: { cache: true, facets } };
if (this.startDate) {
- payload.data.start_date = moment
- .utc(this.startDate, "YYYY-MM-DD")
- .toISOString();
+ payload.data.start_date = moment(this.startDate)
+ .toISOString(true)
+ .split("T")[0];
}
if (this.endDate) {
- payload.data.end_date = moment
- .utc(this.endDate, "YYYY-MM-DD")
- .toISOString();
+ payload.data.end_date = moment(this.endDate)
+ .toISOString(true)
+ .split("T")[0];
}
if (this.get("reportOptions.table.limit")) {
diff --git a/app/assets/javascripts/admin/routes/admin-reports-show.js b/app/assets/javascripts/admin/routes/admin-reports-show.js
index 1fa8bc739d1..3a8a5430a9b 100644
--- a/app/assets/javascripts/admin/routes/admin-reports-show.js
+++ b/app/assets/javascripts/admin/routes/admin-reports-show.js
@@ -13,8 +13,7 @@ export default DiscourseRoute.extend({
params.startDate =
params.start_date ||
- moment
- .utc()
+ moment()
.subtract(1, "day")
.subtract(1, "month")
.startOf("day")
@@ -23,8 +22,7 @@ export default DiscourseRoute.extend({
params.endDate =
params.end_date ||
- moment
- .utc()
+ moment()
.endOf("day")
.format("YYYY-MM-DD");
delete params.end_date;
@@ -56,9 +54,13 @@ export default DiscourseRoute.extend({
onParamsChange(params) {
const queryParams = {
type: params.type,
- start_date: params.startDate,
+ start_date: params.startDate
+ ? params.startDate.toISOString(true).split("T")[0]
+ : null,
filters: params.filters,
end_date: params.endDate
+ ? params.endDate.toISOString(true).split("T")[0]
+ : null
};
this.transitionTo("adminReports.show", { queryParams });
diff --git a/app/assets/javascripts/admin/templates/components/admin-report.hbs b/app/assets/javascripts/admin/templates/components/admin-report.hbs
index ab0c1a63980..ee375ac6ff6 100644
--- a/app/assets/javascripts/admin/templates/components/admin-report.hbs
+++ b/app/assets/javascripts/admin/templates/components/admin-report.hbs
@@ -132,26 +132,16 @@
{{#if showDatesOptions}}
- {{i18n "admin.dashboard.reports.start_date"}}
+ {{i18n "admin.dashboard.reports.dates"}}
- {{date-input
- date=startDate
- onChange=(action "onChangeStartDate")
- }}
-
-
-
-
-
- {{i18n "admin.dashboard.reports.end_date"}}
-
-
-
- {{date-input
- date=endDate
- onChange=(action "onChangeEndDate")
+ {{date-time-input-range
+ from=startDate
+ to=endDate
+ onChange=(action "onChangeDateRange")
+ showFromTime=false
+ showToTime=false
}}
diff --git a/app/assets/javascripts/discourse/components/date-input.js b/app/assets/javascripts/discourse/components/date-input.js
index b44640bcd42..d4ee63ee9b0 100644
--- a/app/assets/javascripts/discourse/components/date-input.js
+++ b/app/assets/javascripts/discourse/components/date-input.js
@@ -1,4 +1,5 @@
import { schedule } from "@ember/runloop";
+import { action } from "@ember/object";
import Component from "@ember/component";
/* global Pikaday:true */
import loadScript from "discourse/lib/load-script";
@@ -25,8 +26,8 @@ export default Component.extend({
this._loadPikadayPicker(container);
}
- if (this.date && this._picker) {
- this._picker.setDate(this.date, true);
+ if (this._picker && this.date) {
+ this._picker.setDate(moment(this.date).toDate(), true);
}
});
},
@@ -34,9 +35,12 @@ export default Component.extend({
didUpdateAttrs() {
this._super(...arguments);
- if (this._picker && typeof this.date === "string") {
- const [year, month, day] = this.date.split("-").map(x => parseInt(x, 10));
- this._picker.setDate(new Date(year, month - 1, day), true);
+ if (this._picker && this.date) {
+ this._picker.setDate(moment(this.date).toDate(), true);
+ }
+
+ if (this._picker && this.relativeDate) {
+ this._picker.setMinDate(moment(this.relativeDate).toDate(), true);
}
if (this._picker && !this.date) {
@@ -46,13 +50,12 @@ export default Component.extend({
_loadPikadayPicker(container) {
loadScript("/javascripts/pikaday.js").then(() => {
- const defaultOptions = {
+ let defaultOptions = {
field: this.element.querySelector(".date-picker"),
container: container || this.element.querySelector(".picker-container"),
bound: container === null,
format: "LL",
firstDay: 1,
- trigger: this.element,
i18n: {
previousMonth: I18n.t("dates.previous_month"),
nextMonth: I18n.t("dates.next_month"),
@@ -63,8 +66,16 @@ export default Component.extend({
onSelect: date => this._handleSelection(date)
};
- this._picker = new Pikaday(Object.assign(defaultOptions, this._opts()));
- this._picker.setDate(this.date, true);
+ if (this.relativeDate) {
+ defaultOptions = Object.assign({}, defaultOptions, {
+ minDate: moment(this.relativeDate).toDate()
+ });
+ }
+
+ this._picker = new Pikaday(
+ Object.assign({}, defaultOptions, this._opts())
+ );
+ this._picker.setDate(moment(this.date).toDate(), true);
});
},
@@ -79,18 +90,23 @@ export default Component.extend({
/* do nothing for native */
};
picker.setDate = date => {
- picker.value = date;
+ picker.value = moment(date).format("YYYY-MM-DD");
+ };
+ picker.setMinDate = date => {
+ picker.min = date;
};
this._picker = picker;
+
+ if (this.date) {
+ picker.setDate(this.date);
+ }
},
_handleSelection(value) {
if (!this.element || this.isDestroying || this.isDestroyed) return;
- this._picker && this._picker.hide();
-
if (this.onChange) {
- this.onChange(value);
+ this.onChange(value ? moment(value) : null);
}
},
@@ -98,8 +114,8 @@ export default Component.extend({
_destroy() {
if (this._picker) {
this._picker.destroy();
+ this._picker = null;
}
- this._picker = null;
},
@discourseComputed()
@@ -111,9 +127,8 @@ export default Component.extend({
return null;
},
- actions: {
- onInput(event) {
- this._picker && this._picker.setDate(event.target.value, true);
- }
+ @action
+ onChangeDate(event) {
+ this._handleSelection(event.target.value);
}
});
diff --git a/app/assets/javascripts/discourse/components/date-time-input-range.js b/app/assets/javascripts/discourse/components/date-time-input-range.js
index 52438ffd949..cb30e162358 100644
--- a/app/assets/javascripts/discourse/components/date-time-input-range.js
+++ b/app/assets/javascripts/discourse/components/date-time-input-range.js
@@ -1,53 +1,46 @@
-import { equal } from "@ember/object/computed";
import Component from "@ember/component";
+import { action } from "@ember/object";
+
export default Component.extend({
classNames: ["d-date-time-input-range"],
-
from: null,
to: null,
onChangeTo: null,
onChangeFrom: null,
- currentPanel: "from",
- showFromTime: true,
+ toTimeFirst: false,
showToTime: true,
- error: null,
+ showFromTime: true,
+ clearable: false,
- fromPanelActive: equal("currentPanel", "from"),
- toPanelActive: equal("currentPanel", "to"),
+ @action
+ onChangeRanges(options, value) {
+ if (this.onChange) {
+ const state = {
+ from: this.from,
+ to: this.to
+ };
- _valid(state) {
- if (state.to && state.from && state.to < state.from) {
- return I18n.t("date_time_picker.errors.to_before_from");
- }
+ const diff = {};
- return true;
- },
-
- actions: {
- _onChange(options, value) {
- if (this.onChange) {
- const state = {
- from: this.from,
- to: this.to
- };
-
- const diff = {};
- diff[options.prop] = value;
-
- const newState = Object.assign(state, diff);
-
- const validation = this._valid(newState);
- if (validation === true) {
- this.set("error", null);
- this.onChange(newState);
+ if (options.prop === "from") {
+ if (value && value.isAfter(this.to)) {
+ diff[options.prop] = value;
+ diff["to"] = value.clone().add(1, "hour");
} else {
- this.set("error", validation);
+ diff[options.prop] = value;
}
}
- },
- onChangePanel(panel) {
- this.set("currentPanel", panel);
+ if (options.prop === "to") {
+ if (value && value.isBefore(this.from)) {
+ diff[options.prop] = this.from.clone().add(1, "hour");
+ } else {
+ diff[options.prop] = value;
+ }
+ }
+
+ const newState = Object.assign({}, state, diff);
+ this.onChange(newState);
}
}
});
diff --git a/app/assets/javascripts/discourse/components/date-time-input.js b/app/assets/javascripts/discourse/components/date-time-input.js
index eff8b99edc4..01fbddaf1c3 100644
--- a/app/assets/javascripts/discourse/components/date-time-input.js
+++ b/app/assets/javascripts/discourse/components/date-time-input.js
@@ -1,44 +1,63 @@
import Component from "@ember/component";
-import { computed } from "@ember/object";
+import { computed, action } from "@ember/object";
export default Component.extend({
classNames: ["d-date-time-input"],
date: null,
+ relativeDate: null,
showTime: true,
clearable: false,
- _hours: computed("date", function() {
- return this.date && this.showTime ? new Date(this.date).getHours() : null;
+ hours: computed("date", "showTime", function() {
+ return this.date && this.get("showTime") ? this.date.hours() : null;
}),
- _minutes: computed("date", function() {
- return this.date && this.showTime ? new Date(this.date).getMinutes() : null;
+ minutes: computed("date", "showTime", function() {
+ return this.date && this.get("showTime") ? this.date.minutes() : null;
}),
- actions: {
- onClear() {
- this.onChange(null);
- },
+ @action
+ onClear() {
+ this.onChange(null);
+ },
- onChangeTime(time) {
- if (this.onChange) {
- const date = new Date(this.date);
- const year = date.getFullYear();
- const month = date.getMonth();
- const day = date.getDate();
- this.onChange(new Date(year, month, day, time.hours, time.minutes));
- }
- },
+ @action
+ onChangeTime(time) {
+ if (this.onChange) {
+ const date = this.date
+ ? this.date
+ : this.relativeDate
+ ? this.relativeDate
+ : moment();
- onChangeDate(date) {
- if (this.onChange) {
- const year = date.getFullYear();
- const month = date.getMonth();
- const day = date.getDate();
- this.onChange(
- new Date(year, month, day, this._hours || 0, this._minutes || 0)
- );
- }
+ this.onChange(
+ moment({
+ year: date.year(),
+ month: date.month(),
+ day: date.date(),
+ hours: time.hours,
+ minutes: time.minutes
+ })
+ );
}
+ },
+
+ @action
+ onChangeDate(date) {
+ if (!date) {
+ this.onClear();
+ return;
+ }
+
+ this.onChange &&
+ this.onChange(
+ moment({
+ year: date.year(),
+ month: date.month(),
+ day: date.date(),
+ hours: this.hours || 0,
+ minutes: this.minutes || 0
+ })
+ );
}
});
diff --git a/app/assets/javascripts/discourse/components/time-input.js b/app/assets/javascripts/discourse/components/time-input.js
index e636380a770..2e28f6974e7 100644
--- a/app/assets/javascripts/discourse/components/time-input.js
+++ b/app/assets/javascripts/discourse/components/time-input.js
@@ -1,76 +1,171 @@
-import { oneWay, or } from "@ember/object/computed";
-import { schedule } from "@ember/runloop";
+import { isPresent } from "@ember/utils";
+import { computed, action } from "@ember/object";
import Component from "@ember/component";
-import { isNumeric } from "discourse/lib/utilities";
+
+function convertMinutes(num) {
+ return { hours: Math.floor(num / 60), minutes: num % 60 };
+}
+
+function convertMinutesToString(n) {
+ const hoursAndMinutes = convertMinutes(n);
+ return `${hoursAndMinutes.hours
+ .toString()
+ .padStart(2, "0")}:${hoursAndMinutes.minutes.toString().padStart(2, "0")}`;
+}
+
+function convertMinutesToDurationString(n) {
+ const hoursAndMinutes = convertMinutes(n);
+
+ let output = "";
+
+ if (hoursAndMinutes.hours) {
+ output = `${hoursAndMinutes.hours}h`;
+
+ if (hoursAndMinutes.minutes > 0) {
+ output = `${output} ${hoursAndMinutes.minutes} min`;
+ }
+ } else {
+ output = `${hoursAndMinutes.minutes} min`;
+ }
+
+ return output;
+}
export default Component.extend({
classNames: ["d-time-input"],
+
hours: null,
+
minutes: null,
- _hours: oneWay("hours"),
- _minutes: oneWay("minutes"),
- isSafari: oneWay("capabilities.isSafari"),
- isMobile: oneWay("site.mobileView"),
- nativePicker: or("isSafari", "isMobile"),
- actions: {
- onInput(options, event) {
- event.preventDefault();
+ relativeDate: null,
- if (this.onChange) {
- let value = event.target.value;
+ didReceiveAttrs() {
+ this._super(...arguments);
- if (!isNumeric(value)) {
- value = 0;
- } else {
- value = parseInt(value, 10);
- }
+ if (isPresent(this.date)) {
+ this.setProperties({
+ hours: this.date.hours(),
+ minutes: this.date.minutes()
+ });
+ }
- if (options.prop === "hours") {
- value = Math.max(0, Math.min(value, 23))
- .toString()
- .padStart(2, "0");
- this._processHoursChange(value);
- } else {
- value = Math.max(0, Math.min(value, 59))
- .toString()
- .padStart(2, "0");
- this._processMinutesChange(value);
- }
-
- schedule("afterRender", () => (event.target.value = value));
- }
- },
-
- onFocusIn(value, event) {
- if (value && event.target) {
- event.target.select();
- }
- },
-
- onChangeTime(event) {
- const time = event.target.value;
-
- if (time && this.onChange) {
- this.onChange({
- hours: time.split(":")[0],
- minutes: time.split(":")[1]
- });
- }
+ if (
+ !isPresent(this.date) &&
+ !isPresent(this.attrs.hours) &&
+ !isPresent(this.attrs.minutes)
+ ) {
+ this.setProperties({
+ hours: null,
+ minutes: null
+ });
}
},
- _processHoursChange(hours) {
- this.onChange({
- hours,
- minutes: this._minutes || "00"
+ minimumTime: computed("relativeDate", "date", function() {
+ if (this.relativeDate) {
+ if (this.date) {
+ if (this.date.diff(this.relativeDate, "minutes") > 1440) {
+ return 0;
+ } else {
+ return this.relativeDate.hours() * 60 + this.relativeDate.minutes();
+ }
+ } else {
+ return this.relativeDate.hours() * 60 + this.relativeDate.minutes();
+ }
+ }
+ }),
+
+ timeOptions: computed("minimumTime", "hours", "minutes", function() {
+ let options = [];
+
+ const start = this.minimumTime
+ ? this.minimumTime > this.time
+ ? this.time
+ : this.minimumTime
+ : 0;
+
+ // theres 1440 minutes in a day
+ // and 1440 / 15 = 96
+ let i = 0;
+ while (i < 96) {
+ // while diff with minimumTime is less than one hour
+ // use 15 minutes steps and then 30 minutes
+ const minutes = this.minimumTime ? (i <= 4 ? 15 : 30) : 15;
+ const option = start + i * minutes;
+
+ // when start is higher than 0 we will reach 1440 minutes
+ // before the 96 iterations
+ if (option > 1440) {
+ break;
+ }
+
+ options.push(option);
+
+ i++;
+ }
+
+ if (this.time && !options.includes(this.time)) {
+ options = [this.time].concat(options);
+ }
+
+ options = options.sort((a, b) => a - b);
+
+ return options.map(option => {
+ let name = convertMinutesToString(option);
+ let label;
+
+ if (this.minimumTime) {
+ const diff = option - this.minimumTime;
+ label = `${name} (${convertMinutesToDurationString(
+ diff
+ )})`.htmlSafe();
+ }
+
+ return {
+ id: option,
+ name,
+ label,
+ title: name
+ };
});
+ }),
+
+ time: computed("minimumTime", "hours", "minutes", function() {
+ if (isPresent(this.hours) && isPresent(this.minutes)) {
+ return parseInt(this.hours, 10) * 60 + parseInt(this.minutes, 10);
+ }
+ }),
+
+ @action
+ onFocusIn(value, event) {
+ if (value && event.target) {
+ event.target.select();
+ }
},
- _processMinutesChange(minutes) {
- this.onChange({
- hours: this._hours || "00",
- minutes
- });
+ @action
+ onChangeTime(time) {
+ if (isPresent(time) && this.onChange) {
+ if (typeof time === "string" && time.length) {
+ let [hours, minutes] = time.split(":");
+ if (hours && minutes) {
+ if (hours < 0) hours = 0;
+ if (hours > 23) hours = 23;
+ if (minutes < 0) minutes = 0;
+ if (minutes > 59) minutes = 59;
+
+ this.onChange({
+ hours: parseInt(hours, 10),
+ minutes: parseInt(minutes, 10)
+ });
+ }
+ } else {
+ this.onChange({
+ hours: convertMinutes(time).hours,
+ minutes: convertMinutes(time).minutes
+ });
+ }
+ }
}
});
diff --git a/app/assets/javascripts/discourse/controllers/review-index.js b/app/assets/javascripts/discourse/controllers/review-index.js
index aeb61d7d61e..4d319ee8bf3 100644
--- a/app/assets/javascripts/discourse/controllers/review-index.js
+++ b/app/assets/javascripts/discourse/controllers/review-index.js
@@ -1,5 +1,6 @@
import discourseComputed from "discourse-common/utils/decorators";
import Controller from "@ember/controller";
+import { isPresent } from "@ember/utils";
export default Controller.extend({
queryParams: [
@@ -86,12 +87,7 @@ export default Controller.extend({
},
setRange(range) {
- if (range.from) {
- this.set("from", new Date(range.from).toISOString().split("T")[0]);
- }
- if (range.to) {
- this.set("to", new Date(range.to).toISOString().split("T")[0]);
- }
+ this.setProperties(range);
},
actions: {
@@ -118,8 +114,12 @@ export default Controller.extend({
status: this.filterStatus,
category_id: this.filterCategoryId,
username: this.filterUsername,
- from_date: this.filterFromDate,
- to_date: this.filterToDate,
+ from_date: isPresent(this.filterFromDate)
+ ? this.filterFromDate.toISOString(true).split("T")[0]
+ : null,
+ to_date: isPresent(this.filterToDate)
+ ? this.filterToDate.toISOString(true).split("T")[0]
+ : null,
sort_order: this.filterSortOrder,
additional_filters: JSON.stringify(this.additionalFilters)
});
diff --git a/app/assets/javascripts/discourse/routes/review-index.js b/app/assets/javascripts/discourse/routes/review-index.js
index 3f2a8abc4a3..4edd43a3343 100644
--- a/app/assets/javascripts/discourse/routes/review-index.js
+++ b/app/assets/javascripts/discourse/routes/review-index.js
@@ -1,4 +1,5 @@
import DiscourseRoute from "discourse/routes/discourse";
+import { isPresent } from "@ember/utils";
export default DiscourseRoute.extend({
model(params) {
@@ -23,8 +24,8 @@ export default DiscourseRoute.extend({
filterPriority: meta.priority,
reviewableTypes: meta.reviewable_types,
filterUsername: meta.username,
- filterFromDate: meta.from_date,
- filterToDate: meta.to_date,
+ filterFromDate: isPresent(meta.from_date) ? moment(meta.from_date) : null,
+ filterToDate: isPresent(meta.to_date) ? moment(meta.to_date) : null,
filterSortOrder: meta.sort_order,
additionalFilters: meta.additional_filters || {}
});
diff --git a/app/assets/javascripts/discourse/templates/components/date-input.hbs b/app/assets/javascripts/discourse/templates/components/date-input.hbs
index ad48e3e25de..b86c4604419 100644
--- a/app/assets/javascripts/discourse/templates/components/date-input.hbs
+++ b/app/assets/javascripts/discourse/templates/components/date-input.hbs
@@ -2,9 +2,8 @@
type=inputType
class="date-picker"
placeholder=placeholder
- value=value
- input=(action "onInput")
- readonly=true
+ value=(readonly value)
+ input=(action "onChangeDate")
}}
diff --git a/app/assets/javascripts/discourse/templates/components/date-time-input-range.hbs b/app/assets/javascripts/discourse/templates/components/date-time-input-range.hbs
index faa96a1eca4..a8e1786acec 100644
--- a/app/assets/javascripts/discourse/templates/components/date-time-input-range.hbs
+++ b/app/assets/javascripts/discourse/templates/components/date-time-input-range.hbs
@@ -1,35 +1,16 @@
-
- -
- {{d-button
- label="date_time_picker.from"
- class="from-panel"
- action=(action "onChangePanel" "from")}}
-
- -
- {{d-button
- label="date_time_picker.to"
- class="to-panel"
- action=(action "onChangePanel" "to")}}
-
-
+{{date-time-input
+ date=from
+ onChange=(action "onChangeRanges" (hash prop="from"))
+ showTime=showFromTime
+ class="from"
+}}
-{{#if error}}
- {{error}}
-{{/if}}
-
-
- {{date-time-input
- date=from
- onChange=(action "_onChange" (hash prop="from"))
- showTime=showFromTime
- }}
-
-
-
- {{date-time-input
- date=to
- onChange=(action "_onChange" (hash prop="to"))
- showTime=showToTime
- clearable=true
- }}
-
+{{date-time-input
+ date=to
+ relativeDate=from
+ onChange=(action "onChangeRanges" (hash prop="to"))
+ timeFirst=toTimeFirst
+ showTime=showToTime
+ clearable=clearable
+ class="to"
+}}
diff --git a/app/assets/javascripts/discourse/templates/components/date-time-input.hbs b/app/assets/javascripts/discourse/templates/components/date-time-input.hbs
index 0b243e74a48..0ec475f5714 100644
--- a/app/assets/javascripts/discourse/templates/components/date-time-input.hbs
+++ b/app/assets/javascripts/discourse/templates/components/date-time-input.hbs
@@ -1,13 +1,31 @@
-{{date-input date=date onChange=(action "onChangeDate")}}
+{{#unless timeFirst}}
+ {{date-input
+ date=date
+ relativeDate=relativeDate
+ onChange=(action "onChangeDate")
+ }}
+{{/unless}}
{{#if showTime}}
{{time-input
- hours=_hours
- minutes=_minutes
+ date=date
+ relativeDate=relativeDate
onChange=(action "onChangeTime")
}}
-
- {{#if clearable}}
- {{d-button icon="times" action=(action "onClear")}}
- {{/if}}
+{{/if}}
+
+{{#if timeFirst}}
+ {{date-input
+ date=date
+ relativeDate=relativeDate
+ onChange=(action "onChangeDate")
+ }}
+{{/if}}
+
+{{#if clearable}}
+ {{d-button
+ class="clear-date-time"
+ icon="times"
+ action=(action "onClear")
+ }}
{{/if}}
diff --git a/app/assets/javascripts/discourse/templates/components/time-input.hbs b/app/assets/javascripts/discourse/templates/components/time-input.hbs
index 51ada91bf64..8dd13ff06b3 100644
--- a/app/assets/javascripts/discourse/templates/components/time-input.hbs
+++ b/app/assets/javascripts/discourse/templates/components/time-input.hbs
@@ -1,40 +1,12 @@
-
- {{#if nativePicker}}
- {{input
- class="field time"
- type="time"
- value=(concat _hours ":" _minutes)
- change=(action "onChangeTime")
- }}
- {{else}}
- {{input
- class="field hours"
- type="number"
- title="Hours"
- minlength=2
- maxlength=2
- max="23"
- min="0"
- placeholder="00"
- value=_hours
- input=(action "onInput" (hash prop="hours"))
- focus-in=(action "onFocusIn")
- }}
-
-
:
-
- {{input
- class="field minutes"
- title="Minutes"
- type="number"
- minlength=2
- maxlength=2
- max="59"
- min="0"
- placeholder="00"
- value=_minutes
- input=(action "onInput" (hash prop="minutes"))
- focus-in=(action "onFocusIn")
- }}
- {{/if}}
-
+{{combo-box
+ value=time
+ content=timeOptions
+ onChange=(action "onChangeTime")
+ options=(hash
+ translatedNone="--:--"
+ allowAny=true
+ filterable=false
+ autoInsertNoneItem=false
+ translatedFilterPlaceholder="--:--"
+ )
+}}
diff --git a/app/assets/javascripts/discourse/templates/review-index.hbs b/app/assets/javascripts/discourse/templates/review-index.hbs
index 7b603f9fa08..c5a0fad8891 100644
--- a/app/assets/javascripts/discourse/templates/review-index.hbs
+++ b/app/assets/javascripts/discourse/templates/review-index.hbs
@@ -77,7 +77,13 @@
{{/if}}
- {{date-time-input-range showFromTime=false showToTime=false from=filterFromDate to=filterToDate onChange=setRange}}
+ {{date-time-input-range
+ from=filterFromDate
+ to=filterToDate
+ onChange=setRange
+ showFromTime=false
+ showToTime=false
+ }}
diff --git a/app/assets/javascripts/select-kit/components/select-kit.js b/app/assets/javascripts/select-kit/components/select-kit.js
index 360dd65738d..4c0b095c1b7 100644
--- a/app/assets/javascripts/select-kit/components/select-kit.js
+++ b/app/assets/javascripts/select-kit/components/select-kit.js
@@ -482,10 +482,7 @@ export default Component.extend(
this.selectKit.options.allowAny &&
!this.selectKit.isExpanded
) {
- return this.defaultItem(
- null,
- I18n.t("select_kit.filter_placeholder_with_any")
- );
+ return null;
}
let item;
@@ -754,8 +751,6 @@ export default Component.extend(
},
_onCloseWrapper(event) {
- this._focusFilter(this.multiSelect);
-
this.set("selectKit.highlighted", null);
let boundaryAction = this._boundaryActionHandler("onClose");
diff --git a/app/assets/stylesheets/common/admin/admin_report.scss b/app/assets/stylesheets/common/admin/admin_report.scss
index 3bf74813193..82bef5d1be5 100644
--- a/app/assets/stylesheets/common/admin/admin_report.scss
+++ b/app/assets/stylesheets/common/admin/admin_report.scss
@@ -161,13 +161,9 @@
width: 100%;
}
- .date-picker-wrapper {
+ .d-date-time-input-range {
+ flex-direction: column;
width: 100%;
- .date-picker {
- box-sizing: border-box;
- width: 100%;
- margin: 0;
- }
}
}
}
diff --git a/app/assets/stylesheets/common/base/reviewables.scss b/app/assets/stylesheets/common/base/reviewables.scss
index 2b85d211052..8c2bc4f91d2 100644
--- a/app/assets/stylesheets/common/base/reviewables.scss
+++ b/app/assets/stylesheets/common/base/reviewables.scss
@@ -126,6 +126,7 @@
width: inherit;
border: none;
padding: 0;
+ flex-direction: column;
.d-date-input {
flex: 1 1 auto;
diff --git a/app/assets/stylesheets/common/base/search.scss b/app/assets/stylesheets/common/base/search.scss
index e62f24f2921..895a4727b6f 100644
--- a/app/assets/stylesheets/common/base/search.scss
+++ b/app/assets/stylesheets/common/base/search.scss
@@ -116,11 +116,9 @@
flex-direction: column;
#search-min-post-count,
- .date-picker,
.combo-box,
.ac-wrap,
.control-group,
- .date-picker-wrapper,
.search-advanced-category-chooser {
box-sizing: border-box;
width: 100%;
@@ -131,15 +129,9 @@
}
}
- .date-picker-wrapper {
+ .d-date-input {
margin-top: 0.5em;
- }
-
- .date-picker {
- box-sizing: border-box;
- text-align: left;
- padding: 4px;
- margin-bottom: 0;
+ width: 100%;
}
.search-advanced-title {
diff --git a/app/assets/stylesheets/common/components/date-input.scss b/app/assets/stylesheets/common/components/date-input.scss
index b24ad8ea4eb..c0f453d4230 100644
--- a/app/assets/stylesheets/common/components/date-input.scss
+++ b/app/assets/stylesheets/common/components/date-input.scss
@@ -1,19 +1,58 @@
.d-date-input {
- display: flex;
- flex: 1;
+ display: inline-flex;
cursor: pointer;
flex-direction: column;
+ min-width: 140px;
.date-picker {
cursor: pointer;
margin: 0;
text-align: left;
width: 100%;
- outline: none;
box-shadow: none !important;
+
+ &::-webkit-input-placeholder {
+ font-size: $font-0;
+ color: $primary-medium;
+ }
+
+ &::-ms-input-placeholder {
+ font-size: $font-0;
+ color: $primary-medium;
+ }
+
+ &::placeholder {
+ font-size: $font-0;
+ color: $primary-medium;
+ }
+
+ &:focus {
+ outline: 1px solid $tertiary;
+ outline-offset: 0;
+ }
}
.pika-single {
margin-left: -1px;
+ margin-top: 1px;
+
+ .pika-row td {
+ .pika-button.pika-day {
+ box-shadow: none;
+ border-radius: 0;
+ }
+ }
}
}
+
+.d-date-input + .d-time-input {
+ margin-left: 1px;
+}
+
+.d-time-input + .d-date-input {
+ margin-left: 1px;
+}
+
+.d-date-input + .clear-date-time {
+ margin-left: 1px;
+}
diff --git a/app/assets/stylesheets/common/components/date-time-input-range.scss b/app/assets/stylesheets/common/components/date-time-input-range.scss
index e46dd6f0b67..47704fcd647 100644
--- a/app/assets/stylesheets/common/components/date-time-input-range.scss
+++ b/app/assets/stylesheets/common/components/date-time-input-range.scss
@@ -1,41 +1,5 @@
.d-date-time-input-range {
- padding: 0.5em;
border: 1px solid $primary-low;
- width: 300px;
- display: flex;
- flex-direction: column;
-
- .panels {
- display: inline-flex;
- list-style: none;
- margin: 0 0 0.5em 0;
- flex: 1;
-
- &.from {
- .from-panel {
- background: $danger;
- color: $secondary;
- }
- }
-
- &.to {
- .to-panel {
- background: $danger;
- color: $secondary;
- }
- }
-
- .btn {
- margin-right: 0.5em;
- }
- }
-
- .panel {
- display: none;
- flex: 1;
-
- &.visible {
- display: flex;
- }
- }
+ display: inline-flex;
+ box-sizing: border-box;
}
diff --git a/app/assets/stylesheets/common/components/date-time-input.scss b/app/assets/stylesheets/common/components/date-time-input.scss
index 1ebe50f9f95..6d113b31307 100644
--- a/app/assets/stylesheets/common/components/date-time-input.scss
+++ b/app/assets/stylesheets/common/components/date-time-input.scss
@@ -1,10 +1,8 @@
.d-date-time-input {
display: flex;
- align-items: center;
border: 1px solid $primary-low;
box-sizing: border-box;
position: relative;
- flex: 1;
.date-picker,
.fields {
@@ -13,5 +11,22 @@
.d-date-time-input {
margin-left: auto;
+ flex: 1 1 auto;
+ }
+
+ .d-time-input {
+ .select-kit.combo-box {
+ .select-kit-header {
+ border: none;
+ }
+ }
+ }
+
+ .d-date-input + .d-time-input {
+ margin-left: 1px;
+ }
+
+ .d-time-input + .d-date-input {
+ margin-right: 1px;
}
}
diff --git a/app/assets/stylesheets/common/components/time-input.scss b/app/assets/stylesheets/common/components/time-input.scss
index d11e2b7c7d9..73d5ef692cd 100644
--- a/app/assets/stylesheets/common/components/time-input.scss
+++ b/app/assets/stylesheets/common/components/time-input.scss
@@ -1,39 +1,43 @@
+.modal-inner-container .d-time-input,
.d-time-input {
- box-sizing: border-box;
+ display: inline-flex;
- .fields {
- display: flex;
- align-items: center;
- border: 1px solid $primary-low;
+ .combo-box {
+ width: 65px;
+ min-width: auto;
- .field {
- text-align: center;
+ &:not(.has-selection) {
+ .select-kit-selected-name .name {
+ color: $primary-medium;
+ }
+ }
+
+ .select-kit-header {
+ .d-icon {
+ padding-left: 0;
+ }
+
+ &:focus {
+ outline: 1px solid $tertiary;
+ }
+ }
+
+ .select-kit-collection {
+ min-width: auto;
+ }
+
+ .select-kit-filter {
width: auto;
- margin: 0;
- border: none;
- outline: none;
- box-shadow: none;
- width: 32px;
-
- &.time {
- width: 100%;
- text-align: left;
+ overflow: hidden;
+ .filter-input {
+ min-width: 0;
}
+ }
- &.hours,
- &.minutes {
- text-align: center;
- width: 45px;
- }
-
- &.hours {
- padding-right: 0;
- }
-
- &.minutes {
- padding-left: 10px;
- width: 55px;
- }
+ .selected-name {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
}
}
}
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 94a3b84af2b..af4c1549b1d 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -304,7 +304,6 @@ en:
unbookmark: "Click to remove all bookmarks in this topic"
unbookmark_with_reminder: "Click to remove all bookmarks and reminders in this topic. You have a reminder set %{reminder_at} for this topic."
-
bookmarks:
created: "you've bookmarked this post"
not_bookmarked: "bookmark this post"
@@ -3393,8 +3392,7 @@ en:
view_table: "table"
view_graph: "graph"
refresh_report: "Refresh Report"
- start_date: "Start Date (UTC)"
- end_date: "End Date (UTC)"
+ dates: "Dates (UTC)"
groups: "All groups"
disabled: "This report is disabled"
totals_for_sample: "Totals for sample"
diff --git a/test/javascripts/acceptance/dashboard-test.js b/test/javascripts/acceptance/dashboard-test.js
index affe6c0a9f5..09c8d0a0b71 100644
--- a/test/javascripts/acceptance/dashboard-test.js
+++ b/test/javascripts/acceptance/dashboard-test.js
@@ -102,7 +102,7 @@ QUnit.test("reports tab", async assert => {
QUnit.test("report filters", async assert => {
await visit(
- '/admin/reports/signups?end_date=2018-07-16&filters=%7B"group"%3A88%7D&start_date=2018-06-16'
+ '/admin/reports/signups_with_groups?end_date=2018-07-16&filters=%7B"group"%3A88%7D&start_date=2018-06-16'
);
const groupFilter = selectKit(".group-filter .combo-box");
diff --git a/test/javascripts/components/date-input-test.js b/test/javascripts/components/date-input-test.js
index 64686aba06d..29f01b4f50e 100644
--- a/test/javascripts/components/date-input-test.js
+++ b/test/javascripts/components/date-input-test.js
@@ -18,7 +18,7 @@ async function pika(year, month, day) {
function noop() {}
-const DEFAULT_DATE = new Date(2019, 0, 29);
+const DEFAULT_DATE = moment("2019-01-29");
componentTest("default", {
template: `{{date-input date=date}}`,
@@ -44,7 +44,7 @@ componentTest("prevents mutations", {
await click(dateInput());
await pika(2019, 0, 2);
- assert.ok(this.date.getTime() === DEFAULT_DATE.getTime());
+ assert.ok(this.date.isSame(DEFAULT_DATE));
}
});
@@ -60,6 +60,6 @@ componentTest("allows mutations through actions", {
await click(dateInput());
await pika(2019, 0, 2);
- assert.ok(this.date.getTime() === new Date(2019, 0, 2).getTime());
+ assert.ok(this.date.isSame(moment("2019-01-02")));
}
});
diff --git a/test/javascripts/components/date-time-input-range-test.js b/test/javascripts/components/date-time-input-range-test.js
index 69ff0a9d458..9ffa7e6ef66 100644
--- a/test/javascripts/components/date-time-input-range-test.js
+++ b/test/javascripts/components/date-time-input-range-test.js
@@ -3,40 +3,22 @@ import componentTest from "helpers/component-test";
moduleForComponent("date-time-input-range", { integration: true });
function fromDateInput() {
- return find(".from .date-picker");
+ return find(".from.d-date-time-input .date-picker")[0];
}
-function fromHoursInput() {
- return find(".from .field.hours");
-}
-
-function fromMinutesInput() {
- return find(".from .field.minutes");
+function fromTimeInput() {
+ return find(".from.d-date-time-input .d-time-input .combo-box-header")[0];
}
function toDateInput() {
- return find(".to .date-picker");
+ return find(".to.d-date-time-input .date-picker")[0];
}
-function toHoursInput() {
- return find(".to .field.hours");
+function toTimeInput() {
+ return find(".to.d-date-time-input .d-time-input .combo-box-header")[0];
}
-function toMinutesInput() {
- return find(".to .field.minutes");
-}
-
-function setDates(dates) {
- this.setProperties(dates);
-}
-
-async function pika(year, month, day) {
- await click(
- `.pika-button.pika-day[data-pika-year="${year}"][data-pika-month="${month}"][data-pika-day="${day}"]`
- );
-}
-
-const DEFAULT_DATE_TIME = new Date(2019, 0, 29, 14, 45);
+const DEFAULT_DATE_TIME = moment("2019-01-29 14:45");
componentTest("default", {
template: `{{date-time-input-range from=from to=to}}`,
@@ -46,60 +28,9 @@ componentTest("default", {
},
test(assert) {
- assert.equal(fromDateInput().val(), "January 29, 2019");
- assert.equal(fromHoursInput().val(), "14");
- assert.equal(fromMinutesInput().val(), "45");
-
- assert.equal(toDateInput().val(), "");
- assert.equal(toHoursInput().val(), "");
- assert.equal(toMinutesInput().val(), "");
- }
-});
-
-componentTest("can switch panels", {
- template: `{{date-time-input-range}}`,
-
- async test(assert) {
- assert.ok(exists(".panel.from.visible"));
- assert.notOk(exists(".panel.to.visible"));
-
- await click(".panels button.to-panel");
-
- assert.ok(exists(".panel.to.visible"));
- assert.notOk(exists(".panel.from.visible"));
- }
-});
-
-componentTest("prevents toDate to be before fromDate", {
- template: `{{date-time-input-range from=from to=to onChange=onChange}}`,
-
- beforeEach() {
- this.setProperties({
- from: DEFAULT_DATE_TIME,
- to: DEFAULT_DATE_TIME,
- onChange: setDates
- });
- },
-
- async test(assert) {
- assert.notOk(exists(".error"), "it begins with no error");
-
- await click(".panels button.to-panel");
- await click(toDateInput());
- await pika(2019, 0, 1);
-
- assert.ok(exists(".error"), "it shows an error");
- assert.deepEqual(this.to, DEFAULT_DATE_TIME, "it didnt trigger a mutation");
-
- await click(".panels button.to-panel");
- await click(toDateInput());
- await pika(2019, 0, 30);
-
- assert.notOk(exists(".error"), "it removes the error");
- assert.deepEqual(
- this.to,
- new Date(2019, 0, 30, 14, 45),
- "it has changed the date"
- );
+ assert.equal(fromDateInput().value, "January 29, 2019");
+ assert.equal(fromTimeInput().dataset.name, "14:45");
+ assert.equal(toDateInput().value, "");
+ assert.equal(toTimeInput().dataset.name, "--:--");
}
});
diff --git a/test/javascripts/components/date-time-input-test.js b/test/javascripts/components/date-time-input-test.js
index 2dd4ac8fcf4..e56e3e09130 100644
--- a/test/javascripts/components/date-time-input-test.js
+++ b/test/javascripts/components/date-time-input-test.js
@@ -3,15 +3,11 @@ import componentTest from "helpers/component-test";
moduleForComponent("date-time-input", { integration: true });
function dateInput() {
- return find(".date-picker");
+ return find(".date-picker")[0];
}
-function hoursInput() {
- return find(".field.hours");
-}
-
-function minutesInput() {
- return find(".field.minutes");
+function timeInput() {
+ return find(".d-time-input .combo-box-header")[0];
}
function setDate(date) {
@@ -24,7 +20,7 @@ async function pika(year, month, day) {
);
}
-const DEFAULT_DATE_TIME = new Date(2019, 0, 29, 14, 45);
+const DEFAULT_DATE_TIME = moment("2019-01-29 14:45");
componentTest("default", {
template: `{{date-time-input date=date}}`,
@@ -34,9 +30,8 @@ componentTest("default", {
},
test(assert) {
- assert.equal(dateInput().val(), "January 29, 2019");
- assert.equal(hoursInput().val(), "14");
- assert.equal(minutesInput().val(), "45");
+ assert.equal(dateInput().value, "January 29, 2019");
+ assert.equal(timeInput().dataset.name, "14:45");
}
});
@@ -51,7 +46,7 @@ componentTest("prevents mutations", {
await click(dateInput());
await pika(2019, 0, 2);
- assert.ok(this.date.getTime() === DEFAULT_DATE_TIME.getTime());
+ assert.ok(this.date.isSame(DEFAULT_DATE_TIME));
}
});
@@ -67,7 +62,7 @@ componentTest("allows mutations through actions", {
await click(dateInput());
await pika(2019, 0, 2);
- assert.ok(this.date.getTime() === new Date(2019, 0, 2, 14, 45).getTime());
+ assert.ok(this.date.isSame(moment("2019-01-02 14:45")));
}
});
@@ -79,6 +74,6 @@ componentTest("can hide time", {
},
async test(assert) {
- assert.notOk(exists(hoursInput()));
+ assert.notOk(exists(timeInput()));
}
});
diff --git a/test/javascripts/components/time-input-test.js b/test/javascripts/components/time-input-test.js
index edbe7574c82..a6ef6606c99 100644
--- a/test/javascripts/components/time-input-test.js
+++ b/test/javascripts/components/time-input-test.js
@@ -1,21 +1,18 @@
+import selectKit from "helpers/select-kit-helper";
import componentTest from "helpers/component-test";
-moduleForComponent("time-input", { integration: true });
+moduleForComponent("time-input", {
+ integration: true,
-function hoursInput() {
- return find(".field.hours");
-}
-
-function minutesInput() {
- return find(".field.minutes");
-}
+ beforeEach() {
+ this.set("subject", selectKit());
+ }
+});
function setTime(time) {
this.setProperties(time);
}
-function noop() {}
-
componentTest("default", {
template: `{{time-input hours=hours minutes=minutes}}`,
@@ -24,8 +21,7 @@ componentTest("default", {
},
test(assert) {
- assert.equal(hoursInput().val(), "14");
- assert.equal(minutesInput().val(), "58");
+ assert.equal(this.subject.header().name(), "14:58");
}
});
@@ -37,11 +33,9 @@ componentTest("prevents mutations", {
},
async test(assert) {
- await fillIn(hoursInput(), "12");
- assert.ok(this.hours === "14");
-
- await fillIn(minutesInput(), "36");
- assert.ok(this.minutes === "58");
+ await this.subject.expand();
+ await this.subject.selectRowByIndex(3);
+ assert.equal(this.subject.header().name(), "14:58");
}
});
@@ -54,44 +48,8 @@ componentTest("allows mutations through actions", {
},
async test(assert) {
- await fillIn(hoursInput(), "12");
- assert.ok(this.hours === "12");
-
- await fillIn(minutesInput(), "36");
- assert.ok(this.minutes === "36");
- }
-});
-
-componentTest("hours and minutes have boundaries", {
- template: `{{time-input hours=14 minutes=58 onChange=onChange}}`,
-
- beforeEach() {
- this.set("onChange", noop);
- },
-
- async test(assert) {
- await fillIn(hoursInput(), "2");
- assert.equal(hoursInput().val(), "02");
-
- await fillIn(hoursInput(), "@");
- assert.equal(hoursInput().val(), "00");
-
- await fillIn(hoursInput(), "24");
- assert.equal(hoursInput().val(), "23");
-
- await fillIn(hoursInput(), "-1");
- assert.equal(hoursInput().val(), "00");
-
- await fillIn(minutesInput(), "@");
- assert.equal(minutesInput().val(), "00");
-
- await fillIn(minutesInput(), "2");
- assert.equal(minutesInput().val(), "02");
-
- await fillIn(minutesInput(), "60");
- assert.equal(minutesInput().val(), "59");
-
- await fillIn(minutesInput(), "-1");
- assert.equal(minutesInput().val(), "00");
+ await this.subject.expand();
+ await this.subject.selectRowByIndex(3);
+ assert.equal(this.subject.header().name(), "00:45");
}
});
diff --git a/test/javascripts/fixtures/reports_bulk.js b/test/javascripts/fixtures/reports_bulk.js
index a41cf345836..100648b3f4f 100644
--- a/test/javascripts/fixtures/reports_bulk.js
+++ b/test/javascripts/fixtures/reports_bulk.js
@@ -59,7 +59,7 @@ let signups = {
prev_end_date: "2018-06-17T00:00:00Z",
prev30Days: null,
dates_filtering: true,
- report_key: 'reports:signups:start:end:[:prev_period]:50:{"group":"88"}:4',
+ report_key: "reports:signups:start:end:[:prev_period]:4",
available_filters: [
{ id: "group", type: "group", allow_any: false, choices: [], default: "88" }
],
@@ -77,18 +77,29 @@ let signups = {
let signups_fixture = JSON.parse(JSON.stringify(signups));
signups_fixture.type = "signups_exception";
signups_fixture.error = "exception";
+signups_fixture.report_key =
+ "reports:signups_exception:start:end:[:prev_period]:4";
const signups_exception = signups_fixture;
signups_fixture = JSON.parse(JSON.stringify(signups));
signups_fixture.type = "signups_timeout";
signups_fixture.error = "timeout";
+signups_fixture.report_key =
+ "reports:signups_timeout:start:end:[:prev_period]:4";
const signups_timeout = signups_fixture;
signups_fixture = JSON.parse(JSON.stringify(signups));
signups_fixture.type = "not_found";
signups_fixture.error = "not_found";
+signups_fixture.report_key = "reports:not_found:start:end:[:prev_period]:4";
const signups_not_found = signups_fixture;
+signups_fixture = JSON.parse(JSON.stringify(signups));
+signups_fixture.type = "signups_with_groups";
+signups_fixture.report_key =
+ 'reports:signups_with_groups:start:end:[:prev_period]:50:{"group":"88"}:4';
+const signups_with_group = signups_fixture;
+
const startDate = moment()
.locale("en")
.utc()
@@ -180,6 +191,7 @@ export default {
"/admin/reports/bulk": {
reports: [
signups,
+ signups_with_group,
signups_not_found,
signups_exception,
signups_timeout,