Skip to content

Commit

Permalink
Date histogram brush - add range filter when field is not index patte…
Browse files Browse the repository at this point in the history
…rn time field. (#12286)

* create range filter for brush event when xaxis field is not index pattern timefield

* remove switch statement

* move logic to functions

* convert Dates to milliseconds

* add format:epoch_millis to date range filter
  • Loading branch information
nreese authored Jun 29, 2017
1 parent fce318b commit b6e9628
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 70 deletions.
124 changes: 91 additions & 33 deletions src/ui/public/utils/__tests__/brush_event.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logsta
import { UtilsBrushEventProvider } from 'ui/utils/brush_event';

describe('brushEvent', function () {
const DAY_IN_MS = 24 * 60 * 60 * 1000;
const JAN_01_2014 = 1388559600000;
let brushEventFn;
let timefilter;

Expand Down Expand Up @@ -51,42 +53,97 @@ describe('brushEvent', function () {
.not.have.property('$newFilters');
});

describe('handles an event when the x-axis field is a date', function () {
let dateEvent;
const dateField = {
name: 'dateField',
type: 'date'
};

beforeEach(ngMock.inject(function () {
dateEvent = _.cloneDeep(baseEvent);
dateEvent.data.xAxisField = dateField;
}));
describe('handles an event when the x-axis field is a date field', function () {
describe('date field is index pattern timefield', function () {
let dateEvent;
const dateField = {
name: 'time',
type: 'date'
};

beforeEach(ngMock.inject(function () {
dateEvent = _.cloneDeep(baseEvent);
dateEvent.data.xAxisField = dateField;
}));

it('by ignoring the event when range spans zero time', function () {
const event = _.cloneDeep(dateEvent);
event.range = [JAN_01_2014, JAN_01_2014];
brushEvent(event);
expect($state)
.not.have.property('$newFilters');
});

it('by ignoring the event when range spans zero time', function () {
const event = _.cloneDeep(dateEvent);
event.range = [1388559600000, 1388559600000];
brushEvent(event);
expect($state)
.not.have.property('$newFilters');
it('by updating the timefilter', function () {
const event = _.cloneDeep(dateEvent);
event.range = [JAN_01_2014, JAN_01_2014 + DAY_IN_MS];
brushEvent(event);
expect(timefilter.time.mode).to.be('absolute');
expect(moment.isMoment(timefilter.time.from))
.to.be(true);
// Set to a baseline timezone for comparison.
expect(timefilter.time.from.utcOffset(0).format('YYYY-MM-DD'))
.to.equal('2014-01-01');
expect(moment.isMoment(timefilter.time.to))
.to.be(true);
// Set to a baseline timezone for comparison.
expect(timefilter.time.to.utcOffset(0).format('YYYY-MM-DD'))
.to.equal('2014-01-02');
});
});

it('by updating the timefilter', function () {
const event = _.cloneDeep(dateEvent);
const DAY_IN_MS = 24 * 60 * 60 * 1000;
event.range = [1388559600000, 1388559600000 + DAY_IN_MS];
brushEvent(event);
expect(timefilter.time.mode).to.be('absolute');
expect(moment.isMoment(timefilter.time.from))
.to.be(true);
// Set to a baseline timezone for comparison.
expect(timefilter.time.from.utcOffset(0).format('YYYY-MM-DD'))
.to.equal('2014-01-01');
expect(moment.isMoment(timefilter.time.to))
.to.be(true);
// Set to a baseline timezone for comparison.
expect(timefilter.time.to.utcOffset(0).format('YYYY-MM-DD'))
.to.equal('2014-01-02');
describe('date field is not index pattern timefield', function () {
let dateEvent;
const dateField = {
name: 'anotherTimeField',
type: 'date'
};

beforeEach(ngMock.inject(function () {
dateEvent = _.cloneDeep(baseEvent);
dateEvent.data.xAxisField = dateField;
}));

it('creates a new range filter', function () {
const event = _.cloneDeep(dateEvent);
const rangeBegin = JAN_01_2014;
const rangeEnd = rangeBegin + DAY_IN_MS;
event.range = [rangeBegin, rangeEnd];
brushEvent(event);
expect($state)
.to.have.property('$newFilters');
expect($state.filters.length)
.to.equal(0);
expect($state.$newFilters.length)
.to.equal(1);
expect($state.$newFilters[0].range.anotherTimeField.gte)
.to.equal(rangeBegin);
expect($state.$newFilters[0].range.anotherTimeField.lt)
.to.equal(rangeEnd);
expect($state.$newFilters[0].range.anotherTimeField).to.have.property('format');
expect($state.$newFilters[0].range.anotherTimeField.format)
.to.equal('epoch_millis');
});

it('converts Date fields to milliseconds', function () {
const event = _.cloneDeep(dateEvent);
const rangeBeginMs = JAN_01_2014;
const rangeEndMs = rangeBeginMs + DAY_IN_MS;
const rangeBegin = new Date(rangeBeginMs);
const rangeEnd = new Date(rangeEndMs);
event.range = [rangeBegin, rangeEnd];
brushEvent(event);
expect($state)
.to.have.property('$newFilters');
expect($state.filters.length)
.to.equal(0);
expect($state.$newFilters.length)
.to.equal(1);
expect($state.$newFilters[0].range.anotherTimeField.gte)
.to.equal(rangeBeginMs);
expect($state.$newFilters[0].range.anotherTimeField.lt)
.to.equal(rangeEndMs);
});
});
});

Expand Down Expand Up @@ -124,6 +181,7 @@ describe('brushEvent', function () {
.to.equal(1);
expect($state.$newFilters[0].range.numberField.lt)
.to.equal(4);
expect($state.$newFilters[0].range.numberField).not.to.have.property('format');
});

it('by updating the existing range filter', function () {
Expand Down
95 changes: 58 additions & 37 deletions src/ui/public/utils/brush_event.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,43 +9,64 @@ export function UtilsBrushEventProvider(timefilter) {
return;
}

switch (event.data.xAxisField.type) {
case 'date':
const from = moment(event.range[0]);
const to = moment(event.range[1]);

if (to - from === 0) return;

timefilter.time.from = from;
timefilter.time.to = to;
timefilter.time.mode = 'absolute';
break;

case 'number':
if (event.range.length <= 1) return;

const existingFilter = $state.filters.find(filter => (
filter.meta && filter.meta.key === event.data.xAxisField.name
));

const min = event.range[0];
const max = event.range[event.range.length - 1];
const range = { gte: min, lt: max };
if (_.has(existingFilter, 'range')) {
existingFilter.range[event.data.xAxisField.name] = range;
} else if (_.has(existingFilter, 'script.script.params.gte')
&& _.has(existingFilter, 'script.script.params.lt')) {
existingFilter.script.script.params.gte = min;
existingFilter.script.script.params.lt = max;
} else {
const newFilter = buildRangeFilter(
event.data.xAxisField,
range,
event.data.indexPattern,
event.data.xAxisFormatter);
$state.$newFilters = [newFilter];
}
break;
const isDate = event.data.xAxisField.type === 'date';
const isNumber = event.data.xAxisField.type === 'number';

if (isDate &&
event.data.xAxisField.name === event.data.indexPattern.timeFieldName) {
setTimefilter();
} else if (isDate || isNumber) {
setRange();
}

function setTimefilter() {
const from = moment(event.range[0]);
const to = moment(event.range[1]);

if (to - from === 0) return;

timefilter.time.from = from;
timefilter.time.to = to;
timefilter.time.mode = 'absolute';
}

function setRange() {
if (event.range.length <= 1) return;

const existingFilter = $state.filters.find(filter => (
filter.meta && filter.meta.key === event.data.xAxisField.name
));

const min = event.range[0];
const max = event.range[event.range.length - 1];
let range;
if (isDate) {
range = {
gte: moment(min).valueOf(),
lt: moment(max).valueOf(),
format: 'epoch_millis'
};
} else {
range = {
gte: min,
lt: max
};
}

if (_.has(existingFilter, 'range')) {
existingFilter.range[event.data.xAxisField.name] = range;
} else if (_.has(existingFilter, 'script.script.params.gte')
&& _.has(existingFilter, 'script.script.params.lt')) {
existingFilter.script.script.params.gte = min;
existingFilter.script.script.params.lt = max;
} else {
const newFilter = buildRangeFilter(
event.data.xAxisField,
range,
event.data.indexPattern,
event.data.xAxisFormatter);
$state.$newFilters = [newFilter];
}
}
};
};
Expand Down

0 comments on commit b6e9628

Please sign in to comment.