mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-26 20:34:02 +03:00
Updated "Created" member filter to work against site timezone instead of UTC
no issue - updated NQL generation to adjust dates in filter string so they are the UTC equivalent - eg, in UTC-5 "created on or after 2022-02-22" becomes `created_at:>='2022-02-22 05:00:00'` - updated NQL parsing to take a UTC date filter, convert to a date in the site timezone, then convert to a local date in a way that the datepicker input value matches the respective site timezone date - eg, in UTC-5 `created_at:<='2022-02-22 04:59:59` becomes "created on or before 2022-02-21"
This commit is contained in:
parent
443689ffb3
commit
7470f887cb
@ -136,10 +136,15 @@ class Filter {
|
||||
this.type = options.type;
|
||||
this.relation = options.relation;
|
||||
this.relationOptions = options.relationOptions;
|
||||
this.timezone = options.timezone || 'Etc/UTC';
|
||||
|
||||
const filterProperty = FILTER_PROPERTIES.find(prop => this.type === prop.name);
|
||||
const value = filterProperty.valueType === 'date'
|
||||
? moment(options.value).toDate()
|
||||
|
||||
// date string values are passed in as UTC strings
|
||||
// we need to convert them to the site timezone and make a local date that matches
|
||||
// so the date string output in the filter inputs is correct
|
||||
const value = filterProperty.valueType === 'date' && typeof options.value === 'string'
|
||||
? moment(moment.tz(moment.utc(options.value), this.timezone).format('YYYY-MM-DD')).toDate()
|
||||
: options.value;
|
||||
|
||||
this.value = value;
|
||||
@ -263,19 +268,23 @@ export default class MembersFilter extends Component {
|
||||
|
||||
if (operator === '>') {
|
||||
relationStr = '>';
|
||||
filterValue = `'${moment(filter.value).set({hour: 23, minute: 59, second: 59}).format(nqlDateFormat)}'`;
|
||||
const tzMoment = moment.tz(moment(filter.value).format('YYYY-MM-DD'), this.settings.get('timezone')).set({hour: 23, minute: 59, second: 59});
|
||||
filterValue = `'${tzMoment.utc().format(nqlDateFormat)}'`;
|
||||
}
|
||||
if (operator === '>=') {
|
||||
relationStr = '>=';
|
||||
filterValue = `'${moment(filter.value).set({hour: 0, minute: 0, second: 0}).format(nqlDateFormat)}'`;
|
||||
const tzMoment = moment.tz(moment(filter.value).format('YYYY-MM-DD'), this.settings.get('timezone')).set({hour: 0, minute: 0, second: 0});
|
||||
filterValue = `'${tzMoment.utc().format(nqlDateFormat)}'`;
|
||||
}
|
||||
if (operator === '<') {
|
||||
relationStr = '<';
|
||||
filterValue = `'${moment(filter.value).set({hour: 0, minute: 0, second: 0}).format(nqlDateFormat)}'`;
|
||||
const tzMoment = moment.tz(moment(filter.value).format('YYYY-MM-DD'), this.settings.get('timezone')).set({hour: 0, minute: 0, second: 0});
|
||||
filterValue = `'${tzMoment.utc().format(nqlDateFormat)}'`;
|
||||
}
|
||||
if (operator === '<=') {
|
||||
relationStr = '<=';
|
||||
filterValue = `'${moment(filter.value).set({hour: 23, minute: 59, second: 59}).format(nqlDateFormat)}'`;
|
||||
const tzMoment = moment.tz(moment(filter.value).format('YYYY-MM-DD'), this.settings.get('timeone')).set({hour: 23, minute: 59, second: 59});
|
||||
filterValue = `'${tzMoment.utc().format(nqlDateFormat)}'`;
|
||||
}
|
||||
|
||||
query += `${filter.type}:${relationStr}${filterValue}+`;
|
||||
@ -302,7 +311,8 @@ export default class MembersFilter extends Component {
|
||||
type: key,
|
||||
relation: 'is',
|
||||
value: value.$in,
|
||||
relationOptions: FILTER_RELATIONS_OPTIONS[key]
|
||||
relationOptions: FILTER_RELATIONS_OPTIONS[key],
|
||||
timezone: this.settings.get('timezone')
|
||||
});
|
||||
}
|
||||
|
||||
@ -313,7 +323,8 @@ export default class MembersFilter extends Component {
|
||||
type: key,
|
||||
relation: 'is-not',
|
||||
value: value.$nin,
|
||||
relationOptions: FILTER_RELATIONS_OPTIONS[key]
|
||||
relationOptions: FILTER_RELATIONS_OPTIONS[key],
|
||||
timezone: this.settings.get('timezone')
|
||||
});
|
||||
}
|
||||
|
||||
@ -324,7 +335,8 @@ export default class MembersFilter extends Component {
|
||||
type: key,
|
||||
relation: 'is-not',
|
||||
value: value.$ne,
|
||||
relationOptions: FILTER_RELATIONS_OPTIONS[key]
|
||||
relationOptions: FILTER_RELATIONS_OPTIONS[key],
|
||||
timezone: this.settings.get('timezone')
|
||||
});
|
||||
}
|
||||
|
||||
@ -336,7 +348,8 @@ export default class MembersFilter extends Component {
|
||||
type: key,
|
||||
relation: 'is-greater',
|
||||
value: value.$gt,
|
||||
relationOptions: FILTER_RELATIONS_OPTIONS[key]
|
||||
relationOptions: FILTER_RELATIONS_OPTIONS[key],
|
||||
timezone: this.settings.get('timezone')
|
||||
});
|
||||
}
|
||||
|
||||
@ -348,7 +361,8 @@ export default class MembersFilter extends Component {
|
||||
type: key,
|
||||
relation: 'is-or-greater',
|
||||
value: value.$gte,
|
||||
relationOptions: FILTER_RELATIONS_OPTIONS[key]
|
||||
relationOptions: FILTER_RELATIONS_OPTIONS[key],
|
||||
timezone: this.settings.get('timezone')
|
||||
});
|
||||
}
|
||||
|
||||
@ -359,7 +373,8 @@ export default class MembersFilter extends Component {
|
||||
type: key,
|
||||
relation: 'is-less',
|
||||
value: value.$lt,
|
||||
relationOptions: FILTER_RELATIONS_OPTIONS[key]
|
||||
relationOptions: FILTER_RELATIONS_OPTIONS[key],
|
||||
timezone: this.settings.get('timezone')
|
||||
});
|
||||
}
|
||||
|
||||
@ -370,7 +385,8 @@ export default class MembersFilter extends Component {
|
||||
type: key,
|
||||
relation: 'is-or-less',
|
||||
value: value.$lte,
|
||||
relationOptions: FILTER_RELATIONS_OPTIONS[key]
|
||||
relationOptions: FILTER_RELATIONS_OPTIONS[key],
|
||||
timezone: this.settings.get('timezone')
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -699,7 +699,7 @@ describe('Acceptance: Members filtering', function () {
|
||||
// with a site timezone UTC-5 (Eastern Time Zone) we would expect date-based NQL filter strings
|
||||
// to be adjusted to UTC.
|
||||
//
|
||||
// Eg. "created at on or after 2022-02-22" = `created_at:>='2022-02-21 19:00:00'
|
||||
// Eg. "created on or after 2022-02-22" = `created_at:>='2022-02-22 05:00:00'
|
||||
//
|
||||
// we also need to convert back when parsing the NQL-based query param and make sure dates
|
||||
// shown in the members table match site timezone
|
||||
@ -721,6 +721,34 @@ describe('Acceptance: Members filtering', function () {
|
||||
const createdAtFields = findAll('[data-test-list="members-list-item"] [data-test-table-data="created-at"]');
|
||||
expect(createdAtFields.filter(el => el.textContent.match(/21 Feb 2022/)).length).to.equal(3);
|
||||
expect(createdAtFields.filter(el => el.textContent.match(/22 Feb 2022/)).length).to.equal(4);
|
||||
|
||||
const filterSelect = `[data-test-members-filter="0"]`;
|
||||
const typeSelect = `${filterSelect} [data-test-select="members-filter"]`;
|
||||
const operatorSelect = `${filterSelect} [data-test-select="members-filter-operator"]`;
|
||||
const valueInput = `${filterSelect} [data-test-input="members-filter-value"] [data-test-date-picker-input]`;
|
||||
|
||||
// filter date is transformed to UTC equivalent timeframe when querying
|
||||
await click('[data-test-button="members-filter-actions"]');
|
||||
await fillIn(typeSelect, 'created_at');
|
||||
await fillIn(operatorSelect, 'is-or-greater');
|
||||
await fillIn(valueInput, '2022-02-22');
|
||||
await blur(valueInput);
|
||||
|
||||
expect(findAll('[data-test-list="members-list-item"]').length, '# of member rows - post filter')
|
||||
.to.equal(4);
|
||||
|
||||
// query param is transformed back to expected filter date value
|
||||
await visit('/'); // TODO: remove once <Members::Filter> component reacts to filter updates
|
||||
const filterQuery = encodeURIComponent(`created_at:<='2022-02-22 04:59:59'`);
|
||||
await visit(`/members?filter=${filterQuery}`);
|
||||
|
||||
expect(findAll('[data-test-list="members-list-item"]').length, '# of member rows - post URL parse')
|
||||
.to.equal(3);
|
||||
|
||||
await click('[data-test-button="members-filter-actions"]');
|
||||
|
||||
expect(find(operatorSelect)).to.have.value('is-or-less');
|
||||
expect(find(valueInput)).to.have.value('2022-02-21');
|
||||
});
|
||||
|
||||
it('can handle multiple filters', async function () {
|
||||
|
Loading…
Reference in New Issue
Block a user