[maps] pass dataFilters to ISource.getImmutableProperties (#159255)

https://github.com/elastic/kibana/pull/159161 is adding adding hyperlink
to anomaly explorer for job from anomaly layer in maps. A requirement
from this request is to be able to include timerange and query state in
the hyperlink. This PR updates ISource.getImmutableProperties to take
dataFilters parameter so hyperlink can be updated with latest query
state.

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Nathan Reese 2023-06-08 09:26:21 -06:00 committed by GitHub
parent afdf3f64fd
commit 43767044cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 103 additions and 97 deletions

View file

@ -33,7 +33,7 @@ import {
Timeslice,
StyleMetaDescriptor,
} from '../../../common/descriptor_types';
import { ImmutableSourceProperty, ISource, SourceEditorArgs } from '../sources/source';
import { ISource, SourceEditorArgs } from '../sources/source';
import { DataRequestContext } from '../../actions';
import { IStyle } from '../styles/style';
import { LICENSED_FEATURES } from '../../licensed_features';
@ -66,7 +66,6 @@ export interface ILayer {
getStyle(): IStyle;
getStyleForEditing(): IStyle;
getCurrentStyle(): IStyle;
getImmutableSourceProperties(): Promise<ImmutableSourceProperty[]>;
renderSourceSettingsEditor(sourceEditorArgs: SourceEditorArgs): ReactElement<any> | null;
isLayerLoading(): boolean;
isFilteredByGlobalTime(): Promise<boolean>;
@ -338,11 +337,6 @@ export class AbstractLayer implements ILayer {
return this._descriptor.query ? this._descriptor.query : null;
}
async getImmutableSourceProperties(): Promise<ImmutableSourceProperty[]> {
const source = this.getSource();
return await source.getImmutableProperties();
}
renderSourceSettingsEditor(sourceEditorArgs: SourceEditorArgs) {
return this.getSourceForEditing().renderSourceSettingsEditor(sourceEditorArgs);
}

View file

@ -25,7 +25,7 @@ import {
StyleDescriptor,
StyleMetaDescriptor,
} from '../../../../common/descriptor_types';
import { ImmutableSourceProperty, ISource, SourceEditorArgs } from '../../sources/source';
import { ISource, SourceEditorArgs } from '../../sources/source';
import { type DataRequestContext } from '../../../actions';
import { getLayersExtent } from '../../../actions/get_layers_extent';
import { ILayer, LayerIcon } from '../layer';
@ -263,10 +263,6 @@ export class LayerGroup implements ILayer {
return null;
}
async getImmutableSourceProperties(): Promise<ImmutableSourceProperty[]> {
return [];
}
renderSourceSettingsEditor(sourceEditorArgs: SourceEditorArgs) {
return null;
}

View file

@ -77,7 +77,7 @@ describe('getTooltipProperties', () => {
});
});
describe('getImmutableSourceProperties', () => {
describe('getImmutableProperties', () => {
it('should only show immutable props', async () => {
const source = new MVTSingleLayerVectorSource(descriptor);
const properties = await source.getImmutableProperties();

View file

@ -14,6 +14,7 @@ import { FieldFormatter, LAYER_TYPE, MAX_ZOOM, MIN_ZOOM } from '../../../common/
import {
AbstractSourceDescriptor,
Attribution,
DataFilters,
DataRequestMeta,
StyleDescriptor,
Timeslice,
@ -49,7 +50,7 @@ export interface ISource {
isFilterByMapBounds(): boolean;
isQueryAware(): boolean;
isTimeAware(): Promise<boolean>;
getImmutableProperties(): Promise<ImmutableSourceProperty[]>;
getImmutableProperties(dataFilters: DataFilters): Promise<ImmutableSourceProperty[]>;
getAttributionProvider(): (() => Promise<Attribution[]>) | null;
isESSource(): boolean;
renderSourceSettingsEditor(sourceEditorArgs: SourceEditorArgs): ReactElement<any> | null;

View file

@ -49,35 +49,13 @@ exports[`EditLayerPanel is rendered 1`] = `
<EuiSpacer
size="xs"
/>
<div
className="mapLayerPanel__sourceDetails"
>
<EuiAccordionClass
buttonContent="Source details"
id="accordion1"
>
<EuiText
color="subdued"
size="s"
>
<EuiSpacer
size="xs"
/>
<p
className="mapLayerPanel__sourceDetail"
key="source prop1"
>
<strong>
source prop1
</strong>
<span>
you get one chance to set me
</span>
</p>
</EuiText>
</EuiAccordionClass>
</div>
<Connect(SourceDetails)
source={
Object {
"supportsJoins": [Function],
}
}
/>
</EuiFlyoutHeader>
<div
className="mapLayerPanel__body"
@ -92,7 +70,6 @@ exports[`EditLayerPanel is rendered 1`] = `
"getDescriptor": [Function],
"getDisplayName": [Function],
"getId": [Function],
"getImmutableSourceProperties": [Function],
"getLayerTypeIconName": [Function],
"getSource": [Function],
"getStyleForEditing": [Function],
@ -117,7 +94,6 @@ exports[`EditLayerPanel is rendered 1`] = `
"getDescriptor": [Function],
"getDisplayName": [Function],
"getId": [Function],
"getImmutableSourceProperties": [Function],
"getLayerTypeIconName": [Function],
"getSource": [Function],
"getStyleForEditing": [Function],

View file

@ -62,9 +62,6 @@ const mockLayer = {
getDisplayName: () => {
return 'layer 1';
},
getImmutableSourceProperties: () => {
return [{ label: 'source prop1', value: 'you get one chance to set me' }];
},
canShowTooltip: () => {
return true;
},

View file

@ -17,9 +17,6 @@ import {
EuiFlyoutHeader,
EuiFlyoutFooter,
EuiSpacer,
EuiAccordion,
EuiText,
EuiLink,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
@ -33,10 +30,11 @@ import { StyleDescriptor, VectorLayerDescriptor } from '../../../common/descript
import { getData, getCore } from '../../kibana_services';
import { ILayer } from '../../classes/layers/layer';
import { isVectorLayer, IVectorLayer } from '../../classes/layers/vector_layer';
import { ImmutableSourceProperty, OnSourceChangeArgs } from '../../classes/sources/source';
import { OnSourceChangeArgs } from '../../classes/sources/source';
import { IField } from '../../classes/fields/field';
import { isLayerGroup } from '../../classes/layers/layer_group';
import { isSpatialJoin } from '../../classes/joins/is_spatial_join';
import { SourceDetails } from './source_details';
const localStorage = new Storage(window.localStorage);
@ -48,7 +46,6 @@ export interface Props {
interface State {
displayName: string;
immutableSourceProps: ImmutableSourceProperty[];
leftJoinFields: JoinField[];
supportsFitToBounds: boolean;
}
@ -57,7 +54,6 @@ export class EditLayerPanel extends Component<Props, State> {
private _isMounted = false;
state: State = {
displayName: '',
immutableSourceProps: [],
leftJoinFields: [],
supportsFitToBounds: false,
};
@ -65,7 +61,6 @@ export class EditLayerPanel extends Component<Props, State> {
componentDidMount() {
this._isMounted = true;
this._loadDisplayName();
this._loadImmutableSourceProperties();
this._loadLeftJoinFields();
this._loadSupportsFitToBounds();
}
@ -96,17 +91,6 @@ export class EditLayerPanel extends Component<Props, State> {
}
};
_loadImmutableSourceProperties = async () => {
if (!this.props.selectedLayer || isLayerGroup(this.props.selectedLayer)) {
return;
}
const immutableSourceProps = await this.props.selectedLayer.getImmutableSourceProperties();
if (this._isMounted) {
this.setState({ immutableSourceProps });
}
};
async _loadLeftJoinFields() {
if (!this.props.selectedLayer || !isVectorLayer(this.props.selectedLayer)) {
return;
@ -205,37 +189,7 @@ export class EditLayerPanel extends Component<Props, State> {
_renderSourceDetails() {
return !this.props.selectedLayer || isLayerGroup(this.props.selectedLayer) ? null : (
<div className="mapLayerPanel__sourceDetails">
<EuiAccordion
id="accordion1"
buttonContent={i18n.translate('xpack.maps.layerPanel.sourceDetailsLabel', {
defaultMessage: 'Source details',
})}
>
<EuiText color="subdued" size="s">
<EuiSpacer size="xs" />
{this.state.immutableSourceProps.map(
({ label, value, link }: ImmutableSourceProperty) => {
function renderValue() {
if (link) {
return (
<EuiLink href={link} target="_blank">
{value}
</EuiLink>
);
}
return <span>{value}</span>;
}
return (
<p key={label} className="mapLayerPanel__sourceDetail">
<strong>{label}</strong> {renderValue()}
</p>
);
}
)}
</EuiText>
</EuiAccordion>
</div>
<SourceDetails source={this.props.selectedLayer.getSource()} />
);
}

View file

@ -0,0 +1,20 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { connect } from 'react-redux';
import { SourceDetails } from './source_details';
import { getDataFilters } from '../../../selectors/map_selectors';
import { MapStoreState } from '../../../reducers/store';
function mapStateToProps(state: MapStoreState) {
return {
dataFilters: getDataFilters(state),
};
}
const connected = connect(mapStateToProps, {})(SourceDetails);
export { connected as SourceDetails };

View file

@ -0,0 +1,68 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { useEffect, useState } from 'react';
import { EuiAccordion, EuiLink, EuiSkeletonText, EuiSpacer, EuiText } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { DataFilters } from '../../../../common/descriptor_types';
import { ImmutableSourceProperty, ISource } from '../../../classes/sources/source';
export interface Props {
source: ISource;
dataFilters: DataFilters;
}
export function SourceDetails(props: Props) {
const [isLoading, setIsLoading] = useState(false);
const [sourceProperties, setSourceProperties] = useState<ImmutableSourceProperty[]>([]);
useEffect(() => {
let ignore = false;
setIsLoading(true);
props.source.getImmutableProperties(props.dataFilters).then((nextSourceProperties) => {
if (!ignore) {
setSourceProperties(nextSourceProperties);
setIsLoading(false);
}
});
return () => {
ignore = true;
};
}, [props.dataFilters, props.source]);
return (
<div className="mapLayerPanel__sourceDetails">
<EuiAccordion
id="accordion1"
buttonContent={i18n.translate('xpack.maps.layerPanel.sourceDetailsLabel', {
defaultMessage: 'Source details',
})}
>
<EuiSpacer size="xs" />
<EuiSkeletonText lines={3} size="s" isLoading={isLoading}>
<EuiText color="subdued" size="s">
{sourceProperties.map(({ label, value, link }: ImmutableSourceProperty) => {
return (
<p key={label} className="mapLayerPanel__sourceDetail">
<strong>{label}</strong>{' '}
{link ? (
<EuiLink href={link} target="_blank">
{value}
</EuiLink>
) : (
<span>{value}</span>
)}
</p>
);
})}
</EuiText>
</EuiSkeletonText>
</EuiAccordion>
</div>
);
}