diff --git a/web/src/components/features/versionHistory/VersionHistoryPanel.tsx b/web/src/components/features/versionHistory/VersionHistoryPanel.tsx new file mode 100644 index 000000000..54dbd77c4 --- /dev/null +++ b/web/src/components/features/versionHistory/VersionHistoryPanel.tsx @@ -0,0 +1,9 @@ +import React from 'react'; + +export const VersionHistoryPanel = React.memo( + ({ assetId, type }: { assetId: string; type: 'metric' | 'dashboard' }) => { + return
VersionHistoryPanel
; + } +); + +VersionHistoryPanel.displayName = 'VersionHistoryPanel'; diff --git a/web/src/components/features/versionHistory/index.ts b/web/src/components/features/versionHistory/index.ts new file mode 100644 index 000000000..aa4fbfead --- /dev/null +++ b/web/src/components/features/versionHistory/index.ts @@ -0,0 +1 @@ +export * from './VersionHistoryPanel'; diff --git a/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricEditController.tsx b/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricEditController.tsx index 06ce7a072..73360b148 100644 --- a/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricEditController.tsx +++ b/web/src/controllers/MetricController/MetricViewChart/MetricEditController/MetricEditController.tsx @@ -14,3 +14,5 @@ export const MetricEditController: React.FC<{ }); MetricEditController.displayName = 'MetricEditController'; + +export default MetricEditController; diff --git a/web/src/controllers/MetricController/MetricViewChart/MetricViewChartController.tsx b/web/src/controllers/MetricController/MetricViewChart/MetricViewChartController.tsx index a674057ff..65329d9f6 100644 --- a/web/src/controllers/MetricController/MetricViewChart/MetricViewChartController.tsx +++ b/web/src/controllers/MetricController/MetricViewChart/MetricViewChartController.tsx @@ -1,12 +1,13 @@ 'use client'; -import React, { useRef } from 'react'; +import React, { useMemo, useRef } from 'react'; import type { MetricViewProps } from '../config'; import { AppSplitter, AppSplitterRef } from '@/components/ui/layouts'; import { MetricViewChart } from './MetricViewChart'; import { MetricEditController } from './MetricEditController'; import { useMetricLayout } from '../useMetricLayout'; import { useChatLayoutContextSelector } from '@/layouts/ChatLayout'; +import { VersionHistoryPanel } from '@/components/features/versionHistory'; const autoSaveId = 'metric-edit-chart'; @@ -23,12 +24,21 @@ export const MetricViewChartController: React.FC = React.memo(( type: 'chart' }); + const RightChildren = useMemo(() => { + if (!renderSecondary) return null; + if (selectedFileViewSecondary === 'chart-edit') + return ; + if (selectedFileViewSecondary === 'version-history') + return ; + return null; + }, [renderSecondary, metricId]); + return ( } - rightChildren={} + rightChildren={RightChildren} rightHidden={!renderSecondary} autoSaveId={autoSaveId} defaultLayout={defaultLayout} diff --git a/web/src/controllers/MetricController/MetricViewChart/index.ts b/web/src/controllers/MetricController/MetricViewChart/index.ts index bddd81a89..ff5537eaa 100644 --- a/web/src/controllers/MetricController/MetricViewChart/index.ts +++ b/web/src/controllers/MetricController/MetricViewChart/index.ts @@ -1 +1,2 @@ export * from './MetricViewChartController'; +export * from './MetricViewChart'; diff --git a/web/src/controllers/MetricController/config.ts b/web/src/controllers/MetricController/config.ts index 7d65acf3c..ec789bec8 100644 --- a/web/src/controllers/MetricController/config.ts +++ b/web/src/controllers/MetricController/config.ts @@ -3,13 +3,14 @@ import type { MetricFileView } from '@/layouts/ChatLayout'; import { MetricViewChartController } from './MetricViewChart'; import { MetricViewFile } from './MetricViewFile'; import { MetricViewResults } from './MetricViewResults'; +import { MetricViewChart } from './MetricViewChart'; export interface MetricViewProps { metricId: string; } export const MetricViewComponents: Record> = { - chart: MetricViewChartController, + chart: MetricViewChart, results: MetricViewResults, file: MetricViewFile }; diff --git a/web/src/layouts/ChatLayout/ChatLayoutContext/ChatLayoutContext.tsx b/web/src/layouts/ChatLayout/ChatLayoutContext/ChatLayoutContext.tsx index c7b51bac4..c35570569 100644 --- a/web/src/layouts/ChatLayout/ChatLayoutContext/ChatLayoutContext.tsx +++ b/web/src/layouts/ChatLayout/ChatLayoutContext/ChatLayoutContext.tsx @@ -48,13 +48,20 @@ export const useChatLayoutContext = ({ appSplitterRef }: UseLayoutConfigProps) = const onCollapseFileClick = useLayoutCollapse({ onSetSelectedFile }); - const { selectedFileView, selectedFileViewSecondary, onSetFileView, closeSecondaryView } = - useLayoutConfig({ - selectedFileId: selectedFile?.id, - selectedFileType: selectedFile?.type - }); + const { + selectedFileView, + selectedFileViewRenderSecondary, + selectedFileViewSecondary, + onSetFileView, + closeSecondaryView + } = useLayoutConfig({ + selectedFileId: selectedFile?.id, + selectedFileType: selectedFile?.type, + isVersionHistoryMode + }); return { + selectedFileViewRenderSecondary, selectedFileView, selectedFileViewSecondary, onSetFileView, diff --git a/web/src/layouts/ChatLayout/ChatLayoutContext/useLayoutConfig/interfaces.ts b/web/src/layouts/ChatLayout/ChatLayoutContext/useLayoutConfig/interfaces.ts index 99117cb74..907810c19 100644 --- a/web/src/layouts/ChatLayout/ChatLayoutContext/useLayoutConfig/interfaces.ts +++ b/web/src/layouts/ChatLayout/ChatLayoutContext/useLayoutConfig/interfaces.ts @@ -3,7 +3,15 @@ export interface FileConfig { fileViewConfig?: FileViewConfig; } -export type FileViewConfig = Partial>; +export type FileViewConfig = Partial< + Record< + FileView, + { + secondaryView: FileViewSecondary; + renderView?: boolean; //this is really just used for metric because it has a vertical view and we don't want to render a right panel. undefined defaults to true + } + > +>; export type FileView = | MetricFileView @@ -21,5 +29,7 @@ export type ValueFileView = 'file'; export type DatasetFileView = 'file'; export type CollectionFileView = 'file' | 'results'; export type ReasoningFileView = 'reasoning'; -export type FileViewSecondary = null | MetricFileViewSecondary; -export type MetricFileViewSecondary = 'chart-edit' | 'sql-edit'; + +export type MetricFileViewSecondary = 'chart-edit' | 'sql-edit' | 'version-history'; +export type DashboardFileViewSecondary = 'version-history'; +export type FileViewSecondary = null | MetricFileViewSecondary | DashboardFileViewSecondary; diff --git a/web/src/layouts/ChatLayout/ChatLayoutContext/useLayoutConfig/useLayoutConfig.ts b/web/src/layouts/ChatLayout/ChatLayoutContext/useLayoutConfig/useLayoutConfig.ts index 8938ca430..718267bcb 100644 --- a/web/src/layouts/ChatLayout/ChatLayoutContext/useLayoutConfig/useLayoutConfig.ts +++ b/web/src/layouts/ChatLayout/ChatLayoutContext/useLayoutConfig/useLayoutConfig.ts @@ -1,17 +1,19 @@ 'use client'; import { FileType } from '@/api/asset_interfaces'; -import { useMemo, useState } from 'react'; +import { useLayoutEffect, useMemo, useState } from 'react'; import { FileConfig, FileView, FileViewConfig, FileViewSecondary } from './interfaces'; import { useMemoizedFn } from '@/hooks'; import { create } from 'mutative'; export const useLayoutConfig = ({ selectedFileId, - selectedFileType + selectedFileType, + isVersionHistoryMode }: { selectedFileId: string | undefined; selectedFileType: FileType | undefined; + isVersionHistoryMode: boolean; }) => { const [fileViews, setFileViews] = useState>({}); @@ -32,15 +34,25 @@ export const useLayoutConfig = ({ return selectedFileViewConfig?.[selectedFileView]?.secondaryView ?? null; }, [selectedFileViewConfig, selectedFileId, selectedFileView]); + const selectedFileViewRenderSecondary: boolean = useMemo(() => { + if (!selectedFileId || !selectedFileViewConfig || !selectedFileView) return false; + if (selectedFileViewConfig?.[selectedFileView]?.secondaryView) { + return selectedFileViewConfig?.[selectedFileView]?.renderView !== false; + } + return false; + }, [selectedFileViewConfig]); + const onSetFileView = useMemoizedFn( ({ fileView, fileId, - secondaryView + secondaryView, + renderView }: { fileView?: FileView; fileId?: string; secondaryView?: FileViewSecondary; + renderView?: boolean; }) => { const id = fileId ?? selectedFileId; if (!id) return; @@ -60,7 +72,8 @@ export const useLayoutConfig = ({ ...newFileConfig.fileViewConfig, [usedFileView]: { ...newFileConfig.fileViewConfig?.[usedFileView], - secondaryView + secondaryView, + renderView } }; } @@ -80,9 +93,25 @@ export const useLayoutConfig = ({ }); }); + useLayoutEffect(() => { + if ( + isVersionHistoryMode && + selectedFileId && + (selectedFileType === 'metric' || selectedFileType === 'dashboard') + ) { + const fileView = selectedFileType === 'metric' ? 'chart' : 'dashboard'; + onSetFileView({ + fileId: selectedFileId, + fileView, + secondaryView: 'version-history' + }); + } + }, [isVersionHistoryMode, selectedFileId]); + return { selectedFileView, selectedFileViewSecondary, + selectedFileViewRenderSecondary, onSetFileView, closeSecondaryView }; diff --git a/web/src/layouts/ChatLayout/ChatLayoutContext/useSelectedFile/useSelectedFile.ts b/web/src/layouts/ChatLayout/ChatLayoutContext/useSelectedFile/useSelectedFile.ts index df42e0dd4..d4b3a7573 100644 --- a/web/src/layouts/ChatLayout/ChatLayoutContext/useSelectedFile/useSelectedFile.ts +++ b/web/src/layouts/ChatLayout/ChatLayoutContext/useSelectedFile/useSelectedFile.ts @@ -44,6 +44,13 @@ export const useSelectedFile = ({ return false; }, [selectedFile?.type, metricVersionNumber, dashboardVersionNumber]); + console.log( + 'isVersionHistoryMode', + isVersionHistoryMode, + metricVersionNumber, + dashboardVersionNumber + ); + const [renderViewLayoutKey, setRenderViewLayoutKey] = useState( selectedLayout || 'chat' ); @@ -96,7 +103,14 @@ export const useSelectedFile = ({ renderViewLayoutKey, setRenderViewLayoutKey }), - [onSetSelectedFile, selectedFile, selectedLayout, chatId, renderViewLayoutKey] + [ + onSetSelectedFile, + isVersionHistoryMode, + selectedFile, + selectedLayout, + chatId, + renderViewLayoutKey + ] ); }; diff --git a/web/src/layouts/ChatLayout/FileContainer/FileContainer.tsx b/web/src/layouts/ChatLayout/FileContainer/FileContainer.tsx index ab285ed8c..25f343c00 100644 --- a/web/src/layouts/ChatLayout/FileContainer/FileContainer.tsx +++ b/web/src/layouts/ChatLayout/FileContainer/FileContainer.tsx @@ -1,15 +1,81 @@ -import React from 'react'; +'use client'; + +import React, { useMemo, useRef } from 'react'; import { FileContainerHeader } from './FileContainerHeader'; -import { AppPageLayout } from '@/components/ui/layouts'; +import { AppPageLayout, AppSplitter, AppSplitterRef } from '@/components/ui/layouts'; +import { useChatLayoutContextSelector } from '../ChatLayoutContext'; +import { createAutoSaveId } from '@/components/ui/layouts/AppSplitter/helper'; +import Cookies from 'js-cookie'; +import { useMemoizedFn, useUpdateLayoutEffect } from '@/hooks'; interface FileContainerProps { children: React.ReactNode; } +const defaultOpenLayout: [string, string] = ['auto', '310px']; +const defaulClosedLayout: [string, string] = ['auto', '0px']; +const autoSaveId = 'file-container-splitter'; + export const FileContainer: React.FC = ({ children }) => { + const appSplitterRef = useRef(null); + + const selectedFileViewSecondary = useChatLayoutContextSelector( + (x) => x.selectedFileViewSecondary + ); + const selectedFileViewRenderSecondary = useChatLayoutContextSelector( + (x) => x.selectedFileViewRenderSecondary + ); + const isOpenSecondary = selectedFileViewRenderSecondary; + + const secondaryLayoutDimensions: [string, string] = useMemo(() => { + const cookieKey = createAutoSaveId(autoSaveId); + const cookieValue = Cookies.get(cookieKey); + if (cookieValue) { + try { + const parsedValue = JSON.parse(cookieValue) as string[]; + if (!parsedValue?.some((item) => item === 'auto')) { + return parsedValue as [string, string]; + } + } catch (error) { + // + } + } + return defaultOpenLayout as [string, string]; + }, []); + + const defaultLayout: [string, string] = useMemo(() => { + if (isOpenSecondary) { + return secondaryLayoutDimensions; + } + return defaulClosedLayout; + }, []); + + const animateOpenSplitter = useMemoizedFn((side: 'open' | 'closed') => { + if (side === 'open') { + appSplitterRef.current?.animateWidth(defaultOpenLayout[1], 'right'); + } else { + appSplitterRef.current?.animateWidth(defaulClosedLayout[1], 'right'); + } + }); + + useUpdateLayoutEffect(() => { + animateOpenSplitter(isOpenSecondary ? 'open' : 'closed'); + }, [isOpenSecondary]); + return ( }> - {children} + Right {selectedFileViewSecondary}} + allowResize={selectedFileViewRenderSecondary} + preserveSide={'right'} + rightPanelMinSize={250} + rightPanelMaxSize={385} + /> ); }; diff --git a/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/FileContainerVersionHistory.tsx b/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/FileContainerVersionHistory.tsx index 3d0897552..b24349061 100644 --- a/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/FileContainerVersionHistory.tsx +++ b/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/FileContainerVersionHistory.tsx @@ -1,16 +1,17 @@ import { Button } from '@/components/ui/buttons'; import { ArrowLeft, History } from '@/components/ui/icons'; -import React, { useMemo } from 'react'; +import React, { useMemo, useTransition } from 'react'; import { useChatLayoutContextSelector } from '../../ChatLayoutContext'; import { useGetMetric } from '@/api/buster_rest/metrics'; import last from 'lodash/last'; import { useGetDashboard } from '@/api/buster_rest/dashboards'; import { useAppLayoutContextSelector } from '@/context/BusterAppLayout'; import { useMemoizedFn } from '@/hooks'; +import { timeout } from '@/lib'; export const FileContainerVersionHistory = React.memo(() => { return ( -
+
@@ -38,6 +39,7 @@ const DisplayVersionHistory = React.memo(() => { ); const versionInfo = useMemo(() => { + if (!metric?.version_number && !dashboard?.version_number) return null; if (type === 'metric') { return { isCurrent: metric?.version_number === metric?.latestVersion?.version_number, @@ -67,10 +69,16 @@ const DisplayVersionHistory = React.memo(() => { DisplayVersionHistory.displayName = 'DisplayVersionHistory'; const ExitVersionHistoryButton = React.memo(() => { + const [isPending, startTransition] = useTransition(); const onChangeQueryParams = useAppLayoutContextSelector((x) => x.onChangeQueryParams); + const closeSecondaryView = useChatLayoutContextSelector((x) => x.closeSecondaryView); - const removeVersionHistoryQueryParams = useMemoizedFn(() => { - onChangeQueryParams({ metric_version_number: null, dashboard_version_number: null }); + const removeVersionHistoryQueryParams = useMemoizedFn(async () => { + closeSecondaryView(); + await timeout(250); + startTransition(() => { + onChangeQueryParams({ metric_version_number: null, dashboard_version_number: null }); + }); }); return ( diff --git a/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderSegment.tsx b/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderSegment.tsx index 201b6f82f..44d4224d4 100644 --- a/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderSegment.tsx +++ b/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/MetricContainerHeaderSegment.tsx @@ -17,7 +17,8 @@ export const MetricContainerHeaderSegment: React.FC = const onSetFileView = useChatLayoutContextSelector((x) => x.onSetFileView); const onChange = useMemoizedFn((fileView: SegmentedItem) => { - onSetFileView({ fileView: fileView.value }); + const renderView = fileView.value === 'results' ? false : true; + onSetFileView({ fileView: fileView.value, renderView }); }); return ( diff --git a/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/interfaces.ts b/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/interfaces.ts index 6f7579277..db8c88953 100644 --- a/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/interfaces.ts +++ b/web/src/layouts/ChatLayout/FileContainer/FileContainerHeader/interfaces.ts @@ -1,10 +1,10 @@ import { FileView } from '../../ChatLayoutContext/useLayoutConfig'; -export interface FileContainerSegmentProps { +export type FileContainerSegmentProps = { selectedFileView: FileView | undefined; selectedFileId: string | undefined; -} +}; -export interface FileContainerButtonsProps { +export type FileContainerButtonsProps = { selectedFileView: FileView | undefined; -} +}; diff --git a/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/FileContainerSecondary.tsx b/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/FileContainerSecondary.tsx new file mode 100644 index 000000000..636e5021f --- /dev/null +++ b/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/FileContainerSecondary.tsx @@ -0,0 +1,31 @@ +import type { FileType } from '@/api/asset_interfaces/chat'; +import type { FileContainerSecondaryProps } from './interfaces'; +import type { + DashboardFileViewSecondary, + MetricFileViewSecondary +} from '../../ChatLayoutContext/useLayoutConfig/interfaces'; + +const MetricSecondaryRecord: Record< + MetricFileViewSecondary, + React.FC +> = { + 'chart-edit': () => null, + 'sql-edit': () => null, + 'version-history': () => null +}; + +const DashboardSecondaryRecord: Record< + DashboardFileViewSecondary, + React.FC +> = { + 'version-history': () => null +}; + +const SelectedFileSecondaryRecord: Record< + FileType, + Record> +> = { + metric: MetricSecondaryRecord, + dashboard: DashboardSecondaryRecord, + reasoning: {} +}; diff --git a/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/index.ts b/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/index.ts new file mode 100644 index 000000000..ab7cc6f67 --- /dev/null +++ b/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/index.ts @@ -0,0 +1 @@ +export * from './FileContainerSecondary'; diff --git a/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/interfaces.ts b/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/interfaces.ts new file mode 100644 index 000000000..f56543cea --- /dev/null +++ b/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/interfaces.ts @@ -0,0 +1,6 @@ +import type { FileViewSecondary } from '@/layouts/ChatLayout/ChatLayoutContext/useLayoutConfig'; + +export type FileContainerSecondaryProps = { + selectedFileId: string | undefined; + selectedFileViewSecondary: FileViewSecondary | undefined; +}; diff --git a/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/secondaryPanelsConfig/allConfigs.tsx b/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/secondaryPanelsConfig/allConfigs.tsx new file mode 100644 index 000000000..0c0c43fa9 --- /dev/null +++ b/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/secondaryPanelsConfig/allConfigs.tsx @@ -0,0 +1,14 @@ +import type { FileType } from '@/api/asset_interfaces/chat'; +import type { FileContainerSecondaryProps } from '../interfaces'; +import React from 'react'; +import { MetricSecondaryRecord } from './metricPanels'; +import { DashboardSecondaryRecord } from './dashboardPanels'; + +export const SelectedFileSecondaryRecord: Record< + FileType, + Record> +> = { + metric: MetricSecondaryRecord, + dashboard: DashboardSecondaryRecord, + reasoning: {} +}; diff --git a/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/secondaryPanelsConfig/dashboardPanels.tsx b/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/secondaryPanelsConfig/dashboardPanels.tsx new file mode 100644 index 000000000..39fd5c21c --- /dev/null +++ b/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/secondaryPanelsConfig/dashboardPanels.tsx @@ -0,0 +1,21 @@ +import { type DashboardFileViewSecondary } from '@/layouts/ChatLayout/ChatLayoutContext/useLayoutConfig'; +import type { FileContainerSecondaryProps } from '../interfaces'; +import dynamic from 'next/dynamic'; +import { loading } from './loading'; + +const VersionHistoryPanel = dynamic( + () => + import('@/components/features/versionHistory/VersionHistoryPanel').then( + (x) => x.VersionHistoryPanel + ), + { loading } +); + +export const DashboardSecondaryRecord: Record< + DashboardFileViewSecondary, + React.FC +> = { + 'version-history': ({ selectedFileId }) => ( + + ) +}; diff --git a/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/secondaryPanelsConfig/index.ts b/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/secondaryPanelsConfig/index.ts new file mode 100644 index 000000000..bdb7d10dd --- /dev/null +++ b/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/secondaryPanelsConfig/index.ts @@ -0,0 +1 @@ +export * from './allConfigs'; diff --git a/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/secondaryPanelsConfig/loading.tsx b/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/secondaryPanelsConfig/loading.tsx new file mode 100644 index 000000000..5c06cb184 --- /dev/null +++ b/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/secondaryPanelsConfig/loading.tsx @@ -0,0 +1,9 @@ +import { CircleSpinnerLoaderContainer } from '@/components/ui/loaders/CircleSpinnerLoaderContainer'; + +export const loading = () => { + return ( +
+ +
+ ); +}; diff --git a/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/secondaryPanelsConfig/metricPanels.tsx b/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/secondaryPanelsConfig/metricPanels.tsx new file mode 100644 index 000000000..68bd27ea0 --- /dev/null +++ b/web/src/layouts/ChatLayout/FileContainer/FileContainerSecondary/secondaryPanelsConfig/metricPanels.tsx @@ -0,0 +1,34 @@ +import dynamic from 'next/dynamic'; +import { loading } from './loading'; +import type { MetricFileViewSecondary } from '@/layouts/ChatLayout/ChatLayoutContext/useLayoutConfig/interfaces'; +import type { FileContainerSecondaryProps } from '../interfaces'; + +const MetricEditController = dynamic( + () => + import('@/controllers/MetricController/MetricViewChart/MetricEditController').then( + (x) => x.MetricEditController + ), + { loading } +); +const VersionHistoryPanel = dynamic( + () => + import('@/components/features/versionHistory/VersionHistoryPanel').then( + (x) => x.VersionHistoryPanel + ), + { loading } +); +const MetricViewResults = dynamic( + () => import('@/controllers/MetricController/MetricViewResults').then((x) => x.MetricViewResults), + { loading } +); + +export const MetricSecondaryRecord: Record< + MetricFileViewSecondary, + React.FC +> = { + 'chart-edit': ({ selectedFileId }) => , + 'sql-edit': ({ selectedFileId }) => , + 'version-history': ({ selectedFileId }) => ( + + ) +};