Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Vis: Default editor] EUIficate time interval control #34991

Merged
merged 37 commits into from
May 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
b822888
EUIficate time interval control
maryia-lapata Apr 12, 2019
db04376
Merge branch 'master' into vis-editor/time-interval
maryia-lapata Apr 15, 2019
9d20af2
Update tests
maryia-lapata Apr 15, 2019
4f397f6
Remove empty option, update fix tests
maryia-lapata Apr 15, 2019
7911aa8
Bind vis to scope for react component only
maryia-lapata Apr 15, 2019
fd642b0
Merge branch 'master' into vis-editor/time-interval
maryia-lapata Apr 16, 2019
32604d0
Merge branch 'master' into vis-editor/time-interval
maryia-lapata Apr 17, 2019
735542e
Combine two interval inputs into one EuiCombobox
maryia-lapata Apr 18, 2019
7b794c3
Merge branch 'master' into vis-editor/time-interval
maryia-lapata Apr 22, 2019
e42d471
Add error message
maryia-lapata Apr 22, 2019
5d0d388
Add migration script; remove unused translations
maryia-lapata Apr 22, 2019
6f32466
Update fuctional tests
maryia-lapata Apr 22, 2019
62d52c6
Update unit test
maryia-lapata Apr 22, 2019
deebd42
Update tests; refactoring
maryia-lapata Apr 23, 2019
c8d0d02
Use flow to invoke several functions
maryia-lapata Apr 23, 2019
f2c4d56
Update test
maryia-lapata Apr 23, 2019
e772718
Refactoring
maryia-lapata Apr 23, 2019
70c4844
Reset options when timeBase
maryia-lapata Apr 23, 2019
9d3340c
Add type for editorConfig prop
maryia-lapata Apr 23, 2019
57fe4b5
Merge branch 'master' into vis-editor/time-interval
maryia-lapata Apr 23, 2019
2c803f5
Merge branch 'master' into vis-editor/time-interval
maryia-lapata Apr 24, 2019
9d24249
Add placeholder
maryia-lapata Apr 24, 2019
ab8fb50
Fix lint errors
maryia-lapata Apr 24, 2019
ffa9172
Call write after interval changing
maryia-lapata Apr 24, 2019
cfa1205
Merge branch 'master' into vis-editor/time-interval
maryia-lapata Apr 25, 2019
224634e
Merge branch 'master' into vis-editor/time-interval
maryia-lapata Apr 29, 2019
0b67d5f
Fix code review comments
maryia-lapata Apr 29, 2019
43aaaed
Make replace for model name global
maryia-lapata Apr 29, 2019
030b036
Revert error catch
maryia-lapata Apr 29, 2019
5571977
Merge branch 'master' into vis-editor/time-interval
maryia-lapata Apr 29, 2019
5f77403
Remove old dependency
maryia-lapata Apr 29, 2019
17f7bde
Add unit test for migration test
maryia-lapata Apr 29, 2019
f986a9c
Merge branch 'master' into vis-editor/time-interval
maryia-lapata Apr 30, 2019
155af1d
Fix message
maryia-lapata Apr 30, 2019
5542184
Fix code review comments
maryia-lapata Apr 30, 2019
aaf9e05
Merge branch 'master' into vis-editor/time-interval
maryia-lapata May 1, 2019
f531484
Update functional test
maryia-lapata May 1, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 81 additions & 39 deletions src/legacy/core_plugins/kibana/migrations.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* under the License.
*/

import { cloneDeep, get, omit, has } from 'lodash';
import { cloneDeep, get, omit, has, flow } from 'lodash';

