Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,32 @@ describe('ChartContainer', () => {
expect(await screen.findByRole('timer')).toBeInTheDocument();
expect(gutter).not.toBeVisible();
});

test('renders LastQueriedLabel when chart is not loading', async () => {
const props = createProps({
chart: {
chartStatus: 'rendered',
queriesResponse: [
{
queried_dttm: '2026-01-27T19:53:40.000Z',
is_cached: false,
},
],
},
});
render(<ChartContainer {...props} />, { useRedux: true });
expect(await screen.findByText(/last queried at/i)).toBeInTheDocument();
});

test('does not render LastQueriedLabel when chart is loading', async () => {
const props = createProps({
chart: {
chartStatus: 'loading',
queriesResponse: [],
},
});
render(<ChartContainer {...props} />, { useRedux: true });
expect(await screen.findByRole('timer')).toBeInTheDocument();
expect(screen.queryByText(/last queried at/i)).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -100,29 +100,51 @@ const MIN_SIZES: PanelSizes = [300, 65];
const DEFAULT_SOUTH_PANE_HEIGHT_PERCENT = 40;

const Styles = styled.div<{ showSplite: boolean }>`
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: stretch;
align-content: stretch;
overflow: auto;
Comment thread
ramiroaquinoromero marked this conversation as resolved.
Resolved
box-shadow: none;
height: 100%;
width: 100%;
min-height: 400px;
min-width: 300px;

& > div {
height: 100%;
min-height: 0;
width: 100%;
box-sizing: border-box;
}

.gutter {
border-top: 1px solid ${({ theme }) => theme.colorSplit};
border-bottom: 1px solid ${({ theme }) => theme.colorSplit};
width: ${({ theme }) => theme.sizeUnit * 9}px;
margin: ${({ theme }) => theme.sizeUnit * GUTTER_SIZE_FACTOR}px auto;
margin: 0 auto;
box-sizing: border-box;
background-color: ${({ theme }) => theme.colorFillQuaternary};
}

.gutter.gutter-vertical {
display: ${({ showSplite }) => (showSplite ? 'block' : 'none')};
cursor: row-resize;
position: relative;
}

.split-pane {
box-sizing: border-box;
}
`;

const ChartWrapper = styled.div`
height: 100%;
width: 100%;
overflow: hidden;
position: relative;
box-sizing: border-box;
`;

const ExploreChartPanel = ({
Expand All @@ -144,11 +166,9 @@ const ExploreChartPanel = ({
can_download: canDownload,
}: ExploreChartPanelProps) => {
const theme = useTheme();
const gutterMargin = theme.sizeUnit * GUTTER_SIZE_FACTOR;
const gutterHeight = theme.sizeUnit * GUTTER_SIZE_FACTOR;
const {
ref: chartPanelRef,
observerRef: resizeObserverRef,
width: chartPanelWidth,
height: chartPanelHeight,
Comment thread
ramiroaquinoromero marked this conversation as resolved.
Resolved
} = useResizeDetectorByObserver();
Expand Down Expand Up @@ -244,19 +264,22 @@ const ExploreChartPanel = ({
setShowSplit(isOpen);
}, []);

const renderChart = useCallback(
const renderChart = useMemo(
Comment thread
ramiroaquinoromero marked this conversation as resolved.
Resolved
() => (
<div
css={css`
min-height: 0;
flex: 1;
overflow: auto;
min-height: 260px;
min-width: 300px;
Comment thread
ramiroaquinoromero marked this conversation as resolved.
Resolved
flex: 1 1 auto;
overflow: hidden;
position: relative;
box-sizing: border-box;
`}
ref={chartPanelRef}
>
{chartPanelWidth && chartPanelHeight && (
{chartPanelWidth && chartPanelHeight ? (
<ChartContainer
width={Math.floor(chartPanelWidth)}
width={chartPanelWidth}
height={chartPanelHeight}
ownState={ownState}
annotationData={chart.annotationData}
Expand All @@ -282,7 +305,7 @@ const ExploreChartPanel = ({
})}
{...(chart.chartStatus && { chartStatus: chart.chartStatus })}
/>
)}
) : null}
</div>
Comment thread
ramiroaquinoromero marked this conversation as resolved.
Resolved
),
[
Expand Down Expand Up @@ -319,8 +342,11 @@ const ExploreChartPanel = ({
display: flex;
flex-direction: column;
padding-top: ${theme.sizeUnit * 2}px;
min-height: 0;
width: 100%;
box-sizing: border-box;
overflow: auto;
`}
ref={resizeObserverRef}
>
{vizTypeNeedsDataset && (
<Alert
Expand Down Expand Up @@ -403,24 +429,26 @@ const ExploreChartPanel = ({
formData={formData}
/>
</ChartHeaderExtension>
{renderChart()}
{!chart.chartStatus || chart.chartStatus !== 'loading' ? (
{renderChart}
<div
css={css`
display: flex;
justify-content: flex-end;
padding-top: ${theme.sizeUnit * 2}px;
flex-shrink: 0;
min-height: ${theme.sizeUnit * 6}px;
visibility: ${!chart.chartStatus || chart.chartStatus !== 'loading'
? 'visible'
: 'hidden'};
`}
>
<LastQueriedLabel
queriedDttm={chart.queriesResponse?.[0]?.queried_dttm ?? null}
/>
</div>
) : null}
</div>
),
[
resizeObserverRef,
showAlertBanner,
errorMessage,
onQuery,
Expand All @@ -434,10 +462,18 @@ const ExploreChartPanel = ({
formData?.matrixify_enable_horizontal_layout,
renderChart,
theme.sizeUnit,
vizTypeNeedsDataset,
chart.id,
slice?.form_data,
formData,
chart.lastRendered,
chart.latestQueryFormData,
chart.queryController,
chart.triggerQuery,
],
);

const standaloneChartBody = useMemo(() => renderChart(), [renderChart]);
const standaloneChartBody = useMemo(() => renderChart, [renderChart]);

const [queryFormData, setQueryFormData] = useState(chart.latestQueryFormData);

Expand All @@ -459,9 +495,9 @@ const ExploreChartPanel = ({
elementSize: number,
gutterSize: number,
) => ({
[dimension]: `calc(${elementSize}% - ${gutterSize + gutterMargin}px)`,
[dimension]: `calc(${elementSize}% - ${gutterSize}px)`,
}),
[gutterMargin],
[],
);

if (standalone) {
Expand All @@ -472,13 +508,14 @@ const ExploreChartPanel = ({
document.body.className += ` ${standaloneClass}`;
}
return (
<div id="app" data-test="standalone-app" ref={resizeObserverRef}>
<ChartWrapper id="app" data-test="standalone-app">
{standaloneChartBody}
</div>
</ChartWrapper>
);
}

return (
<ChartWrapper>
<Styles className="chart-container" showSplite={showSplite}>
<Split
sizes={splitSizes}
Expand All @@ -488,6 +525,8 @@ const ExploreChartPanel = ({
onDragEnd={onDragEnd}
elementStyle={elementStyle}
expandToMin
snapOffset={0}
cursor="row-resize"
>
{panelBody}
<DataTablesPane
Expand All @@ -514,6 +553,7 @@ const ExploreChartPanel = ({
/>
)}
</Styles>
</ChartWrapper>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,35 @@
* specific language governing permissions and limitations
* under the License.
*/
import { useState, useCallback, useRef } from 'react';
import { useMemo } from 'react';
import { useResizeDetector } from 'react-resize-detector';

export default function useResizeDetectorByObserver() {
const ref = useRef<HTMLDivElement>(null);
const [{ width, height }, setChartPanelSize] = useState<{
width?: number;
height?: number;
}>({});
Comment thread
ramiroaquinoromero marked this conversation as resolved.
Resolved
const onResize = useCallback(() => {
if (ref.current) {
const { width, height } = ref.current.getBoundingClientRect?.() || {};
setChartPanelSize({ width, height });
}
}, []);
const { ref: observerRef } = useResizeDetector({
const {
width: rawWidth,
height: rawHeight,
ref,
} = useResizeDetector({
refreshMode: 'debounce',
refreshRate: 300,
onResize,
refreshRate: 250,
handleHeight: true,
handleWidth: true,
skipOnMount: true,
});
Comment thread
ramiroaquinoromero marked this conversation as resolved.
Resolved

// Round dimensions immediately to prevent sub-pixel render loops
const width = useMemo(
() => (rawWidth ? Math.floor(rawWidth) : undefined),
Comment thread
ramiroaquinoromero marked this conversation as resolved.
Resolved
[rawWidth],
);

const height = useMemo(
() => (rawHeight ? Math.floor(rawHeight) : undefined),
Comment thread
ramiroaquinoromero marked this conversation as resolved.
Resolved
[rawHeight],
);

return {
ref,
observerRef,
width,
height,
};
Expand Down
Loading