2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-05-15 11:33:08 +00:00

[PUI] Open links in new window (#7354)

* Breadcrumbs can be opened in a new tab

* Support tab nav for top header items

* Open panel tab in new window
This commit is contained in:
Oliver 2024-05-27 21:31:08 +10:00 committed by GitHub
parent b402836dc4
commit 89cea3045a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 40 additions and 17 deletions

View File

@ -10,6 +10,8 @@ import { IconMenu2 } from '@tabler/icons-react';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { navigateToLink } from '../../functions/navigation';
export type Breadcrumb = { export type Breadcrumb = {
name: string; name: string;
url: string; url: string;
@ -57,7 +59,10 @@ export function BreadcrumbList({
return ( return (
<Anchor <Anchor
key={index} key={index}
onClick={() => breadcrumb.url && navigate(breadcrumb.url)} onClick={(event: any) =>
breadcrumb.url &&
navigateToLink(breadcrumb.url, navigate, event)
}
> >
<Text size="sm">{breadcrumb.name}</Text> <Text size="sm">{breadcrumb.name}</Text>
</Anchor> </Anchor>

View File

@ -8,6 +8,7 @@ import { useMatch, useNavigate } from 'react-router-dom';
import { api } from '../../App'; import { api } from '../../App';
import { navTabs as mainNavTabs } from '../../defaults/links'; import { navTabs as mainNavTabs } from '../../defaults/links';
import { ApiEndpoints } from '../../enums/ApiEndpoints'; import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { navigateToLink } from '../../functions/navigation';
import * as classes from '../../main.css'; import * as classes from '../../main.css';
import { apiUrl } from '../../states/ApiState'; import { apiUrl } from '../../states/ApiState';
import { useLocalState } from '../../states/LocalState'; import { useLocalState } from '../../states/LocalState';
@ -141,13 +142,16 @@ function NavTabs() {
tab: classes.tab tab: classes.tab
}} }}
value={tabValue} value={tabValue}
onChange={(value) =>
value == '/' ? navigate('/') : navigate(`/${value}`)
}
> >
<Tabs.List> <Tabs.List>
{mainNavTabs.map((tab) => ( {mainNavTabs.map((tab) => (
<Tabs.Tab value={tab.name} key={tab.name}> <Tabs.Tab
value={tab.name}
key={tab.name}
onClick={(event: any) =>
navigateToLink(`/${tab.name}`, navigate, event)
}
>
{tab.text} {tab.text}
</Tabs.Tab> </Tabs.Tab>
))} ))}

View File

@ -10,15 +10,17 @@ import {
IconLayoutSidebarLeftCollapse, IconLayoutSidebarLeftCollapse,
IconLayoutSidebarRightCollapse IconLayoutSidebarRightCollapse
} from '@tabler/icons-react'; } from '@tabler/icons-react';
import { ReactNode, useEffect, useMemo, useState } from 'react'; import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react';
import { import {
Navigate, Navigate,
Route, Route,
Routes, Routes,
useLocation,
useNavigate, useNavigate,
useParams useParams
} from 'react-router-dom'; } from 'react-router-dom';
import { navigateToLink } from '../../functions/navigation';
import { useLocalState } from '../../states/LocalState'; import { useLocalState } from '../../states/LocalState';
import { Boundary } from '../Boundary'; import { Boundary } from '../Boundary';
import { PlaceholderPanel } from '../items/Placeholder'; import { PlaceholderPanel } from '../items/Placeholder';
@ -52,6 +54,7 @@ function BasePanelGroup({
selectedPanel, selectedPanel,
collapsible = true collapsible = true
}: Readonly<PanelProps>): ReactNode { }: Readonly<PanelProps>): ReactNode {
const location = useLocation();
const navigate = useNavigate(); const navigate = useNavigate();
const { panel } = useParams(); const { panel } = useParams();
@ -72,19 +75,27 @@ function BasePanelGroup({
}, [setLastUsedPanel]); }, [setLastUsedPanel]);
// Callback when the active panel changes // Callback when the active panel changes
function handlePanelChange(panel: string | null) { const handlePanelChange = useCallback(
(panel: string | null, event?: any) => {
if (activePanels.findIndex((p) => p.name === panel) === -1) { if (activePanels.findIndex((p) => p.name === panel) === -1) {
setLastUsedPanel(''); setLastUsedPanel('');
return navigate('../'); return navigate('../');
} }
if (event && (event?.ctrlKey || event?.shiftKey)) {
const url = `${location.pathname}/../${panel}`;
navigateToLink(url, navigate, event);
} else {
navigate(`../${panel}`); navigate(`../${panel}`);
}
// Optionally call external callback hook // Optionally call external callback hook
if (panel && onPanelChange) { if (panel && onPanelChange) {
onPanelChange(panel); onPanelChange(panel);
} }
} },
[activePanels, setLastUsedPanel, navigate, location, onPanelChange]
);
// if the selected panel state changes update the current panel // if the selected panel state changes update the current panel
useEffect(() => { useEffect(() => {
@ -129,6 +140,9 @@ function BasePanelGroup({
hidden={panel.hidden} hidden={panel.hidden}
disabled={panel.disabled} disabled={panel.disabled}
style={{ cursor: panel.disabled ? 'unset' : 'pointer' }} style={{ cursor: panel.disabled ? 'unset' : 'pointer' }}
onClick={(event: any) =>
handlePanelChange(panel.name, event)
}
> >
{expanded && panel.label} {expanded && panel.label}
</Tabs.Tab> </Tabs.Tab>