blob: 25779d403b6003e5afbe99c7d915923b099306ca [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 { flow, keyBy, mapValues } from 'lodash/fp';
import { flatMap, isEmpty } from 'lodash';
import { CHART_TYPE, TAB_TYPE } from './componentTypes';
import { getChartIdAndColumnFromFilterKey } from './getDashboardFilterKey';
function getTabChildrenScope({
tabScopes,
parentNodeValue,
forceAggregate = false,
hasChartSiblings = false,
immuneChartSiblings = [],
}) {
// if all sub-tabs are in scope, or forceAggregate = true
// aggregate scope to parentNodeValue
if (
forceAggregate ||
(!hasChartSiblings &&
Object.entries(tabScopes).every(
([key, { scope }]) => scope && scope.length && key === scope[0],
))
) {
return {
scope: [parentNodeValue],
immune: flatMap(Object.values(tabScopes), ({ immune }) => immune),
};
}
const componentsInScope = Object.values(tabScopes).filter(
({ scope }) => scope && scope.length,
);
return {
scope: flatMap(componentsInScope, ({ scope }) => scope),
immune: componentsInScope.length
? flatMap(componentsInScope, ({ immune }) => immune)
: flatMap(Object.values(tabScopes), ({ immune }) => immune).concat(
immuneChartSiblings,
),
};
}
function traverse({ currentNode = {}, filterId, checkedChartIds = [] }) {
if (!currentNode) {
return {};
}
const { value: currentValue, children } = currentNode;
const chartChildren = children.filter(({ type }) => type === CHART_TYPE);
const tabChildren = children.filter(({ type }) => type === TAB_TYPE);
const chartsImmune = chartChildren
.filter(
({ value }) => filterId !== value && !checkedChartIds.includes(value),
)
.map(({ value }) => value);
const tabScopes = flow(
keyBy(child => child.value),
mapValues(child =>
traverse({
currentNode: child,
filterId,
checkedChartIds,
}),
),
)(tabChildren);
// if any chart type child is in scope,
// no matter has tab children or not, current node should be scope
if (
!isEmpty(chartChildren) &&
chartChildren.some(({ value }) => checkedChartIds.includes(value))
) {
if (isEmpty(tabChildren)) {
return { scope: [currentValue], immune: chartsImmune };
}
const { scope, immune } = getTabChildrenScope({
tabScopes,
parentNodeValue: currentValue,
forceAggregate: true,
});
return {
scope,
immune: chartsImmune.concat(immune),
};
}
// has tab children but only some sub-tab in scope
if (tabChildren.length) {
return getTabChildrenScope({
tabScopes,
parentNodeValue: currentValue,
hasChartSiblings: !isEmpty(chartChildren),
immuneChartSiblings: chartsImmune,
});
}
// no tab children and no chart children in scope
return {
scope: [],
immune: chartsImmune,
};
}
export default function getFilterScopeFromNodesTree({
filterKey,
nodes = [],
checkedChartIds = [],
}) {
if (nodes.length) {
const { chartId } = getChartIdAndColumnFromFilterKey(filterKey);
return traverse({
currentNode: nodes[0],
filterId: chartId,
checkedChartIds,
});
}
return {};
}