function migrateIndexPattern(doc) {
const searchSourceJSON = get(doc, 'attributes.kibanaSavedObjectMeta.searchSourceJSON');
Expand Down Expand Up @@ -57,6 +57,85 @@ function migrateIndexPattern(doc) {
doc.attributes.kibanaSavedObjectMeta.searchSourceJSON = JSON.stringify(searchSource);
}

// [TSVB] Migrate percentile-rank aggregation (value -> values)
const migratePercentileRankAggregation = doc => {
const visStateJSON = get(doc, 'attributes.visState');
let visState;

if (visStateJSON) {
try {
visState = JSON.parse(visStateJSON);
} catch (e) {
// Let it go, the data is invalid and we'll leave it as is
}
if (visState && visState.type === 'metrics') {
const series = get(visState, 'params.series') || [];

series.forEach(part => {
(part.metrics || []).forEach(metric => {
if (metric.type === 'percentile_rank' && has(metric, 'value')) {
metric.values = [metric.value];

delete metric.value;
}
});
});
return {
...doc,
attributes: {
...doc.attributes,
visState: JSON.stringify(visState),
},
};
}
}
return doc;
};

// Migrate date histogram aggregation (remove customInterval)
const migrateDateHistogramAggregation = doc => {
const visStateJSON = get(doc, 'attributes.visState');
let visState;

if (visStateJSON) {
try {
visState = JSON.parse(visStateJSON);
} catch (e) {
// Let it go, the data is invalid and we'll leave it as is
}

if (visState && visState.aggs) {
visState.aggs.forEach(agg => {
if (agg.type === 'date_histogram' && agg.params) {
if (agg.params.interval === 'custom') {
agg.params.interval = agg.params.customInterval;
}
delete agg.params.customInterval;
}

if (get(agg, 'params.customBucket.type', null) === 'date_histogram'
&& agg.params.customBucket.params
) {
if (agg.params.customBucket.params.interval === 'custom') {
agg.params.customBucket.params.interval = agg.params.customBucket.params.customInterval;
}
delete agg.params.customBucket.params.customInterval;
}
});
return {
...doc,
attributes: {
...doc.attributes,
visState: JSON.stringify(visState),
}
};
}
}
return doc;
};

const executeMigrations710 = flow(migratePercentileRankAggregation, migrateDateHistogramAggregation);

function removeDateHistogramTimeZones(doc) {
const visStateJSON = get(doc, 'attributes.visState');
if (visStateJSON) {
Expand Down Expand Up @@ -185,44 +264,7 @@ export const migrations = {
}
},
'7.0.1': removeDateHistogramTimeZones,
'7.1.0': doc => {
// [TSVB] Migrate percentile-rank aggregation (value -> values)
const migratePercentileRankAggregation = doc => {
const visStateJSON = get(doc, 'attributes.visState');
let visState;

if (visStateJSON) {
try {
visState = JSON.parse(visStateJSON);
} catch (e) {
// Let it go, the data is invalid and we'll leave it as is
}
if (visState && visState.type === 'metrics') {
const series = get(visState, 'params.series') || [];

series.forEach(part => {
(part.metrics || []).forEach(metric => {
if (metric.type === 'percentile_rank' && has(metric, 'value')) {
metric.values = [metric.value];

delete metric.value;
}
});
});
return {
...doc,
attributes: {
...doc.attributes,
visState: JSON.stringify(visState),
},
};
}
}
return doc;
};

return migratePercentileRankAggregation(doc);
}
'7.1.0': doc => executeMigrations710(doc)
},
dashboard: {
'7.0.0': (doc) => {
Expand Down
127 changes: 127 additions & 0 deletions src/legacy/core_plugins/kibana/migrations.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,133 @@ Object {
expect(() => migrate(doc)).toThrowError(/My Vis/);
});
});

