fix secondary mount of sql editor

This commit is contained in:
Nate Kelley 2025-04-21 11:52:19 -06:00
parent 76f479f739
commit 2115c4de06
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
8 changed files with 118 additions and 115 deletions

View File

@ -1,7 +1,7 @@
import { MetricViewResults } from '@/controllers/MetricController/MetricViewResults'; import { MetricViewResultsController } from '@/controllers/MetricController/MetricViewResults';
export default async function ResultsPage({ params }: { params: Promise<{ metricId: string }> }) { export default async function ResultsPage({ params }: { params: Promise<{ metricId: string }> }) {
const { metricId } = await params; const { metricId } = await params;
return <MetricViewResults metricId={metricId} />; return <MetricViewResultsController metricId={metricId} />;
} }

View File

@ -1,7 +1,7 @@
import { MetricViewResults } from '@/controllers/MetricController/MetricViewResults'; import { MetricViewResultsController } from '@/controllers/MetricController/MetricViewResults';
export default async function ResultsPage({ params }: { params: Promise<{ metricId: string }> }) { export default async function ResultsPage({ params }: { params: Promise<{ metricId: string }> }) {
const { metricId } = await params; const { metricId } = await params;
return <MetricViewResults metricId={metricId} />; return <MetricViewResultsController metricId={metricId} />;
} }

View File

@ -3,6 +3,7 @@ import { AppSplitter, type AppSplitterRef } from '@/components/ui/layouts/AppSpl
import { SQLContainer } from './SQLContainer'; import { SQLContainer } from './SQLContainer';
import { DataContainer } from './DataContainer'; import { DataContainer } from './DataContainer';
import type { IDataResult } from '@/api/asset_interfaces'; import type { IDataResult } from '@/api/asset_interfaces';
import { useMount } from '@/hooks';
export interface AppVerticalCodeSplitterProps { export interface AppVerticalCodeSplitterProps {
sql: string; sql: string;

View File

@ -91,9 +91,11 @@ export const AppSplitter = React.memo(
}, [hasHidden, leftHidden, sizes]); }, [hasHidden, leftHidden, sizes]);
const memoizedLeftPaneStyle = useMemo(() => { const memoizedLeftPaneStyle = useMemo(() => {
const isHidden = leftHidden || _sizes[0] === '0%'; //leftHidden || _sizes[0] === '0px' || _sizes[0] === 0 || _sizes[0] === '0%'; const isHidden = leftHidden;
const isEffectivelyHidden = _sizes[0] === '0px' || _sizes[0] === '0%';
return { return {
display: isHidden ? 'none' : undefined display: isHidden ? 'none' : undefined,
overflow: isEffectivelyHidden ? 'hidden' : undefined
}; };
}, [leftHidden, _sizes[0]]); }, [leftHidden, _sizes[0]]);

View File

