blob: b2b45fc42c95c682d2e41feca75cac5c9e249b7b [file] [log] [blame]
/**
* 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 React, { useEffect, useRef, useState } from 'react';
import {
QueryFormData,
styled,
SuperChart,
DataMask,
t,
Behavior,
} from '@superset-ui/core';
import { areObjectsEqual } from 'src/reduxUtils';
import { getChartDataRequest } from 'src/chart/chartAction';
import Loading from 'src/components/Loading';
import BasicErrorAlert from 'src/components/ErrorMessage/BasicErrorAlert';
import { FilterProps } from './types';
import { getFormData } from '../utils';
import { useCascadingFilters } from './state';
const StyledLoadingBox = styled.div`
position: relative;
height: ${({ theme }) => theme.gridUnit * 8}px;
margin-bottom: ${({ theme }) => theme.gridUnit * 6}px;
`;
const FilterItem = styled.div`
padding-bottom: 10px;
`;
const FilterValue: React.FC<FilterProps> = ({
filter,
directPathToChild,
onFilterSelectionChange,
}) => {
const { id, targets, filterType } = filter;
const cascadingFilters = useCascadingFilters(id);
const [state, setState] = useState([]);
const [error, setError] = useState<boolean>(false);
const [formData, setFormData] = useState<Partial<QueryFormData>>({});
const inputRef = useRef<HTMLInputElement>(null);
const [target] = targets;
const {
datasetId,
column = {},
}: Partial<{ datasetId: number; column: { name?: string } }> = target;
const { name: groupby } = column;
const hasDataSource = !!(datasetId && groupby);
const [loading, setLoading] = useState<boolean>(hasDataSource);
useEffect(() => {
const newFormData = getFormData({
...filter,
datasetId,
cascadingFilters,
groupby,
inputRef,
});
if (!areObjectsEqual(formData || {}, newFormData)) {
setFormData(newFormData);
if (!hasDataSource) {
return;
}
getChartDataRequest({
formData: newFormData,
force: false,
requestParams: { dashboardId: 0 },
})
.then(response => {
setState(response.result);
setError(false);
setLoading(false);
})
.catch(() => {
setError(true);
setLoading(false);
});
}
}, [
cascadingFilters,
datasetId,
groupby,
JSON.stringify(filter),
hasDataSource,
]);
useEffect(() => {
if (directPathToChild?.[0] === filter.id) {
// wait for Cascade Popover to open
const timeout = setTimeout(() => {
inputRef?.current?.focus();
}, 200);
return () => clearTimeout(timeout);
}
return undefined;
}, [inputRef, directPathToChild, filter.id]);
const setDataMask = (dataMask: DataMask) =>
onFilterSelectionChange(filter, dataMask);
if (loading) {
return (
<StyledLoadingBox>
<Loading />
</StyledLoadingBox>
);
}
if (error) {
return (
<BasicErrorAlert
title={t('Cannot load filter')}
body={t('Check configuration')}
level="error"
/>
);
}
return (
<FilterItem data-test="form-item-value">
<SuperChart
height={20}
width={220}
formData={formData}
// For charts that don't have datasource we need workaround for empty placeholder
queriesData={hasDataSource ? state : [{ data: [null] }]}
chartType={filterType}
behaviors={[Behavior.NATIVE_FILTER]}
hooks={{ setDataMask }}
/>
</FilterItem>
);
};
export default FilterValue;