150 lines
4.7 KiB
TypeScript
150 lines
4.7 KiB
TypeScript
/* eslint-disable react/jsx-handler-names */
|
|
/* eslint-disable react/no-access-state-in-setstate */
|
|
/* eslint-disable camelcase */
|
|
/**
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF 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 { memo, useCallback, useEffect, useRef, useState } from 'react';
|
|
import { isEqual } from 'lodash';
|
|
import {
|
|
Datasource,
|
|
HandlerFunction,
|
|
JsonObject,
|
|
JsonValue,
|
|
QueryFormData,
|
|
SupersetClient,
|
|
usePrevious,
|
|
} from '@superset-ui/core';
|
|
import { Layer } from '@deck.gl/core';
|
|
|
|
import {
|
|
DeckGLContainerHandle,
|
|
DeckGLContainerStyledWrapper,
|
|
} from '../DeckGLContainer';
|
|
import { getExploreLongUrl } from '../utils/explore';
|
|
import layerGenerators from '../layers';
|
|
import { Viewport } from '../utils/fitViewport';
|
|
import { TooltipProps } from '../components/Tooltip';
|
|
|
|
export type DeckMultiProps = {
|
|
formData: QueryFormData;
|
|
payload: JsonObject;
|
|
setControlValue: (control: string, value: JsonValue) => void;
|
|
viewport: Viewport;
|
|
onAddFilter: HandlerFunction;
|
|
height: number;
|
|
width: number;
|
|
datasource: Datasource;
|
|
onSelect: () => void;
|
|
};
|
|
|
|
const DeckMulti = (props: DeckMultiProps) => {
|
|
const containerRef = useRef<DeckGLContainerHandle>();
|
|
|
|
const [viewport, setViewport] = useState<Viewport>();
|
|
const [subSlicesLayers, setSubSlicesLayers] = useState<Record<number, Layer>>(
|
|
{},
|
|
);
|
|
|
|
const setTooltip = useCallback((tooltip: TooltipProps['tooltip']) => {
|
|
const { current } = containerRef;
|
|
if (current) {
|
|
current.setTooltip(tooltip);
|
|
}
|
|
}, []);
|
|
|
|
const loadLayers = useCallback(
|
|
(formData: QueryFormData, payload: JsonObject, viewport?: Viewport) => {
|
|
setViewport(viewport);
|
|
setSubSlicesLayers({});
|
|
payload.data.slices.forEach(
|
|
(subslice: { slice_id: number } & JsonObject) => {
|
|
// Filters applied to multi_deck are passed down to underlying charts
|
|
// note that dashboard contextual information (filter_immune_slices and such) aren't
|
|
// taken into consideration here
|
|
const filters = [
|
|
...(subslice.form_data.filters || []),
|
|
...(formData.filters || []),
|
|
...(formData.extra_filters || []),
|
|
];
|
|
const subsliceCopy = {
|
|
...subslice,
|
|
form_data: {
|
|
...subslice.form_data,
|
|
filters,
|
|
},
|
|
};
|
|
|
|
const url = getExploreLongUrl(subsliceCopy.form_data, 'json');
|
|
|
|
if (url) {
|
|
SupersetClient.get({
|
|
endpoint: url,
|
|
})
|
|
.then(({ json }) => {
|
|
const layer = layerGenerators[subsliceCopy.form_data.viz_type](
|
|
subsliceCopy.form_data,
|
|
json,
|
|
props.onAddFilter,
|
|
setTooltip,
|
|
props.datasource,
|
|
[],
|
|
props.onSelect,
|
|
);
|
|
setSubSlicesLayers(subSlicesLayers => ({
|
|
...subSlicesLayers,
|
|
[subsliceCopy.slice_id]: layer,
|
|
}));
|
|
})
|
|
.catch(() => {});
|
|
}
|
|
},
|
|
);
|
|
},
|
|
[props.datasource, props.onAddFilter, props.onSelect, setTooltip],
|
|
);
|
|
|
|
const prevDeckSlices = usePrevious(props.formData.deck_slices);
|
|
useEffect(() => {
|
|
const { formData, payload } = props;
|
|
const hasChanges = !isEqual(prevDeckSlices, formData.deck_slices);
|
|
if (hasChanges) {
|
|
loadLayers(formData, payload);
|
|
}
|
|
}, [loadLayers, prevDeckSlices, props]);
|
|
|
|
const { payload, formData, setControlValue, height, width } = props;
|
|
const layers = Object.values(subSlicesLayers);
|
|
|
|
return (
|
|
<DeckGLContainerStyledWrapper
|
|
ref={containerRef}
|
|
mapboxApiAccessToken={payload.data.mapboxApiKey}
|
|
viewport={viewport || props.viewport}
|
|
layers={layers}
|
|
mapStyle={formData.mapbox_style}
|
|
setControlValue={setControlValue}
|
|
onViewportChange={setViewport}
|
|
height={height}
|
|
width={width}
|
|
/>
|
|
);
|
|
};
|
|
|
|
export default memo(DeckMulti);
|