mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-26 20:34:02 +03:00
Switched "Last seen" filter to standard date picker filter
refs https://github.com/TryGhost/Team/issues/1410 - we have problems translating an "x days ago" NQL filter back to the UI component so as a temporary measure we're switching to a datepicker input as we have a working solution for that - a later iteration will add shortcut buttons for selecting typical "x days ago" dates in the datepicker
This commit is contained in:
parent
e23ae31e8f
commit
1f062ff844
@ -33,19 +33,13 @@
|
||||
</span>
|
||||
|
||||
{{else if (eq @filter.type 'last_seen_at')}}
|
||||
<div class="relative">
|
||||
<span class="gh-input-percentage-label">days ago</span>
|
||||
<input
|
||||
type="number"
|
||||
value={{@filter.value}}
|
||||
class="gh-input"
|
||||
aria-label="Number of days ago"
|
||||
{{on "input" (fn this.setInputFilterValue @filter.type @filter.id)}}
|
||||
{{on "blur" (fn this.updateInputFilterValue @filter.type @filter.id)}}
|
||||
{{on "keypress" (fn this.updateInputFilterValueOnEnter @filter.type @filter.id)}}
|
||||
data-test-input="members-filter-value"
|
||||
/>
|
||||
</div>
|
||||
<GhDatePicker
|
||||
@value={{@filter.value}}
|
||||
@maxDate={{now}}
|
||||
@maxDateError="Must be in the past"
|
||||
@onChange={{fn @setFilterValue @filter.type @filter.id}}
|
||||
data-test-input="members-filter-value"
|
||||
/>
|
||||
|
||||
{{else if (eq @filter.type 'created_at')}}
|
||||
<GhDatePicker
|
||||
|
@ -15,7 +15,7 @@ const FILTER_PROPERTIES = [
|
||||
{label: 'Label', name: 'label', group: 'Basic'},
|
||||
{label: 'Tiers', name: 'product', group: 'Basic', feature: 'multipleProducts'},
|
||||
{label: 'Newsletter subscription', name: 'subscribed', group: 'Basic'},
|
||||
{label: 'Last seen', name: 'last_seen_at', group: 'Basic', feature: 'membersLastSeenFilter'},
|
||||
{label: 'Last seen', name: 'last_seen_at', group: 'Basic', valueType: 'date', feature: 'membersLastSeenFilter'},
|
||||
{label: 'Created', name: 'created_at', group: 'Basic', valueType: 'date'},
|
||||
|
||||
// Member subscription
|
||||
@ -38,6 +38,17 @@ const FILTER_PROPERTIES = [
|
||||
// {label: 'Open rate (60 days)', name: 'x', group: 'Email'},
|
||||
];
|
||||
|
||||
const DATE_RELATION_OPTIONS = [
|
||||
{label: 'before', name: 'is-less'},
|
||||
{label: 'on or before', name: 'is-or-less'},
|
||||
// TODO: these cause problems because they require multiple NQL statements, eg:
|
||||
// created_at:>='2022-03-02 00:00'+created_at:<'2022-03-03 00:00'
|
||||
// {label: 'on', name: 'is'},
|
||||
// {label: 'not on', name: 'is-not'},
|
||||
{label: 'after', name: 'is-greater'},
|
||||
{label: 'on or after', name: 'is-or-greater'}
|
||||
];
|
||||
|
||||
const FILTER_RELATIONS_OPTIONS = {
|
||||
// name: [
|
||||
// {label: 'is', name: 'is'},
|
||||
@ -59,20 +70,8 @@ const FILTER_RELATIONS_OPTIONS = {
|
||||
{label: 'is', name: 'is'},
|
||||
{label: 'is not', name: 'is-not'}
|
||||
],
|
||||
last_seen_at: [
|
||||
{label: 'less than', name: 'is-less'},
|
||||
{label: 'more than', name: 'is-greater'}
|
||||
],
|
||||
created_at: [
|
||||
{label: 'before', name: 'is-less'},
|
||||
{label: 'on or before', name: 'is-or-less'},
|
||||
// TODO: these cause problems because they require multiple NQL statements, eg:
|
||||
// created_at:>='2022-03-02 00:00'+created_at:<'2022-03-03 00:00'
|
||||
// {label: 'on', name: 'is'},
|
||||
// {label: 'not on', name: 'is-not'},
|
||||
{label: 'after', name: 'is-greater'},
|
||||
{label: 'on or after', name: 'is-or-greater'}
|
||||
],
|
||||
last_seen_at: DATE_RELATION_OPTIONS,
|
||||
created_at: DATE_RELATION_OPTIONS,
|
||||
status: [
|
||||
{label: 'is', name: 'is'},
|
||||
{label: 'is not', name: 'is-not'}
|
||||
@ -85,26 +84,8 @@ const FILTER_RELATIONS_OPTIONS = {
|
||||
{label: 'is', name: 'is'},
|
||||
{label: 'is not', name: 'is-not'}
|
||||
],
|
||||
'subscriptions.start_date': [
|
||||
{label: 'before', name: 'is-less'},
|
||||
{label: 'on or before', name: 'is-or-less'},
|
||||
// TODO: these cause problems because they require multiple NQL statements, eg:
|
||||
// created_at:>='2022-03-02 00:00'+created_at:<'2022-03-03 00:00'
|
||||
// {label: 'on', name: 'is'},
|
||||
// {label: 'not on', name: 'is-not'},
|
||||
{label: 'after', name: 'is-greater'},
|
||||
{label: 'on or after', name: 'is-or-greater'}
|
||||
],
|
||||
'subscriptions.current_period_end': [
|
||||
{label: 'before', name: 'is-less'},
|
||||
{label: 'on or before', name: 'is-or-less'},
|
||||
// TODO: these cause problems because they require multiple NQL statements, eg:
|
||||
// created_at:>='2022-03-02 00:00'+created_at:<'2022-03-03 00:00'
|
||||
// {label: 'on', name: 'is'},
|
||||
// {label: 'not on', name: 'is-not'},
|
||||
{label: 'after', name: 'is-greater'},
|
||||
{label: 'on or after', name: 'is-or-greater'}
|
||||
],
|
||||
'subscriptions.start_date': DATE_RELATION_OPTIONS,
|
||||
'subscriptions.current_period_end': DATE_RELATION_OPTIONS,
|
||||
email_count: [
|
||||
{label: 'is', name: 'is'},
|
||||
{label: 'is greater than', name: 'is-greater'},
|
||||
@ -276,13 +257,6 @@ export default class MembersFilter extends Component {
|
||||
const relationStr = filter.relation === 'is-not' ? '-' : '';
|
||||
const filterValue = '[' + filter.value.join(',') + ']';
|
||||
query += `${filter.type}:${relationStr}${filterValue}+`;
|
||||
} else if (filter.type === 'last_seen_at') {
|
||||
// is-greater = more than x days ago = <date
|
||||
// is-less = less than x days ago = >date
|
||||
const relationStr = filter.relation === 'is-greater' ? '<=' : '>=';
|
||||
const daysAgoMoment = moment.utc().subtract(filter.value, 'days');
|
||||
const filterValue = `'${daysAgoMoment.format(nqlDateFormat)}'`;
|
||||
query += `${filter.type}:${relationStr}${filterValue}+`;
|
||||
} else if (filterProperty.valueType === 'date') {
|
||||
const operator = relationMap[filter.relation];
|
||||
let relationStr;
|
||||
|
@ -536,37 +536,41 @@ describe('Acceptance: Members filtering', function () {
|
||||
|
||||
it('can filter by last seen date', async function () {
|
||||
clock = sinon.useFakeTimers({
|
||||
now: moment('2022-02-10 11:50:00.000Z').toDate(),
|
||||
now: moment('2022-02-05 11:50:00.000Z').toDate(),
|
||||
shouldAdvanceTime: true
|
||||
});
|
||||
|
||||
// add some members to filter
|
||||
this.server.createList('member', 3, {lastSeenAt: moment('2022-02-01 12:00:00').format('YYYY-MM-DD HH:mm:ss')});
|
||||
this.server.createList('member', 4, {lastSeenAt: moment('2022-02-05 12:00:00').format('YYYY-MM-DD HH:mm:ss')});
|
||||
this.server.createList('member', 3, {lastSeenAt: moment('2022-02-01 11:00:00').format('YYYY-MM-DD HH:mm:ss')});
|
||||
this.server.createList('member', 4, {lastSeenAt: moment('2022-02-05 11:00:00').format('YYYY-MM-DD HH:mm:ss')});
|
||||
|
||||
await visit('/members');
|
||||
|
||||
expect(findAll('[data-test-list="members-list-item"]').length, '# of initial member rows')
|
||||
.to.equal(7);
|
||||
|
||||
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]`;
|
||||
const valueDatePicker = `${filterSelect} [data-test-input="members-filter-value"]`;
|
||||
|
||||
await click('[data-test-button="members-filter-actions"]');
|
||||
|
||||
const filterSelector = `[data-test-members-filter="0"]`;
|
||||
|
||||
await fillIn(`${filterSelector} [data-test-select="members-filter"]`, 'last_seen_at');
|
||||
|
||||
const operatorSelector = `${filterSelector} [data-test-select="members-filter-operator"]`;
|
||||
await fillIn(typeSelect, 'last_seen_at');
|
||||
|
||||
// has the right operators
|
||||
const operatorOptions = findAll(`${operatorSelector} option`);
|
||||
expect(operatorOptions).to.have.length(2);
|
||||
const operatorOptions = findAll(`${operatorSelect} option`);
|
||||
expect(operatorOptions).to.have.length(4);
|
||||
expect(operatorOptions[0]).to.have.value('is-less');
|
||||
expect(operatorOptions[1]).to.have.value('is-greater');
|
||||
expect(operatorOptions[1]).to.have.value('is-or-less');
|
||||
expect(operatorOptions[2]).to.have.value('is-greater');
|
||||
expect(operatorOptions[3]).to.have.value('is-or-greater');
|
||||
|
||||
const valueInput = `${filterSelector} [data-test-input="members-filter-value"]`;
|
||||
// has the right default operator
|
||||
expect(find(operatorSelect)).to.have.value('is-or-less');
|
||||
|
||||
// has no default filter
|
||||
expect(find(valueInput)).to.have.value('');
|
||||
// has expected default value
|
||||
expect(find(valueInput)).to.have.value('2022-02-05');
|
||||
expect(findAll('[data-test-list="members-list-item"]').length, '# of filtered member rows - default')
|
||||
.to.equal(7);
|
||||
|
||||
@ -576,42 +580,29 @@ describe('Acceptance: Members filtering', function () {
|
||||
expect(findAll('[data-test-list="members-list-item"]').length, '# of filtered member rows - after blur')
|
||||
.to.equal(7);
|
||||
|
||||
// can change filter
|
||||
await fillIn(valueInput, '2'); // last seen less than 2 days ago
|
||||
await blur(valueInput);
|
||||
expect(findAll('[data-test-list="members-list-item"]').length, '# of filtered member rows - last seen less than 2 days ago')
|
||||
.to.equal(0);
|
||||
// can change operator
|
||||
await fillIn(operatorSelect, 'is-less');
|
||||
expect(findAll('[data-test-list="members-list-item"]').length, '# of filtered member rows - is before 2022-02-05')
|
||||
.to.equal(3);
|
||||
|
||||
await fillIn(valueInput, '6'); // last seen less than 6 days ago
|
||||
// can change filter via input
|
||||
await fillIn(operatorSelect, 'is-greater');
|
||||
await fillIn(valueInput, '2022-02-01');
|
||||
await blur(valueInput);
|
||||
expect(findAll('[data-test-list="members-list-item"]').length, '# of filtered member rows - last seen less than 6 days ago')
|
||||
expect(findAll('[data-test-list="members-list-item"]').length, '# of filtered member rows - is after 2022-02-01')
|
||||
.to.equal(4);
|
||||
|
||||
// can change filter via date picker
|
||||
await fillIn(operatorSelect, 'is-or-greater');
|
||||
await datepickerSelect(valueDatePicker, moment.utc('2022-01-01').toDate());
|
||||
expect(findAll('[data-test-list="members-list-item"]').length, '# of filtered member rows - is after 2022-01-01')
|
||||
.to.equal(7);
|
||||
|
||||
// table shows last seen column+data
|
||||
expect(find('[data-test-table-column="last_seen_at"]')).to.exist;
|
||||
expect(findAll('[data-test-table-data="last_seen_at"]').length).to.equal(4);
|
||||
expect(find('[data-test-table-data="last_seen_at"]')).to.contain.text('5 Feb 2022');
|
||||
expect(find('[data-test-table-data="last_seen_at"]')).to.contain.text('5 days ago');
|
||||
|
||||
await fillIn(valueInput, '11'); // last seen less than 11 days ago
|
||||
await blur(valueInput);
|
||||
expect(findAll('[data-test-list="members-list-item"]').length, '# of filtered member rows - last seen less than 11 days ago')
|
||||
.to.equal(7);
|
||||
|
||||
// can change operator
|
||||
await fillIn(operatorSelector, 'is-greater');
|
||||
expect(findAll('[data-test-list="members-list-item"]').length, '# of filtered member rows - last seen more than 11 days ago')
|
||||
.to.equal(0);
|
||||
|
||||
await fillIn(valueInput, '6'); // last seen more than 6 days ago
|
||||
await blur(valueInput);
|
||||
expect(findAll('[data-test-list="members-list-item"]').length, '# of filtered member rows - last seen more than 6 days ago')
|
||||
.to.equal(3);
|
||||
|
||||
await fillIn(valueInput, '2'); // last seen more than 2 days ago
|
||||
await blur(valueInput);
|
||||
expect(findAll('[data-test-list="members-list-item"]').length, '# of filtered member rows - last seen more than 2 days ago')
|
||||
.to.equal(7);
|
||||
expect(findAll('[data-test-table-data="last_seen_at"]').length).to.equal(7);
|
||||
expect(find('[data-test-table-data="last_seen_at"]')).to.contain.trimmed.text('1 Feb 2022');
|
||||
expect(find('[data-test-table-data="last_seen_at"]')).to.contain.trimmed.text('4 days ago');
|
||||
});
|
||||
|
||||
it('can filter by created at date', async function () {
|
||||
|
Loading…
Reference in New Issue
Block a user