Files
factorio-clusterio/packages/web_ui/src/util/useRowNavigation.ts
T
bbassieandClaude Opus 4.8 f04fc68513 Use real links for navigation so they open in new tabs
In-app navigation was done with JS onClick -> navigate() handlers instead of
real <a href> anchors, so the browser's right-click "Open in new tab" (and
middle-click / ctrl-click) was unavailable. (closes #929)

- Sidebar nav items and the account "user" entry now render their label as the
  existing Link component (a real anchor via react-router useHref), keeping the
  Menu onClick for plain left-clicks; stopPropagation avoids double navigation.
- The "back to instances" alert action becomes a Link.
- Table rows (Hosts, Roles, Plugins, Instances, Users, the user instance-stats
  table, Mod Packs): the name cell becomes a real Link (color inherit, so it
  looks unchanged) which carries the right-click context menu, and a new
  useRowNavigation hook handles the whole row — left-click navigates in place,
  middle-click / ctrl-click open the target in a new tab. The hook ignores
  clicks landing on a real link inside the row so the anchor handles those.

Genuine actions (download/delete/modify/logout), post-create navigation and
external links are left as-is.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 23:52:15 +00:00

53 lines
1.7 KiB
TypeScript

import type React from "react";
import { useNavigate } from "react-router-dom";
/** Resolve an in-app path to a full path including the router basename. */
function resolvePath(to: string): string {
const base = webRoot.replace(/\/$/, "");
return base + to;
}
function isInsideLink(target: EventTarget | null): boolean {
return target instanceof HTMLElement && target.closest("a") !== null;
}
/**
* Navigation handlers for a whole table row that also support "open in new
* tab": left-click navigates in place, middle-click or ctrl/cmd-click opens the
* target in a new tab. Spread the result into the object returned from antd's
* `onRow`, e.g. `onRow={record => rowNav(`/hosts/${record.id}/view`)}`. Clicks
* that land on a real link inside the row are ignored so the anchor handles
* them (and shows the native context menu / new-tab affordances itself).
*/
export default function useRowNavigation() {
const navigate = useNavigate();
return function rowNavigation(to: string): React.HTMLAttributes<HTMLElement> {
return {
style: { cursor: "pointer" },
onClick: (event) => {
if (event.defaultPrevented || isInsideLink(event.target)) {
return;
}
if (event.ctrlKey || event.metaKey || event.shiftKey) {
window.open(resolvePath(to), "_blank", "noopener");
} else {
navigate(to);
}
},
onAuxClick: (event) => {
// Middle click opens the row in a new tab.
if (event.button === 1 && !isInsideLink(event.target)) {
event.preventDefault();
window.open(resolvePath(to), "_blank", "noopener");
}
},
onMouseDown: (event) => {
// Suppress the middle-click autoscroll cursor.
if (event.button === 1) {
event.preventDefault();
}
},
};
};
}