import { isEqual, map, find } from 'lodash'; import React, { useState, useMemo, useEffect, useRef } from 'react'; import PropTypes from 'prop-types'; import { react2angular } from 'react2angular'; import useQueryResult from '@/lib/hooks/useQueryResult'; import { Filters, FiltersType, filterData } from '@/components/Filters'; import { registeredVisualizations, VisualizationType } from './index'; function combineFilters(localFilters, globalFilters) { // tiny optimization - to avoid unnecessary updates if ((localFilters.length === 0) || (globalFilters.length === 0)) { return localFilters; } return map(localFilters, (localFilter) => { const globalFilter = find(globalFilters, f => f.name === localFilter.name); if (globalFilter) { return { ...localFilter, current: globalFilter.current, }; } return localFilter; }); } export function VisualizationRenderer(props) { const data = useQueryResult(props.queryResult); const [filters, setFilters] = useState(data.filters); const lastOptions = useRef(); // Reset local filters when query results updated useEffect(() => { setFilters(combineFilters(data.filters, props.filters)); }, [data]); // Update local filters when global filters changed useEffect(() => { setFilters(combineFilters(filters, props.filters)); }, [props.filters]); const filteredData = useMemo(() => ({ columns: data.columns, rows: filterData(data.rows, filters), }), [data, filters]); const { showFilters, visualization } = props; const { Renderer, getOptions } = registeredVisualizations[visualization.type]; // Avoid unnecessary updates (which may be expensive or cause issues with // internal state of some visualizations like Table) - compare options deeply // and use saved reference if nothing changed // More details: https://github.com/getredash/redash/pull/3963#discussion_r306935810 let options = getOptions(visualization.options, data); if (isEqual(lastOptions.current, options)) { options = lastOptions.current; } lastOptions.current = options; return (