diff --git a/src/frontend/src/components/panels/PanelGroup.tsx b/src/frontend/src/components/panels/PanelGroup.tsx index 17e19e8544..e7dd751cf3 100644 --- a/src/frontend/src/components/panels/PanelGroup.tsx +++ b/src/frontend/src/components/panels/PanelGroup.tsx @@ -1,6 +1,8 @@ import { ActionIcon, Divider, + Group, + Loader, Paper, Stack, Tabs, @@ -78,7 +80,7 @@ function BasePanelGroup({ const [expanded, setExpanded] = useState(true); // Hook to load plugins for this panel - const pluginPanels = usePluginPanels({ + const pluginPanelSet = usePluginPanels({ model: model, instance: instance, id: id @@ -89,7 +91,7 @@ function BasePanelGroup({ const _panels = [...panels]; // Add plugin panels - pluginPanels?.forEach((panel) => { + pluginPanelSet.panels?.forEach((panel) => { let panelKey = panel.name; // Check if panel with this name already exists @@ -107,7 +109,7 @@ function BasePanelGroup({ }); return _panels; - }, [panels, pluginPanels]); + }, [panels, pluginPanelSet]); const activePanels = useMemo( () => allPanels.filter((panel) => !panel.hidden && !panel.disabled), @@ -188,20 +190,23 @@ function BasePanelGroup({ ) )} {collapsible && ( - setExpanded(!expanded)} - variant='transparent' - size='md' - > - {expanded ? ( - - ) : ( - - )} - + + setExpanded(!expanded)} + variant='transparent' + size='md' + > + {expanded ? ( + + ) : ( + + )} + + {pluginPanelSet.isLoading && } + )} {allPanels.map( diff --git a/src/frontend/src/hooks/UsePluginPanels.tsx b/src/frontend/src/hooks/UsePluginPanels.tsx index d7491520d8..f0d798c215 100644 --- a/src/frontend/src/hooks/UsePluginPanels.tsx +++ b/src/frontend/src/hooks/UsePluginPanels.tsx @@ -1,4 +1,4 @@ -import { useQuery } from '@tanstack/react-query'; +import { type UseQueryResult, useQuery } from '@tanstack/react-query'; import { useMemo } from 'react'; import { api } from '../App'; @@ -35,6 +35,13 @@ export type PluginPanelContext = InvenTreeContext & { */ export type PluginPanelType = PanelType & { pluginName: string; + isLoading: boolean; +}; + +export type PluginPanelSet = { + panels: PluginPanelType[]; + query: UseQueryResult; + isLoading: boolean; }; export function usePluginPanels({ @@ -45,7 +52,7 @@ export function usePluginPanels({ instance?: any; model?: ModelType | string; id?: string | number | null; -}): PluginPanelType[] { +}): PluginPanelSet { const globalSettings = useGlobalSettingsState(); const pluginPanelsEnabled: boolean = useMemo( @@ -54,7 +61,7 @@ export function usePluginPanels({ ); // API query to fetch initial information on available plugin panels - const { data: pluginData } = useQuery({ + const pluginQuery = useQuery({ enabled: pluginPanelsEnabled && !!model && id !== undefined, queryKey: ['custom-plugin-panels', model, id], queryFn: async () => { @@ -95,7 +102,7 @@ export function usePluginPanels({ const pluginPanels: PluginPanelType[] = useMemo(() => { return ( - pluginData?.map((props: PluginUIFeature) => { + pluginQuery?.data?.map((props: PluginUIFeature) => { const iconName: string = props?.icon || 'ti:plug:outline'; const pluginContext: any = { @@ -117,7 +124,15 @@ export function usePluginPanels({ }; }) ?? [] ); - }, [pluginData, contextData]); + }, [pluginQuery.data, contextData]); - return pluginPanels; + const panelSet: PluginPanelSet = useMemo(() => { + return { + panels: pluginPanels, + isLoading: pluginQuery.isLoading || pluginQuery.isFetching, + query: pluginQuery + }; + }, [pluginPanels, pluginQuery]); + + return panelSet; }