describe('date histogram custom interval removal', () => {
const migrate = doc => migrations.visualization['7.1.0'](doc);
let doc;
beforeEach(() => {
doc = {
attributes: {
visState: JSON.stringify({
aggs: [
{
'enabled': true,
'id': '1',
'params': {
'customInterval': '1h'
},
'schema': 'metric',
'type': 'count'
},
{
'enabled': true,
'id': '2',
'params': {
'customInterval': '2h',
'drop_partials': false,
'extended_bounds': {},
'field': 'timestamp',
'interval': 'auto',
'min_doc_count': 1,
'useNormalizedEsInterval': true
},
'schema': 'segment',
'type': 'date_histogram'
},
{
'enabled': true,
'id': '4',
'params': {
'customInterval': '2h',
'drop_partials': false,
'extended_bounds': {},
'field': 'timestamp',
'interval': 'custom',
'min_doc_count': 1,
'useNormalizedEsInterval': true
},
'schema': 'segment',
'type': 'date_histogram'
},
{
'enabled': true,
'id': '3',
'params': {
'customBucket': {
'enabled': true,
'id': '1-bucket',
'params': {
'customInterval': '2h',
'drop_partials': false,
'extended_bounds': {},
'field': 'timestamp',
'interval': 'custom',
'min_doc_count': 1,
'useNormalizedEsInterval': true
},
'type': 'date_histogram'
},
'customMetric': {
'enabled': true,
'id': '1-metric',
'params': {},
'type': 'count'
}
},
'schema': 'metric',
'type': 'max_bucket'
},
]
}),
}
};
});

it('should remove customInterval from date_histogram aggregations', () => {
const migratedDoc = migrate(doc);
const aggs = JSON.parse(migratedDoc.attributes.visState).aggs;
expect(aggs[1]).not.toHaveProperty('params.customInterval');
});

it('should not change interval from date_histogram aggregations', () => {
const migratedDoc = migrate(doc);
const aggs = JSON.parse(migratedDoc.attributes.visState).aggs;
expect(aggs[1].params.interval).toBe(JSON.parse(doc.attributes.visState).aggs[1].params.interval);
});

it('should not remove customInterval from non date_histogram aggregations', () => {
const migratedDoc = migrate(doc);
const aggs = JSON.parse(migratedDoc.attributes.visState).aggs;
expect(aggs[0]).toHaveProperty('params.customInterval');
});

it('should set interval with customInterval value and remove customInterval when interval equals "custom"', () => {
const migratedDoc = migrate(doc);
const aggs = JSON.parse(migratedDoc.attributes.visState).aggs;
expect(aggs[2].params.interval).toBe(JSON.parse(doc.attributes.visState).aggs[2].params.customInterval);
expect(aggs[2]).not.toHaveProperty('params.customInterval');
});

it('should remove customInterval from nested aggregations', () => {
const migratedDoc = migrate(doc);
const aggs = JSON.parse(migratedDoc.attributes.visState).aggs;
expect(aggs[3]).not.toHaveProperty('params.customBucket.params.customInterval');
});

it('should remove customInterval from nested aggregations and set interval with customInterval value', () => {
const migratedDoc = migrate(doc);
const aggs = JSON.parse(migratedDoc.attributes.visState).aggs;
expect(aggs[3].params.customBucket.params.interval)
.toBe(JSON.parse(doc.attributes.visState).aggs[3].params.customBucket.params.customInterval);
expect(aggs[3]).not.toHaveProperty('params.customBucket.params.customInterval');
});

it('should not fail on date histograms without a customInterval', () => {
const migratedDoc = migrate(doc);
const aggs = JSON.parse(migratedDoc.attributes.visState).aggs;
expect(aggs[3]).not.toHaveProperty('params.customInterval');
});
});
});

describe('dashboard', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ describe('editor', function () {
beforeEach(ngMock.inject(function () {
field = _.sample(indexPattern.fields);
interval = _.sample(intervalOptions);
params = render({ field: field, interval: interval });
params = render({ field: field, interval: interval.val });
}));

it('renders the field editor', function () {
Expand All @@ -112,11 +112,11 @@ describe('editor', function () {
});

it('renders the interval editor', function () {
expect(agg.params.interval).to.be(interval);
expect(agg.params.interval).to.be(interval.val);

expect(params).to.have.property('interval');
expect(params.interval).to.have.property('$el');
expect(params.interval.modelValue()).to.be(interval);
expect($scope.agg.params.interval).to.be(interval.val);
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,8 @@ describe('date_histogram params', function () {
expect(output.params).to.have.property('interval', '1d');
});

it('ignores invalid intervals', function () {
const output = writeInterval('foo');
expect(output.params).to.have.property('interval', '0ms');
it('throws error when interval is invalid', function () {
expect(() => writeInterval('foo')).to.throw('TypeError: "foo" is not a valid interval.');
});

it('automatically picks an interval', function () {
Expand Down
9 changes: 8 additions & 1 deletion src/legacy/ui/public/agg_types/agg_param.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,17 @@ import { AggConfig } from '../vis';
interface AggParam {
type: string;
name: string;
options?: AggParamOption[];
required?: boolean;
displayName?: string;
onChange?(agg: AggConfig): void;
shouldShow?(agg: AggConfig): boolean;
}

export { AggParam };
interface AggParamOption {
val: string;
display: string;
enabled?(agg: AggConfig): void;
}

export { AggParam, AggParamOption };
6 changes: 0 additions & 6 deletions src/legacy/ui/public/agg_types/buckets/_interval_options.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,5 @@ export const intervalOptions = [
defaultMessage: 'Yearly',
}),
val: 'y'
},
{
display: i18n.translate('common.ui.aggTypes.buckets.intervalOptions.customDisplayName', {
defaultMessage: 'Custom',
}),
val: 'custom'
}
];
Loading