Skip to content

Commit

Permalink
Add AggTypeFieldFilters to filter out fields in vis editor (#20539) (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
jen-huang committed Jul 10, 2018
1 parent 802c624 commit 3413463
Show file tree
Hide file tree
Showing 8 changed files with 258 additions and 23 deletions.
20 changes: 20 additions & 0 deletions src/ui/public/agg_types/param_types/field.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

export type FieldParamType = any;
28 changes: 5 additions & 23 deletions src/ui/public/agg_types/param_types/field.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,15 @@
* under the License.
*/

import _ from 'lodash';

import { sortBy } from 'lodash';
import { SavedObjectNotFound } from '../../errors';
import editorHtml from '../controls/field.html';
import { BaseParamType } from './base';
import '../../filters/field_type';
import { IndexedArray } from '../../indexed_array';
import { toastNotifications } from '../../notify';
import { propFilter } from '../../filters/_prop_filter';
import { createLegacyClass } from '../../utils/legacy_class';
import { aggTypeFieldFilters } from './filter';

export function FieldParamType(config) {
FieldParamType.Super.call(this, config);
Expand Down Expand Up @@ -55,30 +54,13 @@ FieldParamType.prototype.serialize = function (field) {
*/
FieldParamType.prototype.getFieldOptions = function (aggConfig) {
const indexPattern = aggConfig.getIndexPattern();
let fields = indexPattern.fields.raw;

if (this.onlyAggregatable) {
fields = fields.filter(f => f.aggregatable);
}

if (!this.scriptable) {
fields = fields.filter(field => !field.scripted);
}

if (this.filterFieldTypes) {
let filters = this.filterFieldTypes;
if (_.isFunction(this.filterFieldTypes)) {
filters = this.filterFieldTypes.bind(this, aggConfig.vis);
}
fields = propFilter('type')(fields, filters);
fields = _.sortBy(fields, ['type', 'name']);
}

const fields = aggTypeFieldFilters
.filter(indexPattern.fields.raw, this, indexPattern, aggConfig);

return new IndexedArray({
index: ['name'],
group: ['type'],
initialSet: fields
initialSet: sortBy(fields, ['type', 'name']),
});
};

Expand Down
61 changes: 61 additions & 0 deletions src/ui/public/agg_types/param_types/filter/field_filters.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { AggTypeFieldFilters } from './field_filters';

describe('AggTypeFieldFilters', () => {
let registry: AggTypeFieldFilters;
const fieldParamType = {};
const indexPattern = {};
const aggConfig = {};

beforeEach(() => {
registry = new AggTypeFieldFilters();
});

it('should filter nothing without registered filters', async () => {
const fields = [{ name: 'foo' }, { name: 'bar' }];
const filtered = registry.filter(fields, fieldParamType, indexPattern, aggConfig);
expect(filtered).toEqual(fields);
});

it('should pass all fields to the registered filter', async () => {
const fields = [{ name: 'foo' }, { name: 'bar' }];
const filter = jest.fn();
registry.addFilter(filter);
registry.filter(fields, fieldParamType, indexPattern, aggConfig);
expect(filter).toHaveBeenCalledWith(fields[0], fieldParamType, indexPattern, aggConfig);
expect(filter).toHaveBeenCalledWith(fields[1], fieldParamType, indexPattern, aggConfig);
});

it('should allow registered filters to filter out fields', async () => {
const fields = [{ name: 'foo' }, { name: 'bar' }];
let filtered = registry.filter(fields, fieldParamType, indexPattern, aggConfig);
expect(filtered).toEqual(fields);

registry.addFilter(() => true);
registry.addFilter(field => field.name !== 'foo');
filtered = registry.filter(fields, fieldParamType, indexPattern, aggConfig);
expect(filtered).toEqual([fields[1]]);

registry.addFilter(field => field.name !== 'bar');
filtered = registry.filter(fields, fieldParamType, indexPattern, aggConfig);
expect(filtered).toEqual([]);
});
});
75 changes: 75 additions & 0 deletions src/ui/public/agg_types/param_types/filter/field_filters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { FieldParamType } from '../';
import { IndexPattern } from '../../../index_patterns';
import { AggConfig } from '../../../vis';

type AggTypeFieldFilter = (
field: any,
fieldParamType: FieldParamType,
indexPattern: IndexPattern,
aggConfig: AggConfig
) => boolean;

/**
* A registry to store {@link AggTypeFieldFilter} which are used to filter down
* available fields for a specific visualization and {@link AggType}.
*/
class AggTypeFieldFilters {
private filters = new Set<AggTypeFieldFilter>();

/**
* Register a new {@link AggTypeFieldFilter} with this registry.
* This will be used by the {@link #filter|filter method}.
*
* @param filter The filter to register.
*/
public addFilter(filter: AggTypeFieldFilter): void {
this.filters.add(filter);
}

/**
* Returns the {@link any|fields} filtered by all registered filters.
*
* @param fields A list of fields that will be filtered down by this registry.
* @param fieldParamType The fieldParamType for which the returning list will be used.
* @param indexPattern The indexPattern for which the returning list will be used.
* @param aggConfig The aggConfig for which the returning list will be used.
* @return A filtered list of the passed fields.
*/
public filter(
fields: any[],
fieldParamType: FieldParamType,
indexPattern: IndexPattern,
aggConfig: AggConfig
) {
const allFilters = Array.from(this.filters);
const allowedAggTypeFields = fields.filter(field => {
const isAggTypeFieldAllowed = allFilters.every(filter =>
filter(field, fieldParamType, indexPattern, aggConfig)
);
return isAggTypeFieldAllowed;
});
return allowedAggTypeFields;
}
}

const aggTypeFieldFilters = new AggTypeFieldFilters();

export { aggTypeFieldFilters, AggTypeFieldFilters };
20 changes: 20 additions & 0 deletions src/ui/public/agg_types/param_types/filter/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

export { aggTypeFieldFilters } from './field_filters';
20 changes: 20 additions & 0 deletions src/ui/public/agg_types/param_types/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

export { FieldParamType } from './field';
1 change: 1 addition & 0 deletions src/ui/public/vis/editors/default/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import './sidebar';
import './vis_options';
import './vis_editor_resizer';
import './vis_type_agg_filter';
import './vis_type_field_filter';
import $ from 'jquery';

import _ from 'lodash';
Expand Down
56 changes: 56 additions & 0 deletions src/ui/public/vis/editors/default/vis_type_field_filter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { isFunction } from 'lodash';
import { FieldParamType } from '../../../agg_types/param_types';
import { aggTypeFieldFilters } from '../../../agg_types/param_types/filter';
import { IndexPattern } from '../../../index_patterns';
import { AggConfig } from '../../../vis';

import { propFilter } from '../../../filters/_prop_filter';

const filterByType = propFilter('type');

/**
* This filter uses the {@link FieldParamType|fieldParamType} information
* and limits available fields based on that.
*/
aggTypeFieldFilters.addFilter(
(
field: any,
fieldParamType: FieldParamType,
indexPattern: IndexPattern,
aggConfig: AggConfig
) => {
const { onlyAggregatable, scriptable, filterFieldTypes } = fieldParamType;

const filters = isFunction(filterFieldTypes)
? filterFieldTypes.bind(fieldParamType, aggConfig.vis)
: filterFieldTypes;

if ((onlyAggregatable && !field.aggregatable) || (!scriptable && field.scripted)) {
return false;
}

if (!filters) {
return true;
}

return filterByType([field], filters).length !== 0;
}
);

0 comments on commit 3413463

Please sign in to comment.