mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
Fleet UI: Add route params to host details page (#8673)
This commit is contained in:
parent
fc11c0a06d
commit
a623a6410a
7 changed files with 88 additions and 19 deletions
1
changes/issue-8504-host-details-route-params
Normal file
1
changes/issue-8504-host-details-route-params
Normal file
|
|
@ -0,0 +1 @@
|
|||
- New URL routes for host details page tabs
|
||||
|
|
@ -223,7 +223,7 @@ const WelcomeHost = ({
|
|||
<div className={`${baseClass}__intro`}>
|
||||
<img alt="" src={LaptopMac} />
|
||||
<div className="info">
|
||||
<Link to={PATHS.HOST_DETAILS(host)} className="external-link">
|
||||
<Link to={PATHS.HOST_DETAILS(host.id)} className="external-link">
|
||||
{host.display_name}
|
||||
<img alt="" src={LinkArrow} />
|
||||
</Link>
|
||||
|
|
@ -258,7 +258,7 @@ const WelcomeHost = ({
|
|||
return null;
|
||||
})}
|
||||
{host.policies?.length > 3 && (
|
||||
<Link to={PATHS.HOST_DETAILS(host)} className="external-link">
|
||||
<Link to={PATHS.HOST_DETAILS(host.id)} className="external-link">
|
||||
Go to Host details to see all policies
|
||||
<img alt="" src={LinkArrow} />
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
Cell: (cellProps: ICellProps) => (
|
||||
<LinkCell
|
||||
value={cellProps.cell.value}
|
||||
path={PATHS.HOST_DETAILS(cellProps.row.original)}
|
||||
path={PATHS.HOST_DETAILS(cellProps.row.original.id)}
|
||||
title={lastSeenTime(
|
||||
cellProps.row.original.status,
|
||||
cellProps.row.original.seen_time
|
||||
|
|
|
|||
|
|
@ -68,6 +68,9 @@ const baseClass = "host-details";
|
|||
|
||||
interface IHostDetailsProps {
|
||||
router: InjectedRouter; // v3
|
||||
location: {
|
||||
pathname: string;
|
||||
};
|
||||
params: Params;
|
||||
}
|
||||
|
||||
|
|
@ -84,6 +87,12 @@ interface IHostDiskEncryptionProps {
|
|||
tooltip?: string;
|
||||
}
|
||||
|
||||
interface IHostDetailsSubNavItem {
|
||||
name: string | JSX.Element;
|
||||
title: string;
|
||||
pathname: string;
|
||||
}
|
||||
|
||||
const TAGGED_TEMPLATES = {
|
||||
queryByHostRoute: (hostId: number | undefined | null) => {
|
||||
return `${hostId ? `?host_ids=${hostId}` : ""}`;
|
||||
|
|
@ -92,6 +101,7 @@ const TAGGED_TEMPLATES = {
|
|||
|
||||
const HostDetailsPage = ({
|
||||
router,
|
||||
location: { pathname },
|
||||
params: { host_id },
|
||||
}: IHostDetailsProps): JSX.Element => {
|
||||
const hostIdFromURL = parseInt(host_id, 10);
|
||||
|
|
@ -548,6 +558,48 @@ const HostDetailsPage = ({
|
|||
const statusClassName = classnames("status", `status--${host?.status}`);
|
||||
const failingPoliciesCount = host?.issues.failing_policies_count || 0;
|
||||
|
||||
const hostDetailsSubNav: IHostDetailsSubNavItem[] = [
|
||||
{
|
||||
name: "Details",
|
||||
title: "details",
|
||||
pathname: PATHS.HOST_DETAILS(hostIdFromURL),
|
||||
},
|
||||
{
|
||||
name: "Software",
|
||||
title: "software",
|
||||
pathname: PATHS.HOST_SOFTWARE(hostIdFromURL),
|
||||
},
|
||||
{
|
||||
name: "Schedule",
|
||||
title: "schedule",
|
||||
pathname: PATHS.HOST_SCHEDULE(hostIdFromURL),
|
||||
},
|
||||
{
|
||||
name: (
|
||||
<>
|
||||
{failingPoliciesCount > 0 && (
|
||||
<span className="count">{failingPoliciesCount}</span>
|
||||
)}
|
||||
Policies
|
||||
</>
|
||||
),
|
||||
title: "policies",
|
||||
pathname: PATHS.HOST_POLICIES(hostIdFromURL),
|
||||
},
|
||||
];
|
||||
|
||||
const getTabIndex = (path: string): number => {
|
||||
return hostDetailsSubNav.findIndex((navItem) => {
|
||||
// tab stays highlighted for paths that ends with same pathname
|
||||
return path.endsWith(navItem.pathname);
|
||||
});
|
||||
};
|
||||
|
||||
const navigateToNav = (i: number): void => {
|
||||
const navPath = hostDetailsSubNav[i].pathname;
|
||||
router.push(navPath);
|
||||
};
|
||||
|
||||
return (
|
||||
<MainContent className={baseClass}>
|
||||
<div className={`${baseClass}__wrapper`}>
|
||||
|
|
@ -566,17 +618,16 @@ const HostDetailsPage = ({
|
|||
renderActionButtons={renderActionButtons}
|
||||
/>
|
||||
<TabsWrapper>
|
||||
<Tabs>
|
||||
<Tabs
|
||||
selectedIndex={getTabIndex(pathname)}
|
||||
onSelect={(i) => navigateToNav(i)}
|
||||
>
|
||||
<TabList>
|
||||
<Tab>Details</Tab>
|
||||
<Tab>Software</Tab>
|
||||
<Tab>Schedule</Tab>
|
||||
<Tab>
|
||||
{failingPoliciesCount > 0 && (
|
||||
<span className="count">{failingPoliciesCount}</span>
|
||||
)}
|
||||
Policies
|
||||
</Tab>
|
||||
{hostDetailsSubNav.map((navItem) => {
|
||||
// Bolding text when the tab is active causes a layout shift
|
||||
// so we add a hidden pseudo element with the same text string
|
||||
return <Tab key={navItem.title}>{navItem.name}</Tab>;
|
||||
})}
|
||||
</TabList>
|
||||
<TabPanel>
|
||||
<AboutCard
|
||||
|
|
@ -636,7 +687,6 @@ const HostDetailsPage = ({
|
|||
</TabPanel>
|
||||
</Tabs>
|
||||
</TabsWrapper>
|
||||
|
||||
{showDeleteHostModal && (
|
||||
<DeleteHostModal
|
||||
onCancel={() => setShowDeleteHostModal(false)}
|
||||
|
|
|
|||
|
|
@ -227,7 +227,8 @@
|
|||
.react-tabs__tab {
|
||||
padding: 6px 0px 16px 0px;
|
||||
margin-right: $pad-xxlarge;
|
||||
display: inline-block;
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.react-tabs__tab--selected {
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ const routes = (
|
|||
<Route path="windows" component={DashboardPage} />
|
||||
</Route>
|
||||
<Route path="settings" component={AuthAnyAdminRoutes}>
|
||||
<IndexRedirect to={"/dashboard"} />
|
||||
<IndexRedirect to={"organization"} />
|
||||
<Route component={SettingsWrapper}>
|
||||
<Route component={AuthGlobalAdminRoutes}>
|
||||
<Route path="organization" component={AdminAppSettingsPage} />
|
||||
|
|
@ -143,7 +143,15 @@ const routes = (
|
|||
path="manage/:active_label/labels/:label_id"
|
||||
component={ManageHostsPage}
|
||||
/>
|
||||
<Route path=":host_id" component={HostDetailsPage} />
|
||||
|
||||
<IndexRedirect to={":host_id"} />
|
||||
<Route component={HostDetailsPage}>
|
||||
<Route path=":host_id" component={HostDetailsPage}>
|
||||
<Route path="software" component={HostDetailsPage} />
|
||||
<Route path="schedule" component={HostDetailsPage} />
|
||||
<Route path="policies" component={HostDetailsPage} />
|
||||
</Route>
|
||||
</Route>
|
||||
</Route>
|
||||
<Route path="software">
|
||||
<IndexRedirect to={"manage"} />
|
||||
|
|
|
|||
|
|
@ -48,8 +48,17 @@ export default {
|
|||
MANAGE_HOSTS_LABEL: (labelId: number | string): string => {
|
||||
return `${URL_PREFIX}/hosts/manage/labels/${labelId}`;
|
||||
},
|
||||
HOST_DETAILS: (host: IHost): string => {
|
||||
return `${URL_PREFIX}/hosts/${host.id}`;
|
||||
HOST_DETAILS: (id: number): string => {
|
||||
return `${URL_PREFIX}/hosts/${id}`;
|
||||
},
|
||||
HOST_SOFTWARE: (id: number): string => {
|
||||
return `${URL_PREFIX}/hosts/${id}/software`;
|
||||
},
|
||||
HOST_SCHEDULE: (id: number): string => {
|
||||
return `${URL_PREFIX}/hosts/${id}/schedule`;
|
||||
},
|
||||
HOST_POLICIES: (id: number): string => {
|
||||
return `${URL_PREFIX}/hosts/${id}/policies`;
|
||||
},
|
||||
DEVICE_USER_DETAILS: (deviceAuthToken: any): string => {
|
||||
return `${URL_PREFIX}/device/${deviceAuthToken}`;
|
||||
|
|
|
|||
Loading…
Reference in a new issue