This is an automated email from the ASF dual-hosted git repository. kgabryje pushed a commit to branch what-if in repository https://gitbox.apache.org/repos/asf/superset.git
commit 5d6a697e324dd8142dac06d3e88c0ceef09d5c70 Author: Kamil Gabryjelski <[email protected]> AuthorDate: Tue Dec 16 23:12:10 2025 +0100 fun border --- .../gridComponents/ChartHolder/ChartHolder.tsx | 5 +- .../src/dashboard/util/useWhatIfHighlightStyles.ts | 143 +++++++++++++++++++++ 2 files changed, 147 insertions(+), 1 deletion(-) diff --git a/superset-frontend/src/dashboard/components/gridComponents/ChartHolder/ChartHolder.tsx b/superset-frontend/src/dashboard/components/gridComponents/ChartHolder/ChartHolder.tsx index 7d68c8ceae..1f1014b67d 100644 --- a/superset-frontend/src/dashboard/components/gridComponents/ChartHolder/ChartHolder.tsx +++ b/superset-frontend/src/dashboard/components/gridComponents/ChartHolder/ChartHolder.tsx @@ -31,6 +31,7 @@ import HoverMenu from 'src/dashboard/components/menu/HoverMenu'; import ResizableContainer from 'src/dashboard/components/resizable/ResizableContainer'; import getChartAndLabelComponentIdFromPath from 'src/dashboard/util/getChartAndLabelComponentIdFromPath'; import useFilterFocusHighlightStyles from 'src/dashboard/util/useFilterFocusHighlightStyles'; +import useWhatIfHighlightStyles from 'src/dashboard/util/useWhatIfHighlightStyles'; import { COLUMN_TYPE, ROW_TYPE } from 'src/dashboard/util/componentTypes'; import { GRID_BASE_UNIT, @@ -107,6 +108,7 @@ const ChartHolder = ({ const isFullSize = fullSizeChartId === chartId; const focusHighlightStyles = useFilterFocusHighlightStyles(chartId); + const whatIfHighlightStyles = useWhatIfHighlightStyles(chartId); const directPathToChild = useSelector( (state: RootState) => state.dashboardState.directPathToChild, ); @@ -260,7 +262,7 @@ const ChartHolder = ({ ref={dragSourceRef} data-test="dashboard-component-chart-holder" style={focusHighlightStyles} - css={isFullSize ? fullSizeStyle : undefined} + css={[isFullSize && fullSizeStyle, whatIfHighlightStyles]} className={cx( 'dashboard-component', 'dashboard-component-chart-holder', @@ -325,6 +327,7 @@ const ChartHolder = ({ onResizeStop, editMode, focusHighlightStyles, + whatIfHighlightStyles, isFullSize, fullSizeStyle, chartId, diff --git a/superset-frontend/src/dashboard/util/useWhatIfHighlightStyles.ts b/superset-frontend/src/dashboard/util/useWhatIfHighlightStyles.ts new file mode 100644 index 0000000000..1db666a7f8 --- /dev/null +++ b/superset-frontend/src/dashboard/util/useWhatIfHighlightStyles.ts @@ -0,0 +1,143 @@ +/** + * 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 { useMemo } from 'react'; +import { useSelector } from 'react-redux'; +import { css, keyframes } from '@emotion/react'; +import { RootState, WhatIfModification } from 'src/dashboard/types'; +import { extractColumnsFromSlice } from './whatIf'; + +const EMPTY_STYLES = undefined; + +/* eslint-disable theme-colors/no-literal-colors */ +const rainbowSlide = keyframes` + 0% { + background-position: 0% 50%; + } + 100% { + background-position: 300% 50%; + } +`; + +const pulse = keyframes` + 0%, 100% { + opacity: 0.7; + filter: blur(0px); + } + 50% { + opacity: 1; + filter: blur(2px); + } +`; + +const whatIfHighlightStyles = css` + position: relative; + + &::before { + content: ''; + position: absolute; + inset: -2px; + border-radius: 10px; + padding: 4px; + background: linear-gradient( + 90deg, + #ff0000, + #ff8000, + #ffff00, + #80ff00, + #00ff00, + #00ff80, + #00ffff, + #0080ff, + #0000ff, + #8000ff, + #ff00ff, + #ff0080, + #ff0000, + #ff8000, + #ffff00, + #80ff00, + #00ff00, + #00ff80, + #00ffff, + #0080ff, + #0000ff, + #8000ff, + #ff00ff, + #ff0080, + #ff0000 + ); + background-size: 300% 100%; + animation: + ${rainbowSlide} 20s linear infinite, + ${pulse} 3s ease-in-out infinite; + -webkit-mask: + linear-gradient(#fff 0 0) content-box, + linear-gradient(#fff 0 0); + -webkit-mask-composite: xor; + mask-composite: exclude; + pointer-events: none; + } +`; +/* eslint-enable theme-colors/no-literal-colors */ + +/** + * Hook that returns animated rainbow border styles for charts + * that are affected by what-if transformations. + */ +const useWhatIfHighlightStyles = (chartId: number) => { + const whatIfModifications = useSelector( + (state: RootState) => state.dashboardState.whatIfModifications, + ); + + const slice = useSelector( + (state: RootState) => state.sliceEntities?.slices?.[chartId], + ); + + const isAffected = useMemo(() => { + if (!whatIfModifications || whatIfModifications.length === 0) { + return false; + } + + if (!slice) { + return false; + } + + const chartColumns = extractColumnsFromSlice(slice); + const modifiedColumns = new Set( + whatIfModifications.map((mod: WhatIfModification) => mod.column), + ); + + // Check if any of the chart's columns are being modified + for (const column of chartColumns) { + if (modifiedColumns.has(column)) { + return true; + } + } + + return false; + }, [whatIfModifications, slice]); + + if (!isAffected) { + return EMPTY_STYLES; + } + + return whatIfHighlightStyles; +}; + +export default useWhatIfHighlightStyles;
