|
@@ -1,12 +1,13 @@
|
|
|
import React from 'react';
|
|
import React from 'react';
|
|
|
import _ from 'lodash';
|
|
import _ from 'lodash';
|
|
|
|
|
|
|
|
-import Segment from './Segment';
|
|
|
|
|
import { QueryMeta, Target } from '../types';
|
|
import { QueryMeta, Target } from '../types';
|
|
|
-import { FilterSegments } from '../filter_segments';
|
|
|
|
|
|
|
+import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader';
|
|
|
|
|
+import '../query_filter_ctrl';
|
|
|
|
|
|
|
|
export interface Props {
|
|
export interface Props {
|
|
|
- onChange: (metricDescriptor) => void;
|
|
|
|
|
|
|
+ filtersChanged: (filters) => void;
|
|
|
|
|
+ groupBysChanged: (groupBys) => void;
|
|
|
templateSrv: any;
|
|
templateSrv: any;
|
|
|
labelData: QueryMeta;
|
|
labelData: QueryMeta;
|
|
|
loading: Promise<any>;
|
|
loading: Promise<any>;
|
|
@@ -14,226 +15,44 @@ export interface Props {
|
|
|
uiSegmentSrv: any;
|
|
uiSegmentSrv: any;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-interface State {
|
|
|
|
|
- defaultRemoveGroupByValue: string;
|
|
|
|
|
- resourceTypeValue: string;
|
|
|
|
|
- groupBySegments: any[];
|
|
|
|
|
- // filterSegments: FilterSegments;
|
|
|
|
|
- filterSegments: any;
|
|
|
|
|
- removeSegment?: any;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-export class Filter extends React.Component<Props, State> {
|
|
|
|
|
- state: State = {
|
|
|
|
|
- defaultRemoveGroupByValue: '-- remove group by --',
|
|
|
|
|
- resourceTypeValue: 'resource.type',
|
|
|
|
|
- groupBySegments: [],
|
|
|
|
|
- filterSegments: new FilterSegments(this.getFilterKeys.bind(this), this.getFilterValues.bind(this)),
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- constructor(props) {
|
|
|
|
|
- super(props);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- componentDidMount() {
|
|
|
|
|
- this.initSegments(false);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- shouldComponentUpdate(nextProps) {
|
|
|
|
|
- return this.state.filterSegments.filterSegments.length > 0;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- initSegments(hideGroupBys: boolean) {
|
|
|
|
|
- this.state.filterSegments.init(this.props.uiSegmentSrv);
|
|
|
|
|
- if (!hideGroupBys) {
|
|
|
|
|
- this.setState({
|
|
|
|
|
- groupBySegments: this.props.target.aggregation.groupBys.map(groupBy => {
|
|
|
|
|
- return this.props.uiSegmentSrv.getSegmentForValue(groupBy);
|
|
|
|
|
- }),
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- this.ensurePlusButton(this.state.groupBySegments);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- this.setState({
|
|
|
|
|
- removeSegment: this.props.uiSegmentSrv.newSegment({ fake: true, value: '-- remove group by --' }),
|
|
|
|
|
- });
|
|
|
|
|
|
|
+export class Filter extends React.Component<Props, any> {
|
|
|
|
|
+ element: any;
|
|
|
|
|
+ component: AngularComponent;
|
|
|
|
|
|
|
|
- this.state.filterSegments.buildSegmentModel(this.props.target.filters);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- async createLabelKeyElements() {
|
|
|
|
|
- await this.props.loading;
|
|
|
|
|
-
|
|
|
|
|
- let elements = Object.keys(this.props.labelData.metricLabels || {}).map(l => {
|
|
|
|
|
- return this.props.uiSegmentSrv.newSegment({
|
|
|
|
|
- value: `metric.label.${l}`,
|
|
|
|
|
- expandable: false,
|
|
|
|
|
- });
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- elements = [
|
|
|
|
|
- ...elements,
|
|
|
|
|
- ...Object.keys(this.props.labelData.resourceLabels || {}).map(l => {
|
|
|
|
|
- return this.props.uiSegmentSrv.newSegment({
|
|
|
|
|
- value: `resource.label.${l}`,
|
|
|
|
|
- expandable: false,
|
|
|
|
|
- });
|
|
|
|
|
- }),
|
|
|
|
|
- ];
|
|
|
|
|
-
|
|
|
|
|
- if (this.props.labelData.resourceTypes && this.props.labelData.resourceTypes.length > 0) {
|
|
|
|
|
- elements = [
|
|
|
|
|
- ...elements,
|
|
|
|
|
- this.props.uiSegmentSrv.newSegment({
|
|
|
|
|
- value: this.state.resourceTypeValue,
|
|
|
|
|
- expandable: false,
|
|
|
|
|
- }),
|
|
|
|
|
- ];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return elements;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- async getFilterKeys(segment, removeText?: string) {
|
|
|
|
|
- let elements = await this.createLabelKeyElements();
|
|
|
|
|
-
|
|
|
|
|
- if (this.props.target.filters.indexOf(this.state.resourceTypeValue) !== -1) {
|
|
|
|
|
- elements = elements.filter(e => e.value !== this.state.resourceTypeValue);
|
|
|
|
|
|
|
+ async componentDidMount() {
|
|
|
|
|
+ if (!this.element) {
|
|
|
|
|
+ return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const noValueOrPlusButton = !segment || segment.type === 'plus-button';
|
|
|
|
|
- if (noValueOrPlusButton && elements.length === 0) {
|
|
|
|
|
- return [];
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ const { loading, labelData, target, filtersChanged, groupBysChanged } = this.props;
|
|
|
|
|
+ const loader = getAngularLoader();
|
|
|
|
|
+ const template = '<stackdriver-filter> </stackdriver-filter>';
|
|
|
|
|
|
|
|
- return [
|
|
|
|
|
- ...elements,
|
|
|
|
|
- this.props.uiSegmentSrv.newSegment({ fake: true, value: removeText || this.state.defaultRemoveGroupByValue }),
|
|
|
|
|
- ];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- async getGroupBys(segment) {
|
|
|
|
|
- let elements = await this.createLabelKeyElements();
|
|
|
|
|
-
|
|
|
|
|
- elements = elements.filter(e => this.props.target.aggregation.groupBys.indexOf(e.value) === -1);
|
|
|
|
|
- const noValueOrPlusButton = !segment || segment.type === 'plus-button';
|
|
|
|
|
- if (noValueOrPlusButton && elements.length === 0) {
|
|
|
|
|
- return [];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- this.state.removeSegment.value = this.state.defaultRemoveGroupByValue;
|
|
|
|
|
- return [...elements, this.state.removeSegment];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- groupByChanged(segment, index) {
|
|
|
|
|
- if (segment.value === this.state.removeSegment.value) {
|
|
|
|
|
- // this.groupBySegments.splice(index, 1);
|
|
|
|
|
- } else {
|
|
|
|
|
- segment.type = 'value';
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const reducer = (memo, seg) => {
|
|
|
|
|
- if (!seg.fake) {
|
|
|
|
|
- memo.push(seg.value);
|
|
|
|
|
- }
|
|
|
|
|
- return memo;
|
|
|
|
|
|
|
+ const scopeProps = {
|
|
|
|
|
+ loading,
|
|
|
|
|
+ labelData,
|
|
|
|
|
+ target,
|
|
|
|
|
+ filtersChanged,
|
|
|
|
|
+ groupBysChanged,
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- this.props.target.aggregation.groupBys = this.state.groupBySegments.reduce(reducer, []);
|
|
|
|
|
- this.ensurePlusButton(this.state.groupBySegments);
|
|
|
|
|
- // this.$rootScope.$broadcast('metricTypeChanged');
|
|
|
|
|
- // this.$scope.refresh();
|
|
|
|
|
|
|
+ this.component = loader.load(this.element, scopeProps, template);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- async getFilters(segment, index) {
|
|
|
|
|
- await this.props.loading;
|
|
|
|
|
- const hasNoFilterKeys =
|
|
|
|
|
- this.props.labelData.metricLabels && Object.keys(this.props.labelData.metricLabels).length === 0;
|
|
|
|
|
- return this.state.filterSegments.getFilters(segment, index, hasNoFilterKeys);
|
|
|
|
|
|
|
+ componentDidUpdate() {
|
|
|
|
|
+ const scope = this.component.getScope();
|
|
|
|
|
+ scope.loading = _.clone(this.props.loading);
|
|
|
|
|
+ scope.labelData = _.cloneDeep(this.props.labelData);
|
|
|
|
|
+ scope.target = _.cloneDeep(this.props.target);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- getFilterValues(index) {
|
|
|
|
|
- const filterKey = this.props.templateSrv.replace(this.state.filterSegments.filterSegments[index - 2].value);
|
|
|
|
|
- if (
|
|
|
|
|
- !filterKey ||
|
|
|
|
|
- !this.props.labelData.metricLabels ||
|
|
|
|
|
- Object.keys(this.props.labelData.metricLabels).length === 0
|
|
|
|
|
- ) {
|
|
|
|
|
- return [];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const shortKey = filterKey.substring(filterKey.indexOf('.label.') + 7);
|
|
|
|
|
-
|
|
|
|
|
- if (filterKey.startsWith('metric.label.') && this.props.labelData.metricLabels.hasOwnProperty(shortKey)) {
|
|
|
|
|
- return this.props.labelData.metricLabels[shortKey];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (filterKey.startsWith('resource.label.') && this.props.labelData.resourceLabels.hasOwnProperty(shortKey)) {
|
|
|
|
|
- return this.props.labelData.resourceLabels[shortKey];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (filterKey === this.state.resourceTypeValue) {
|
|
|
|
|
- return this.props.labelData.resourceTypes;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return [];
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- filterSegmentUpdated(segment, index) {
|
|
|
|
|
- this.props.target.filters = this.state.filterSegments.filterSegmentUpdated(segment, index);
|
|
|
|
|
- // this.$scope.refresh();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- ensurePlusButton(segments) {
|
|
|
|
|
- const count = segments.length;
|
|
|
|
|
- const lastSegment = segments[Math.max(count - 1, 0)];
|
|
|
|
|
-
|
|
|
|
|
- if (!lastSegment || lastSegment.type !== 'plus-button') {
|
|
|
|
|
- segments.push(this.props.uiSegmentSrv.newPlusButton());
|
|
|
|
|
|
|
+ componentWillUnmount() {
|
|
|
|
|
+ if (this.component) {
|
|
|
|
|
+ this.component.destroy();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
render() {
|
|
|
- const { filterSegments } = this.state;
|
|
|
|
|
- // const { metrifilterSegmentscType } = this.props;
|
|
|
|
|
-
|
|
|
|
|
- return (
|
|
|
|
|
- <React.Fragment>
|
|
|
|
|
- <div className="gf-form-inline">
|
|
|
|
|
- <div className="gf-form">
|
|
|
|
|
- <span className="gf-form-label query-keyword width-9">Filter</span>
|
|
|
|
|
- <div className="gf-form">
|
|
|
|
|
- {filterSegments.filterSegments.map((segment, i) => (
|
|
|
|
|
- <Segment
|
|
|
|
|
- key={i}
|
|
|
|
|
- segment={segment}
|
|
|
|
|
- getOptions={() => this.getFilters(segment, i)}
|
|
|
|
|
- onChange={segment => this.filterSegmentUpdated(segment, i)}
|
|
|
|
|
- />
|
|
|
|
|
- ))}
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div className="gf-form gf-form--grow">
|
|
|
|
|
- <div className="gf-form-label gf-form-label--grow" />
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- {/* <div className="gf-form-inline" ng-hide="ctrl.$scope.hideGroupBys">
|
|
|
|
|
- <div className="gf-form">
|
|
|
|
|
- <span className="gf-form-label query-keyword width-9">Group By</span>
|
|
|
|
|
- <div className="gf-form" ng-repeat="segment in ctrl.groupBySegments">
|
|
|
|
|
- <Segment
|
|
|
|
|
- segment="segment"
|
|
|
|
|
- get-options="ctrl.getGroupBys(segment)"
|
|
|
|
|
- on-change="ctrl.groupByChanged(segment, $index)"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div className="gf-form gf-form--grow">
|
|
|
|
|
- <div className="gf-form-label gf-form-label--grow" />
|
|
|
|
|
- </div>
|
|
|
|
|
- </div> */}
|
|
|
|
|
- </React.Fragment>
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ return <div ref={element => (this.element = element)} style={{ width: '100%' }} />;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|