@ -4,7 +4,6 @@ import { BusterChart } from '@/components/ui/charts';
import { cn } from '@/lib/classMerge'; import { cn } from '@/lib/classMerge';
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { METRIC_CHART_CONTAINER_ID } from './config'; import { METRIC_CHART_CONTAINER_ID } from './config';
import { useMount } from '@/hooks';
interface MetricViewChartContentProps { interface MetricViewChartContentProps {
className?: string; className?: string;

View File

@ -1,7 +1,7 @@
'use client'; 'use client';
import React, { useEffect, useMemo, useState } from 'react'; import React, { useEffect, useMemo, useState } from 'react';
import { useMemoizedFn, useUnmount } from '@/hooks'; import { useMemoizedFn, useMount, useUnmount } from '@/hooks';
import { IDataResult } from '@/api/asset_interfaces'; import { IDataResult } from '@/api/asset_interfaces';
import { useMetricResultsLayout } from './useMetricResultsLayout'; import { useMetricResultsLayout } from './useMetricResultsLayout';
import { useChatLayoutContextSelector } from '@/layouts/ChatLayout/ChatLayoutContext'; import { useChatLayoutContextSelector } from '@/layouts/ChatLayout/ChatLayoutContext';
@ -12,111 +12,109 @@ import { useGetMetric, useGetMetricData } from '@/api/buster_rest/metrics';
const autoSaveId = 'metric-view-results'; const autoSaveId = 'metric-view-results';
export const MetricViewResults: React.FC<{ metricId: string }> = React.memo(({ metricId }) => { export const MetricViewResultsController: React.FC<{ metricId: string }> = React.memo(
const appSplitterRef = React.useRef<AppSplitterRef>(null); ({ metricId }) => {
const selectedFileViewSecondary = useChatLayoutContextSelector( const appSplitterRef = React.useRef<AppSplitterRef>(null);
(x) => x.selectedFileViewSecondary const selectedFileViewSecondary = useChatLayoutContextSelector(
); (x) => x.selectedFileViewSecondary
const containerRef = React.useRef<HTMLDivElement>(null); );
const containerRef = React.useRef<HTMLDivElement>(null);
const { const {
runSQL, runSQL,
resetRunSQLData, resetRunSQLData,
saveSQL, saveSQL,
saveMetricError, saveMetricError,
runSQLError, runSQLError,
isSavingMetric, isSavingMetric,
isRunningSQL isRunningSQL
} = useMetricRunSQL(); } = useMetricRunSQL();
const { data: metric } = useGetMetric( const { data: metric } = useGetMetric(
{ id: metricId }, { id: metricId },
{ {
select: ({ sql, data_source_id }) => ({ select: ({ sql, data_source_id }) => ({
sql, sql,
data_source_id data_source_id
}) })
}
);
const { data: metricData, isFetched: isFetchedInitialData } = useGetMetricData(
{ id: metricId },
{ enabled: false }
);
const [sql, setSQL] = useState(metric?.sql || '');
const dataSourceId = metric?.data_source_id || '';
const data: IDataResult = metricData?.dataFromRerun || metricData?.data || null;
const disableSave = useMemo(() => {
return !sql || isRunningSQL || sql === metric?.sql;
}, [sql, isRunningSQL, metric?.sql]);
const onRunQuery = useMemoizedFn(async () => {
try {
const res = await runSQL({
dataSourceId,
sql,
metricId
});
if (res && res.data && res.data.length > 0) {
const data = res.data;
const headerHeight = 28.1;
const heightOfRow = 28.1;
const heightOfDataContainer = headerHeight + heightOfRow * (data.length || 0);
const containerHeight = containerRef.current?.clientHeight || 0;
const maxHeight = Math.floor(containerHeight * 0.6);
const finalHeight = Math.min(heightOfDataContainer, maxHeight) + 12;
appSplitterRef.current?.setSplitSizes(['auto', `${finalHeight}px`]);
} }
} catch (error) { );
// const { data: metricData, isFetched: isFetchedInitialData } = useGetMetricData(
} { id: metricId },
}); { enabled: false }
);
const onSaveSQL = useMemoizedFn(async () => { const [sql, setSQL] = useState(metric?.sql || '');
await saveSQL({
metricId, const dataSourceId = metric?.data_source_id || '';
sql, const data: IDataResult = metricData?.dataFromRerun || metricData?.data || null;
dataSourceId
const disableSave = useMemo(() => {
return !sql || isRunningSQL || sql === metric?.sql;
}, [sql, isRunningSQL, metric?.sql]);
const onRunQuery = useMemoizedFn(async () => {
try {
const res = await runSQL({
dataSourceId,
sql,
metricId
});
if (res && res.data && res.data.length > 0) {
const data = res.data;
const headerHeight = 28.1;
const heightOfRow = 28.1;
const heightOfDataContainer = headerHeight + heightOfRow * (data.length || 0);
const containerHeight = containerRef.current?.clientHeight || 0;
const maxHeight = Math.floor(containerHeight * 0.6);
const finalHeight = Math.min(heightOfDataContainer, maxHeight) + 12;
appSplitterRef.current?.setSplitSizes(['auto', `${finalHeight}px`]);
}
} catch (error) {
//
}
}); });
});
const { defaultLayout, renderSecondary } = useMetricResultsLayout({ const onSaveSQL = useMemoizedFn(async () => {
selectedFileViewSecondary, await saveSQL({
appSplitterRef, metricId,
autoSaveId sql,
}); dataSourceId
});
});
useEffect(() => { const { defaultLayout, renderSecondary } = useMetricResultsLayout({
if (metric?.sql) { selectedFileViewSecondary,
setSQL(metric.sql); appSplitterRef,
} autoSaveId
}, [metric?.sql]); });
useUnmount(() => { useEffect(() => {
resetRunSQLData({ metricId }); if (metric?.sql) {
}); setSQL(metric.sql);
}
}, [metric?.sql]);
return ( return (
<div ref={containerRef} className="h-full w-full p-5"> <div ref={containerRef} className="h-full w-full p-5">
<AppVerticalCodeSplitter <AppVerticalCodeSplitter
ref={appSplitterRef} ref={appSplitterRef}
autoSaveId={autoSaveId} autoSaveId={autoSaveId}
sql={sql} sql={sql}
setSQL={setSQL} setSQL={setSQL}
runSQLError={runSQLError || saveMetricError} runSQLError={runSQLError || saveMetricError}
topHidden={!renderSecondary} topHidden={!renderSecondary}
onRunQuery={onRunQuery} onRunQuery={onRunQuery}
onSaveSQL={onSaveSQL} onSaveSQL={onSaveSQL}
data={data} data={data}
disabledSave={disableSave} disabledSave={disableSave}
fetchingData={isRunningSQL || isSavingMetric || !isFetchedInitialData} fetchingData={isRunningSQL || isSavingMetric || !isFetchedInitialData}
defaultLayout={defaultLayout} defaultLayout={defaultLayout}
/> />
</div> </div>
); );
}); }
);
MetricViewResults.displayName = 'MetricViewResults'; MetricViewResultsController.displayName = 'MetricViewResultsController';

View File

@ -120,7 +120,7 @@ const EditSQLButton = React.memo(({ metricId }: { metricId: string }) => {
const selectedFileViewSecondary = useChatLayoutContextSelector( const selectedFileViewSecondary = useChatLayoutContextSelector(
(x) => x.selectedFileViewSecondary (x) => x.selectedFileViewSecondary
); );
const onSetFileView = useChatLayoutContextSelector((x) => x.onSetFileView); const onChangePage = useAppLayoutContextSelector((x) => x.onChangePage);
const chatId = useChatIndividualContextSelector((x) => x.chatId); const chatId = useChatIndividualContextSelector((x) => x.chatId);
const metricVersionNumber = useChatLayoutContextSelector((x) => x.metricVersionNumber); const metricVersionNumber = useChatLayoutContextSelector((x) => x.metricVersionNumber);
const editableSecondaryView: MetricFileViewSecondary = 'sql-edit'; const editableSecondaryView: MetricFileViewSecondary = 'sql-edit';
@ -148,14 +148,21 @@ const EditSQLButton = React.memo(({ metricId }: { metricId: string }) => {
// onSetFileView({ secondaryView, fileView: 'results' }); // onSetFileView({ secondaryView, fileView: 'results' });
// }); // });
console.log('href', href); const onClickButton = useMemoizedFn(() => {
onChangePage(href, { shallow: true });
});
return ( return (
<Link href={href}> <Link
href={href}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
}}>
<SelectableButton <SelectableButton
tooltipText="SQL editor" tooltipText="SQL editor"
icon={<SquareCode />} icon={<SquareCode />}
onClick={() => {}} onClick={onClickButton}
selected={isSelectedView} selected={isSelectedView}
/> />
</Link> </Link>

View File

@ -17,17 +17,13 @@ const VersionHistoryPanel = dynamic(
), ),
{ loading } { loading }
); );
const MetricViewResults = dynamic(
() => import('@/controllers/MetricController/MetricViewResults').then((x) => x.MetricViewResults),
{ loading }
);
export const MetricSecondaryRecord: Record< export const MetricSecondaryRecord: Record<
MetricFileViewSecondary, MetricFileViewSecondary,
React.FC<FileContainerSecondaryProps> React.FC<FileContainerSecondaryProps>
> = { > = {
'chart-edit': ({ selectedFile }) => <MetricEditController metricId={selectedFile?.id || ''} />, 'chart-edit': ({ selectedFile }) => <MetricEditController metricId={selectedFile?.id || ''} />,
'sql-edit': ({ selectedFile }) => <MetricViewResults metricId={selectedFile?.id || ''} />, 'sql-edit': ({ selectedFile }) => <></>, //because this is a vertical splitter, we don't want to render the sql edit view in the secondary view because it is vertical
'version-history': ({ selectedFile }) => ( 'version-history': ({ selectedFile }) => (
<VersionHistoryPanel assetId={selectedFile?.id || ''} type="metric" /> <VersionHistoryPanel assetId={selectedFile?.id || ''} type="metric" />
) )