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

[Maps] timeslider #96791

Closed
wants to merge 32 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
303045d
[maps] timeslider
nreese Apr 5, 2021
47fe821
range control with ticks
nreese Apr 5, 2021
c553348
add timeslice to store
nreese Apr 5, 2021
2e036eb
add close button to time slider
nreese Apr 6, 2021
6340845
display time window in slider
nreese Apr 6, 2021
bfbffe7
next and previous buttons
nreese Apr 6, 2021
a16f58c
preserve range when using next and previous buttons
nreese Apr 6, 2021
1de69e7
use timeslice in ES search
nreese Apr 6, 2021
0b90907
clear timeslice when time range changes or timeslider is closed
nreese Apr 6, 2021
cf740d4
time format clean up
nreese Apr 6, 2021
db6aca9
esSearcSource.updateDueToTimeslice
nreese Apr 7, 2021
2023f95
mask for timeslice in mb filter
nreese Apr 8, 2021
284b914
replace updateDueToTimeslice with source.maskForTimeslice
nreese Apr 10, 2021
5c9e1cc
pass source data request meta to maskForTimeslice
nreese Apr 10, 2021
551c094
rename maskForTimeslice to canMaskForTimeslice
nreese Apr 10, 2021
9dbca99
get source.canMaskTimeslice working for edge cases
nreese Apr 11, 2021
131e1f6
move getInterval into time utils
nreese Apr 11, 2021
d3722cf
canMaskTimeslice tests
nreese Apr 11, 2021
350de35
add timeslice mask field to request meta
nreese Apr 11, 2021
c6a2098
tslint
nreese Apr 12, 2021
f8f1ed6
getInterval tests
nreese Apr 12, 2021
98bbd55
fix mapbox_styles functional test
nreese Apr 13, 2021
a60781d
Merge branch 'master' into timeslider
kibanamachine Apr 13, 2021
dfb0393
Merge branch 'timeslider' of github.com:nreese/kibana into timeslider
nreese Apr 13, 2021
1e9af66
fix docvalue_fields functional test
nreese Apr 13, 2021
3a38ae5
fix broken jest tests
nreese Apr 13, 2021
2ca2bdc
Merge branch 'master' into timeslider
kibanamachine Apr 19, 2021
78875bb
pass timesliceMaskConfig to symbol filter expression
nreese Apr 19, 2021
c1c13c8
merge with master
nreese Apr 27, 2021
add90ad
fix merge conflict
nreese Apr 27, 2021
14cdf38
Merge branch 'master' into timeslider
kibanamachine Apr 29, 2021
ea2d163
merge with master
nreese May 5, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ import { RENDER_AS, SCALING_TYPES } from '../constants';
import { MapExtent, MapQuery } from './map_descriptor';
import { Filter, TimeRange } from '../../../../../src/plugins/data/common';

export type Timeslice = {
from: number;
to: number;
};

