You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by kg...@apache.org on 2025/12/18 23:55:22 UTC
(superset) 08/23: fun border
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 <ka...@gmail.com>
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;