[Feat] UI - Add Open in New Tab on leftnav Bar (#22731)
* Add minimal dev_config.yaml for proxy development Co-authored-by: Ishaan Jaff <ishaan-jaff@users.noreply.github.com> * feat(ui): wrap left nav items in <a> tags for open-in-new-tab support Nav items are now rendered as <a> elements with proper href attributes, enabling right-click → 'Open in new tab', Ctrl/Cmd+click, and middle-click to open any sidebar page in a new browser tab. Normal clicks continue to use SPA navigation (no full page reload). Applied to both leftnav.tsx (query-param routing) and Sidebar2.tsx (Next.js file-based routing). Co-authored-by: Ishaan Jaff <ishaan-jaff@users.noreply.github.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Ishaan Jaff <ishaan-jaff@users.noreply.github.com>
This commit is contained in:
parent
120201049e
commit
8baa3ae8cb
13
dev_config.yaml
Normal file
13
dev_config.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
model_list:
|
||||
- model_name: fake-openai-endpoint
|
||||
litellm_params:
|
||||
model: openai/fake-model
|
||||
api_key: fake-key
|
||||
api_base: https://exampleopenaiendpoint-production.up.railway.app/
|
||||
|
||||
general_settings:
|
||||
master_key: sk-1234
|
||||
|
||||
litellm_settings:
|
||||
drop_params: True
|
||||
telemetry: False
|
||||
@ -374,6 +374,27 @@ const Sidebar2: React.FC<SidebarProps> = ({ accessToken, userRole, defaultSelect
|
||||
router.push(href);
|
||||
};
|
||||
|
||||
// Wrap label in <a> so every nav item supports right-click → "Open in new tab"
|
||||
// and Ctrl/Cmd+click to open in a new tab, while preserving SPA navigation for normal clicks.
|
||||
const renderNavLink = (label: string, page: string): React.ReactNode => {
|
||||
const href = toHref(page);
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
onClick={(e) => {
|
||||
if (e.metaKey || e.ctrlKey || e.shiftKey || e.button === 1) {
|
||||
e.stopPropagation();
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
}}
|
||||
style={{ color: "inherit", textDecoration: "none" }}
|
||||
>
|
||||
{label}
|
||||
</a>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Layout style={{ minHeight: "100vh" }}>
|
||||
<Sider
|
||||
@ -412,11 +433,11 @@ const Sidebar2: React.FC<SidebarProps> = ({ accessToken, userRole, defaultSelect
|
||||
items={filteredMenuItems.map((item) => ({
|
||||
key: item.key,
|
||||
icon: item.icon,
|
||||
label: item.label,
|
||||
label: renderNavLink(item.label, item.page),
|
||||
children: item.children?.map((child) => ({
|
||||
key: child.key,
|
||||
icon: child.icon,
|
||||
label: child.label,
|
||||
label: renderNavLink(child.label, child.page),
|
||||
onClick: () => goTo(child.page),
|
||||
})),
|
||||
onClick: !item.children ? () => goTo(item.page) : undefined,
|
||||
|
||||
@ -374,6 +374,46 @@ const Sidebar: React.FC<SidebarProps> = ({ setPage, defaultSelectedKey, collapse
|
||||
setPage(page);
|
||||
};
|
||||
|
||||
// Wrap label in <a> so every nav item supports right-click → "Open in new tab"
|
||||
// and Ctrl/Cmd+click to open in a new tab, while preserving SPA navigation for normal clicks.
|
||||
const renderNavLink = (
|
||||
label: React.ReactNode,
|
||||
page: string,
|
||||
externalUrl?: string,
|
||||
): React.ReactNode => {
|
||||
if (externalUrl) {
|
||||
return (
|
||||
<a
|
||||
href={externalUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
style={{ color: "inherit", textDecoration: "none" }}
|
||||
>
|
||||
{label}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
params.set("page", page);
|
||||
const href = `?${params.toString()}`;
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
onClick={(e) => {
|
||||
if (e.metaKey || e.ctrlKey || e.shiftKey || e.button === 1) {
|
||||
e.stopPropagation();
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
}}
|
||||
style={{ color: "inherit", textDecoration: "none" }}
|
||||
>
|
||||
{label}
|
||||
</a>
|
||||
);
|
||||
};
|
||||
|
||||
// Filter items based on user role and enabled pages for internal users
|
||||
const filterItemsByRole = (items: MenuItem[]): MenuItem[] => {
|
||||
const isAdmin = isAdminRole(userRole);
|
||||
@ -469,11 +509,11 @@ const Sidebar: React.FC<SidebarProps> = ({ setPage, defaultSelectedKey, collapse
|
||||
children: filteredItems.map((item) => ({
|
||||
key: item.key,
|
||||
icon: item.icon,
|
||||
label: item.label,
|
||||
label: renderNavLink(item.label, item.page, item.external_url),
|
||||
children: item.children?.map((child) => ({
|
||||
key: child.key,
|
||||
icon: child.icon,
|
||||
label: child.label,
|
||||
label: renderNavLink(child.label, child.page, child.external_url),
|
||||
onClick: () => {
|
||||
if (child.external_url) {
|
||||
window.open(child.external_url, "_blank");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user