Top level hortizontal tab can now be loaded using the #tab id in the url

This commit is contained in:
Colin Dawson 2026-01-31 23:46:08 +00:00
parent c95d7b469c
commit c7428be21b
3 changed files with 20 additions and 11 deletions

View File

@ -1,4 +1,5 @@
import React, { useEffect, useState, useCallback, useMemo } from "react"; import React, { useEffect, useState, useCallback, useMemo } from "react";
import { useLocation } from "react-router-dom";
import TabHeader from "./TabHeader"; import TabHeader from "./TabHeader";
interface HorizontalTabsProps { interface HorizontalTabsProps {
@ -10,22 +11,25 @@ const HorizontalTabs: React.FC<HorizontalTabsProps> = ({
children, children,
initialTab, initialTab,
}) => { }) => {
const location = useLocation();
const [activeTab, setActiveTab] = useState<string>(""); const [activeTab, setActiveTab] = useState<string>("");
// Set initial tab on mount // Set initial tab on mount
useEffect(() => { useEffect(() => {
if (children.length > 0) { if (children.length > 0) {
const tabToSelect = initialTab || children[0].props.label; // Check for hash in URL first, then fall back to initialTab prop
const hashTab = location.hash.slice(1); // Remove the # character
const tabToSelect = hashTab || initialTab || children[0].props.id;
setActiveTab(tabToSelect); setActiveTab(tabToSelect);
} }
}, [children, initialTab]); }, [children, initialTab, location.hash]);
const onClickTabItem = useCallback((tab: string) => { const onClickTabItem = useCallback((tab: string) => {
setActiveTab((prev) => (prev !== tab ? tab : prev)); setActiveTab((prev) => (prev !== tab ? tab : prev));
}, []); }, []);
const activeTabChildren = useMemo(() => { const activeTabChildren = useMemo(() => {
const match = children.find((child) => child.props.label === activeTab); const match = children.find((child) => child.props.id === activeTab);
return match ? match.props.children : <></>; return match ? match.props.children : <></>;
}, [children, activeTab]); }, [children, activeTab]);
@ -38,13 +42,13 @@ const HorizontalTabs: React.FC<HorizontalTabsProps> = ({
<div className="horizionalTabs"> <div className="horizionalTabs">
<ul className="tab-list"> <ul className="tab-list">
{children.map((child) => { {children.map((child) => {
const { label } = child.props; const { id, label } = child.props;
return ( return (
<TabHeader <TabHeader
key={label} key={label}
label={label} label={label}
isActive={label === activeTab} isActive={id === activeTab}
onClick={onClickTabItem} onClick={() => onClickTabItem(id)}
/> />
); );
})} })}

View File

@ -1,10 +1,15 @@
import React from "react"; import React from "react";
interface TabProps { interface TabProps {
id?: string;
label: string; label: string;
children: React.ReactNode; children: React.ReactNode;
} }
export default function Tab({ label, children }: TabProps): JSX.Element { export default function Tab({ id, label, children }: TabProps): JSX.Element {
return <div data-tab-label={label}>{children}</div>; return (
<div data-tab-id={id} data-tab-label={label}>
{children}
</div>
);
} }

View File

@ -28,7 +28,7 @@ const DomainsDetails: React.FC<DomainsDetailsProps> = ({ isEditMode }) => {
const tabs: JSX.Element[] = []; const tabs: JSX.Element[] = [];
tabs.push( tabs.push(
<Tab key={1} label={t("General")}> <Tab id="general" key="general" label={t("General")}>
<GeneralTab isEditMode={isEditMode} /> <GeneralTab isEditMode={isEditMode} />
</Tab>, </Tab>,
); );
@ -36,14 +36,14 @@ const DomainsDetails: React.FC<DomainsDetailsProps> = ({ isEditMode }) => {
if (isEditMode) { if (isEditMode) {
if (canViewMailTemplates) { if (canViewMailTemplates) {
tabs.push( tabs.push(
<Tab key={2} label={t("MailTemplates")}> <Tab id="mailTemplates" key="mailTemplates" label={t("MailTemplates")}>
<MailTemplatesTab /> <MailTemplatesTab />
</Tab>, </Tab>,
); );
} }
if (canViewSecurityRoles) { if (canViewSecurityRoles) {
tabs.push( tabs.push(
<Tab key={3} label={t("SecurityRoles")}> <Tab id="securityRoles" key="securityRoles" label={t("SecurityRoles")}>
<SecurityRolesTab initialRoleId={roleId} initialInnerTab={innerTab} /> <SecurityRolesTab initialRoleId={roleId} initialInnerTab={innerTab} />
</Tab>, </Tab>,
); );