// Global map state passed to every layer.
export type MapFilters = {
buffer?: MapExtent; // extent with additional buffer
Expand All @@ -22,6 +27,7 @@ export type MapFilters = {
refreshTimerLastTriggeredAt?: string;
searchSessionId?: string;
timeFilters: TimeRange;
timeslice?: Timeslice;
zoom: number;
};

Expand Down
3 changes: 3 additions & 0 deletions x-pack/plugins/maps/public/actions/map_actions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,9 @@ describe('map_actions', () => {
require('../selectors/map_selectors').getTimeFilters = () => {
return timeFilters;
};
require('../selectors/map_selectors').getTimeslice = () => {
return undefined;
};
require('../selectors/map_selectors').getFilters = () => {
return filters;
};
Expand Down
29 changes: 25 additions & 4 deletions x-pack/plugins/maps/public/actions/map_actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
getWaitingForMapReadyLayerListRaw,
getQuery,
getTimeFilters,
getTimeslice,
getLayerList,
getSearchSessionId,
getSearchSessionMapBuffer,
Expand Down Expand Up @@ -54,6 +55,7 @@ import {
MapCenterAndZoom,
MapExtent,
MapRefreshConfig,
Timeslice,
} from '../../common/descriptor_types';
import { INITIAL_LOCATION } from '../../common/constants';
import { scaleBounds } from '../../common/elasticsearch_util';
Expand Down Expand Up @@ -227,17 +229,21 @@ function generateQueryTimestamp() {
export function setQuery({
query,
timeFilters,
timeslice,
filters = [],
forceRefresh = false,
searchSessionId,
searchSessionMapBuffer,
clearTimeslice,
}: {
filters?: Filter[];
query?: Query;
timeFilters?: TimeRange;
timeslice?: Timeslice;
forceRefresh?: boolean;
searchSessionId?: string;
searchSessionMapBuffer?: MapExtent;
clearTimeslice?: boolean;
}) {
return async (
dispatch: ThunkDispatch<MapStoreState, void, AnyAction>,
Expand All @@ -249,10 +255,24 @@ export function setQuery({
? prevQuery.queryLastTriggeredAt
: generateQueryTimestamp();

const prevTimeFilters = getTimeFilters(getState());

function getNextTimeslice() {
if (
clearTimeslice ||
(timeFilters !== undefined && !_.isEqual(timeFilters, prevTimeFilters))
) {
return undefined;
}

return timeslice ? timeslice : getTimeslice(getState());
}

const nextQueryContext = {
timeFilters: timeFilters ? timeFilters : getTimeFilters(getState()),
timeFilters: timeFilters ? timeFilters : prevTimeFilters,
timeslice: getNextTimeslice(),
query: {
...(query ? query : getQuery(getState())),
...(query ? query : prevQuery),
// ensure query changes to trigger re-fetch when "Refresh" clicked
queryLastTriggeredAt: forceRefresh ? generateQueryTimestamp() : prevTriggeredAt,
},
Expand All @@ -262,8 +282,9 @@ export function setQuery({
};

const prevQueryContext = {
timeFilters: getTimeFilters(getState()),
query: getQuery(getState()),
timeFilters: prevTimeFilters,
timeslice: getTimeslice(getState()),
query: prevQuery,
filters: getFilters(getState()),
searchSessionId: getSearchSessionId(getState()),
searchSessionMapBuffer: getSearchSessionMapBuffer(getState()),
Expand Down
20 changes: 19 additions & 1 deletion x-pack/plugins/maps/public/actions/ui_actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ import { ThunkDispatch } from 'redux-thunk';
import { MapStoreState } from '../reducers/store';
import { getFlyoutDisplay } from '../selectors/ui_selectors';
import { FLYOUT_STATE } from '../reducers/ui';
import { trackMapSettings } from './map_actions';
import { setQuery, trackMapSettings } from './map_actions';
import { setSelectedLayer } from './layer_actions';

export const UPDATE_FLYOUT = 'UPDATE_FLYOUT';
export const SET_IS_LAYER_TOC_OPEN = 'SET_IS_LAYER_TOC_OPEN';
export const SET_IS_TIME_SLIDER_OPEN = 'SET_IS_TIME_SLIDER_OPEN';
export const SET_FULL_SCREEN = 'SET_FULL_SCREEN';
export const SET_READ_ONLY = 'SET_READ_ONLY';
export const SET_OPEN_TOC_DETAILS = 'SET_OPEN_TOC_DETAILS';
Expand Down Expand Up @@ -87,3 +88,20 @@ export function hideTOCDetails(layerId: string) {
layerId,
};
}

export function openTimeslider() {
return {
type: SET_IS_TIME_SLIDER_OPEN,
isTimesliderOpen: true,
};
}

export function closeTimeslider() {
return (dispatch: ThunkDispatch<MapStoreState, void, AnyAction>) => {
dispatch({
type: SET_IS_TIME_SLIDER_OPEN,
isTimesliderOpen: false,
});
dispatch(setQuery({ clearTimeslice: true }));
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer {
async syncData(syncContext: DataRequestContext) {
const dataRequestId = ACTIVE_COUNT_DATA_ID;
const requestToken = Symbol(`layer-active-count:${this.getId()}`);
const searchFilters: VectorSourceRequestMeta = this._getSearchFilters(
const requestMeta: VectorSourceRequestMeta = await this._getSearchFilters(
syncContext.dataFilters,
this.getSource(),
this.getCurrentStyle()
Expand All @@ -303,7 +303,7 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer {
const canSkipFetch = await canSkipSourceUpdate({
source,
prevDataRequest: this.getDataRequest(dataRequestId),
nextMeta: searchFilters,
nextMeta: requestMeta,
extentAware: source.isFilterByMapBounds(),
});

Expand All @@ -321,11 +321,11 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer {
} else {
let isSyncClustered;
try {
syncContext.startLoading(dataRequestId, requestToken, searchFilters);
syncContext.startLoading(dataRequestId, requestToken, requestMeta);
const abortController = new AbortController();
syncContext.registerCancelCallback(requestToken, () => abortController.abort());
const maxResultWindow = await this._documentSource.getMaxResultWindow();
const searchSource = await this._documentSource.makeSearchSource(searchFilters, 0);
const searchSource = await this._documentSource.makeSearchSource(requestMeta, 0);
searchSource.setField('trackTotalHits', maxResultWindow + 1);
const resp = await searchSource.fetch({
abortSignal: abortController.signal,
Expand All @@ -336,8 +336,9 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer {
(resp.hits.total as unknown) as TotalHits,
maxResultWindow
);
const countData = { isSyncClustered } as CountData;
syncContext.stopLoading(dataRequestId, requestToken, countData, searchFilters);
const results = { isSyncClustered } as CountData;
const resultsMeta = { areResultsTrimmed: isSyncClustered };
syncContext.stopLoading(dataRequestId, requestToken, results, resultsMeta);
} catch (error) {
if (!(error instanceof DataRequestAbortError) || !isSearchSourceAbortError(error)) {
syncContext.onLoadError(dataRequestId, requestToken, error.message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { FeatureCollection } from 'geojson';
import { AbstractLayer } from '../layer';
import { HeatmapStyle } from '../../styles/heatmap/heatmap_style';
import { EMPTY_FEATURE_COLLECTION, LAYER_TYPE } from '../../../../common/constants';
import { HeatmapLayerDescriptor, MapQuery } from '../../../../common/descriptor_types';
import { HeatmapLayerDescriptor, MapQuery, Timeslice } from '../../../../common/descriptor_types';
import { ESGeoGridSource } from '../../sources/es_geo_grid_source';
import { addGeoJsonMbSource, getVectorSourceBounds, syncVectorSource } from '../vector_layer';
import { DataRequestContext } from '../../../actions';
Expand Down Expand Up @@ -119,7 +119,7 @@ export class HeatmapLayer extends AbstractLayer {
}
}

syncLayerWithMB(mbMap: MbMap) {
async syncLayerWithMB(mbMap: MbMap, timeslice?: Timeslice) {
addGeoJsonMbSource(this._getMbSourceId(), this.getMbLayerIds(), mbMap);

const heatmapLayerId = this._getHeatmapLayerId();
Expand Down
5 changes: 3 additions & 2 deletions x-pack/plugins/maps/public/classes/layers/layer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
LayerDescriptor,
MapExtent,
StyleDescriptor,
Timeslice,
} from '../../../common/descriptor_types';
import { ImmutableSourceProperty, ISource, SourceEditorArgs } from '../sources/source';
import { DataRequestContext } from '../../actions';
Expand Down Expand Up @@ -78,7 +79,7 @@ export interface ILayer {
ownsMbLayerId(mbLayerId: string): boolean;
ownsMbSourceId(mbSourceId: string): boolean;
canShowTooltip(): boolean;
syncLayerWithMB(mbMap: MbMap): void;
syncLayerWithMB(mbMap: MbMap, timeslice?: Timeslice): Promise<void>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if there is a way we can avoid this. Making the sync-operation async causes this asynciness to cascade. It's added complexity in the rendering, and not 100% sure if we're introducing issues.

e.g. the async should be explicitly handled here

this._syncMbMapWithLayerList();
}
this.props.spatialFiltersLayer.syncLayerWithMB(this.state.mbMap);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a similar comment wrt adding timeslice as optional param. All the other state propagates with search-filters, timeslice being the exception.

Right now, this is because of supporting masking, so it makes sense.

But could we keep track of timeslice state separately? e.g. it's not the only piece of state that is async but needed in styling. E.g. styleMeta is managed async too, but read-out synchronously when styles update.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the main question here imho would be: Can we make timeslice not special, and treat it like other parts of the global state required by layers.

getLayerTypeIconName(): string;
isInitialDataLoadComplete(): boolean;
getIndexPatternIds(): string[];
Expand Down Expand Up @@ -456,7 +457,7 @@ export class AbstractLayer implements ILayer {
return false;
}

syncLayerWithMB(mbMap: MbMap) {
syncLayerWithMB(mbMap: MbMap, timeslice?: Timeslice): Promise<void> {
throw new Error('Should implement AbstractLayer#syncLayerWithMB');
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export class TileLayer extends AbstractLayer {
return this.getId() === mbSourceId;
}

syncLayerWithMB(mbMap) {
async syncLayerWithMB(mbMap) {
const source = mbMap.getSource(this.getId());
const mbLayerId = this._getMbLayerId();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { VectorLayer, VectorLayerArguments } from '../vector_layer';
import { ITiledSingleLayerVectorSource } from '../../sources/tiled_single_layer_vector_source';
import { DataRequestContext } from '../../../actions';
import {
Timeslice,
VectorLayerDescriptor,
VectorSourceRequestMeta,
} from '../../../../common/descriptor_types';
Expand Down Expand Up @@ -66,7 +67,7 @@ export class TiledVectorLayer extends VectorLayer {
dataFilters,
}: DataRequestContext) {
const requestToken: symbol = Symbol(`layer-${this.getId()}-${SOURCE_DATA_REQUEST_ID}`);
const searchFilters: VectorSourceRequestMeta = this._getSearchFilters(
const searchFilters: VectorSourceRequestMeta = await this._getSearchFilters(
dataFilters,
this.getSource(),
this._style as IVectorStyle
Expand Down Expand Up @@ -162,7 +163,7 @@ export class TiledVectorLayer extends VectorLayer {
return this._getMbSourceId() === mbSourceId;
}

_syncStylePropertiesWithMb(mbMap: MbMap) {
async _syncStylePropertiesWithMb(mbMap: MbMap) {
// @ts-ignore
const mbSource = mbMap.getSource(this._getMbSourceId());
if (!mbSource) {
Expand Down Expand Up @@ -229,7 +230,7 @@ export class TiledVectorLayer extends VectorLayer {
return false;
}

syncLayerWithMB(mbMap: MbMap) {
async syncLayerWithMB(mbMap: MbMap, timeslice?: Timeslice) {
this._removeStaleMbSourcesAndLayers(mbMap);
this._syncSourceBindingWithMb(mbMap);
this._syncStylePropertiesWithMb(mbMap);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export async function getVectorSourceBounds({
sourceQuery: sourceQuery ? sourceQuery : undefined,
query: dataFilters.query,
timeFilters: dataFilters.timeFilters,
timeslice: dataFilters.timeslice,
filters: dataFilters.filters,
applyGlobalQuery: source.getApplyGlobalQuery(),
applyGlobalTime: source.getApplyGlobalTime(),
Expand Down
Loading