Fleet UI: Host details page includes team_id param in URL (#39801)

This commit is contained in:
RachelElysia
2026-02-13 16:42:17 -05:00
committed by GitHub
parent c4196ed46c
commit ed7216eb10
12 changed files with 65 additions and 19 deletions
+1
View File
@@ -0,0 +1 @@
- Fleet UI: Host details page includes team_id param in URL to allow retaining team on refresh
@@ -87,7 +87,7 @@ const lastSeenTime = (status: string, seenTime: string): string => {
return "Online";
};
const allHostTableHeaders: IHostTableColumnConfig[] = [
const allHostTableHeaders = (teamId?: number): IHostTableColumnConfig[] => [
// We are using React Table useRowSelect functionality for the selection header.
// More information on its API can be found here
// https://react-table.tanstack.com/docs/api/useRowSelect
@@ -158,7 +158,7 @@ const allHostTableHeaders: IHostTableColumnConfig[] = [
return (
<LinkCell
value={cellProps.cell.value}
path={PATHS.HOST_DETAILS(cellProps.row.original.id)}
path={PATHS.HOST_DETAILS(cellProps.row.original.id, teamId)}
title={lastSeenTime(
cellProps.row.original.status,
cellProps.row.original.seen_time
@@ -697,11 +697,13 @@ const defaultHiddenColumns = [
const generateAvailableTableHeaders = ({
isFreeTier = true,
isOnlyObserver = true,
teamId,
}: {
isFreeTier: boolean | undefined;
isOnlyObserver: boolean | undefined;
teamId?: number;
}): IHostTableColumnConfig[] => {
return allHostTableHeaders.reduce(
return allHostTableHeaders(teamId).reduce(
(columns: Column<IHost>[], currentColumn: Column<IHost>) => {
// skip over column headers that are not shown in free observer tier
if (isFreeTier) {
@@ -738,17 +740,21 @@ const generateVisibleTableColumns = ({
hiddenColumns,
isFreeTier = true,
isOnlyObserver = true,
teamId,
}: {
hiddenColumns: string[];
isFreeTier: boolean | undefined;
isOnlyObserver: boolean | undefined;
teamId?: number;
}): IHostTableColumnConfig[] => {
// remove columns set as hidden by the user.
return generateAvailableTableHeaders({ isFreeTier, isOnlyObserver }).filter(
(column) => {
return !hiddenColumns.includes(column.id as string);
}
);
return generateAvailableTableHeaders({
isFreeTier,
isOnlyObserver,
teamId,
}).filter((column) => {
return !hiddenColumns.includes(column.id as string);
});
};
export {
@@ -1568,6 +1568,7 @@ const ManageHostsPage = ({
hiddenColumns: currentHiddenColumns,
isFreeTier,
isOnlyObserver,
teamId: teamIdForApi,
});
const columnIds = tableColumns
@@ -1810,6 +1811,7 @@ const ManageHostsPage = ({
isOnlyObserver ||
isGlobalTechnician ||
(!isOnGlobalTeam && !isTeamMaintainerOrTeamAdmin),
teamId: teamIdForApi,
});
const emptyState = () => {
@@ -163,6 +163,7 @@ interface IHostDetailsProps {
query?: string;
order_key?: string;
order_direction?: "asc" | "desc";
team_id?: string;
};
search?: string;
};
@@ -973,7 +974,7 @@ const HostDetailsPage = ({
const onClickAddQuery = () => {
router.push(
getPathWithQueryParams(PATHS.NEW_QUERY, {
team_id: currentTeam?.id,
team_id: currentTeam?.id || location.query.team_id,
host_id: hostIdFromURL,
})
);
@@ -1097,12 +1098,20 @@ const HostDetailsPage = ({
const navigateToNav = (i: number): void => {
const navPath = hostDetailsSubNav[i].pathname;
router.push(navPath);
router.push(
getPathWithQueryParams(navPath, {
team_id: currentTeam?.id || location.query.team_id,
})
);
};
const navigateToSoftwareTab = (i: number): void => {
const navPath = hostSoftwareSubNav[i].pathname;
router.push(navPath);
router.push(
getPathWithQueryParams(navPath, {
team_id: currentTeam?.id || location.query.team_id,
})
);
};
const isHostTeamAdmin = permissions.isTeamAdmin(currentUser, host?.team_id);
@@ -1285,7 +1294,12 @@ const HostDetailsPage = ({
<div className={`${baseClass}__header-links`}>
<BackButton
text="Back to all hosts"
path={filteredHostsPath || PATHS.MANAGE_HOSTS}
path={
filteredHostsPath ||
getPathWithQueryParams(PATHS.MANAGE_HOSTS, {
team_id: location.query.team_id,
})
}
/>
</div>
<div className={`${baseClass}__header-summary`}>
@@ -119,7 +119,7 @@ const HostQueryReport = ({
<div className={`${baseClass}__header__row1`}>
<BackButton
text="Back to host details"
path={PATHS.HOST_DETAILS_PAGE(hostId)}
path={PATHS.HOST_DETAILS(hostId)}
/>
</div>
<div className={`${baseClass}__header__row2`}>
@@ -88,6 +88,7 @@ export const parseHostSoftwareLibraryQueryParams = (queryParams: {
order_key?: string;
order_direction?: "asc" | "desc";
self_service?: string;
team_id?: string;
}) => {
const searchQuery = queryParams?.query ?? DEFAULT_SEARCH_QUERY;
const sortHeader = queryParams?.order_key ?? DEFAULT_SORT_HEADER;
@@ -97,6 +98,9 @@ export const parseHostSoftwareLibraryQueryParams = (queryParams: {
: DEFAULT_PAGE;
const pageSize = DEFAULT_PAGE_SIZE;
const selfService = queryParams?.self_service === "true";
const teamId = queryParams?.team_id
? parseInt(queryParams.team_id, 10)
: undefined;
return {
page,
@@ -106,6 +110,7 @@ export const parseHostSoftwareLibraryQueryParams = (queryParams: {
per_page: pageSize,
available_for_install: true, // always true for host installers
self_service: selfService,
team_id: teamId,
};
};
@@ -605,6 +610,7 @@ const HostSoftwareLibrary = ({
page={queryParams.page}
pagePath={pathname}
selfService={queryParams.self_service}
teamId={queryParams.team_id}
/>
);
};
@@ -41,6 +41,7 @@ interface IHostSoftwareLibraryTableProps {
page: number;
pagePath: string;
selfService: boolean;
teamId?: number;
}
const HostSoftwareLibraryTable = ({
@@ -56,6 +57,7 @@ const HostSoftwareLibraryTable = ({
selfService,
page,
pagePath,
teamId,
}: IHostSoftwareLibraryTableProps) => {
const determineQueryParamChange = useCallback(
(newTableQuery: ITableQueryData) => {
@@ -85,6 +87,7 @@ const HostSoftwareLibraryTable = ({
order_direction: newTableQuery.sortDirection,
order_key: newTableQuery.sortHeader,
page: changedParam === "pageIndex" ? newTableQuery.pageIndex : 0,
team_id: teamId,
...(selfService && { self_service: "true" }),
};
@@ -125,6 +128,7 @@ const HostSoftwareLibraryTable = ({
orderDirection: sortDirection,
orderKey: sortHeader,
page: 0, // resets page index
teamId,
...(value === "selfService" && { selfService: true }),
};
@@ -81,6 +81,7 @@ export const parseHostSoftwareQueryParams = (queryParams: {
max_cvss_score?: string;
self_service?: string;
category_id?: string;
team_id?: string;
}) => {
const searchQuery = queryParams?.query ?? DEFAULT_SEARCH_QUERY;
const sortHeader = queryParams?.order_key ?? DEFAULT_SORT_HEADER;
@@ -96,6 +97,9 @@ export const parseHostSoftwareQueryParams = (queryParams: {
? parseInt(queryParams.category_id, 10)
: undefined;
const selfService = queryParams?.self_service === "true";
const teamId = queryParams?.team_id
? parseInt(queryParams.team_id, 10)
: undefined;
return {
page,
@@ -110,6 +114,7 @@ export const parseHostSoftwareQueryParams = (queryParams: {
exploit: softwareVulnFilters.exploit,
available_for_install: false, // always false for host software
category_id: categoryId,
team_id: teamId,
};
};
@@ -228,6 +233,7 @@ const HostSoftware = ({
orderKey: queryParams.order_key,
perPage: queryParams.per_page,
page: 0, // resets page index
team_id: queryParams.team_id,
...buildSoftwareVulnFiltersQueryParams(vulnFilters),
};
@@ -304,6 +310,7 @@ const HostSoftware = ({
min_cvss_score: queryParams.min_cvss_score,
max_cvss_score: queryParams.max_cvss_score,
})}
teamId={queryParams.team_id}
onAddFiltersClick={toggleSoftwareFiltersModal}
// for my device software details modal toggling
isMyDevicePage={isMyDevicePage}
@@ -75,6 +75,7 @@ interface IHostSoftwareTableProps {
page: number;
pagePath: string;
vulnFilters: ISoftwareVulnFiltersParams;
teamId?: number;
onAddFiltersClick: () => void;
isMyDevicePage?: boolean;
onShowInventoryVersions: (software: IHostSoftware) => void;
@@ -92,6 +93,7 @@ const HostSoftwareTable = ({
page,
pagePath,
vulnFilters,
teamId,
onAddFiltersClick,
isMyDevicePage,
onShowInventoryVersions,
@@ -124,6 +126,7 @@ const HostSoftwareTable = ({
order_direction: newTableQuery.sortDirection,
order_key: newTableQuery.sortHeader,
page: changedParam === "pageIndex" ? newTableQuery.pageIndex : 0,
team_id: teamId,
...buildSoftwareVulnFiltersQueryParams(vulnFilters),
};
return newQueryParam;
@@ -257,7 +257,10 @@ const QueryDetailsPage = ({
const backPath = () => {
if (filteredQueriesPath) return filteredQueriesPath;
if (hostId) return getPathWithQueryParams(PATHS.HOST_DETAILS(hostId));
if (hostId)
return getPathWithQueryParams(
PATHS.HOST_DETAILS(hostId, currentTeamId)
);
return getPathWithQueryParams(PATHS.MANAGE_QUERIES, {
team_id: currentTeamId,
@@ -381,7 +381,7 @@ const EditQueryPage = ({
}
if (hostId) {
return getPathWithQueryParams(PATHS.HOST_DETAILS(hostId));
return getPathWithQueryParams(PATHS.HOST_DETAILS(hostId, currentTeamId));
}
if (filteredQueriesPath) return filteredQueriesPath;
+4 -4
View File
@@ -141,10 +141,10 @@ export default {
MANAGE_HOSTS_LABEL: (labelId: number | string): string => {
return `${URL_PREFIX}/hosts/manage/labels/${labelId}`;
},
HOST_DETAILS_PAGE: (id: number): string => {
return `${URL_PREFIX}/hosts/${id}`;
},
HOST_DETAILS: (id: number): string => {
HOST_DETAILS: (id: number, teamId?: number): string => {
if (teamId) {
return `${URL_PREFIX}/hosts/${id}/details?team_id=${teamId}`;
}
return `${URL_PREFIX}/hosts/${id}/details`;
},
HOST_SCRIPTS: (id: number): string => {