diff --git a/src/components/ui/PropertiesDrawer/PropertiesDrawer.tsx b/src/components/ui/PropertiesDrawer/PropertiesDrawer.tsx index 4a98b61c..1e017e3a 100644 --- a/src/components/ui/PropertiesDrawer/PropertiesDrawer.tsx +++ b/src/components/ui/PropertiesDrawer/PropertiesDrawer.tsx @@ -10,6 +10,7 @@ import { import toast from 'react-hot-toast'; import { HiOutlineDocument, HiOutlineDuplicate, HiX } from 'react-icons/hi'; import { HiOutlineFolder } from 'react-icons/hi2'; +import { useLocation } from 'react-router'; import PermissionsTable from '@/components/ui/PropertiesDrawer/PermissionsTable'; import OverviewTable from '@/components/ui/PropertiesDrawer/OverviewTable'; @@ -80,8 +81,10 @@ export default function PropertiesDrawer({ setShowPermissionsDialog, setShowConvertFileDialog }: PropertiesDrawerProps): JSX.Element { + const location = useLocation(); const [showDataLinkDialog, setShowDataLinkDialog] = React.useState(false); + const [activeTab, setActiveTab] = React.useState('overview'); const { fileBrowserState } = useFileBrowserContext(); const { pathPreference, areDataLinksAutomatic } = usePreferencesContext(); @@ -95,6 +98,13 @@ export default function PropertiesDrawer({ handleDeleteDataLink } = useDataToolLinks(setShowDataLinkDialog); + // Set active tab to 'convert' when navigating from jobs page + React.useEffect(() => { + if (location.state?.openConvertTab) { + setActiveTab('convert'); + } + }, [location.state]); + const fullPath = getPreferredPathForDisplay( pathPreference, fileBrowserState.currentFileSharePath, @@ -145,8 +155,9 @@ export default function PropertiesDrawer({ {fileBrowserState.propertiesTarget ? ( ) => { + e.preventDefault(); + const result = await setLayoutWithPropertiesOpen(); + if (!result.success) { + toast.error(`Error opening properties for file: ${result.error}`); + return; + } + navigate(makeBrowseLink(item.fsp_name, item.path), { + state: { openConvertTab: true } + }); + }; + return (
- + {displayPath}
diff --git a/src/components/ui/widgets/FgLink.tsx b/src/components/ui/widgets/FgLink.tsx index 582e07d2..1b82fb91 100644 --- a/src/components/ui/widgets/FgLink.tsx +++ b/src/components/ui/widgets/FgLink.tsx @@ -9,6 +9,7 @@ type StyledLinkProps = { readonly target?: string; readonly rel?: string; readonly textSize?: 'default' | 'large' | 'small'; + readonly onClick?: (e: React.MouseEvent) => void; }; export function FgStyledLink({ @@ -17,7 +18,8 @@ export function FgStyledLink({ className = '', target, rel, - textSize = 'default' + textSize = 'default', + onClick }: StyledLinkProps) { const baseClasses = 'text-primary-light hover:underline focus:underline'; const textClasses = { @@ -29,6 +31,7 @@ export function FgStyledLink({ return ( Promise; + setLayoutWithPropertiesOpen: () => Promise>; loadingRecentlyViewedFolders: boolean; isLayoutLoadedFromDB: boolean; handleContextMenuFavorite: () => Promise>; @@ -223,6 +229,34 @@ export const PreferencesProvider = ({ setLayout(layout); }; + const setLayoutWithPropertiesOpen = async (): Promise> => { + try { + // Keep sidebar in new layout if it is currently present + const hasSidebar = layout.includes('sidebar'); + + const layoutKey = hasSidebar + ? WITH_PROPERTIES_AND_SIDEBAR + : ONLY_PROPERTIES; + + const layoutSizes = hasSidebar ? [24, 50, 26] : [75, 25]; + + const newLayout = { + [LAYOUT_NAME]: { + [layoutKey]: { + expandToSizes: {}, + layout: layoutSizes + } + } + }; + const newLayoutString = JSON.stringify(newLayout); + await savePreferencesToBackend('layout', newLayoutString); + setLayout(newLayoutString); + return createSuccess(undefined); + } catch (error) { + return handleError(error); + } + }; + const handlePathPreferenceSubmit = React.useCallback( async ( localPathPreference: ['linux_path'] | ['windows_path'] | ['mac_path'] @@ -750,6 +784,7 @@ export const PreferencesProvider = ({ recentlyViewedFolders, layout, handleUpdateLayout, + setLayoutWithPropertiesOpen, loadingRecentlyViewedFolders, isLayoutLoadedFromDB, handleContextMenuFavorite diff --git a/src/hooks/useLayoutPrefs.ts b/src/hooks/useLayoutPrefs.ts index 2a6e5fe5..afe36a4d 100644 --- a/src/hooks/useLayoutPrefs.ts +++ b/src/hooks/useLayoutPrefs.ts @@ -3,6 +3,14 @@ import React from 'react'; import { usePreferencesContext } from '@/contexts/PreferencesContext'; import { useCentralServerHealthContext } from '@/contexts/CentralServerHealthContext'; import logger from '@/logger'; +import { + LAYOUT_NAME, + WITH_PROPERTIES_AND_SIDEBAR, + ONLY_SIDEBAR, + ONLY_PROPERTIES, + DEFAULT_LAYOUT, + DEFAULT_LAYOUT_SMALL_SCREENS +} from '@/constants/layoutConstants'; /** * Custom hook that provides storage interface for react-resizable-panels * with debounced updates to reduce API calls when resizing panels @@ -12,20 +20,6 @@ import logger from '@/logger'; const DEBOUNCE_MS = 500; -// Name is set by the autosaveId prop in PanelGroup -const LAYOUT_NAME = 'react-resizable-panels:layout'; -// Confusingly, the names are in alphabetical order, but the order of the sizes is set by the order prop -// in the respective Panel components -const DEFAULT_LAYOUT = - '{"main,properties,sidebar":{"expandToSizes":{},"layout":[24,50,24]}}'; -const DEFAULT_LAYOUT_SMALL_SCREENS = - '{"main":{"expandToSizes":{},"layout":[100]}}'; - -// Layout keys for the two possible panel combinations -const WITH_PROPERTIES_AND_SIDEBAR = 'main,properties,sidebar'; -const ONLY_SIDEBAR = 'main,sidebar'; -const ONLY_PROPERTIES = 'main,properties'; - export default function useLayoutPrefs() { const [showPropertiesDrawer, setShowPropertiesDrawer] = React.useState(false);