mirror of
https://github.com/empayre/fleet.git
synced 2024-11-06 08:55:24 +00:00
Bug 11525: Fixed navigation issues on 'My Device' page (#12102)
Fixed navigation on DeviceUserPage Tab components.
This commit is contained in:
parent
40d866a274
commit
90197d83ae
1
changes/11525-bug-software-table-device-page
Normal file
1
changes/11525-bug-software-table-device-page
Normal file
@ -0,0 +1 @@
|
||||
- Fixed bug with page navigation inside 'My Device' page.
|
@ -8,6 +8,30 @@ import { createCustomRenderer } from "test/test-utils";
|
||||
import { customDeviceHandler } from "test/handlers/device-handler";
|
||||
import DeviceUserPage from "./DeviceUserPage";
|
||||
|
||||
const mockRouter = {
|
||||
push: jest.fn(),
|
||||
replace: jest.fn(),
|
||||
goBack: jest.fn(),
|
||||
goForward: jest.fn(),
|
||||
go: jest.fn(),
|
||||
setRouteLeaveHook: jest.fn(),
|
||||
isActive: jest.fn(),
|
||||
createHref: jest.fn(),
|
||||
createPath: jest.fn(),
|
||||
};
|
||||
|
||||
const mockLocation = {
|
||||
pathname: "",
|
||||
query: {
|
||||
vulnerable: undefined,
|
||||
page: undefined,
|
||||
query: undefined,
|
||||
order_key: undefined,
|
||||
order_direction: undefined,
|
||||
},
|
||||
search: undefined,
|
||||
};
|
||||
|
||||
describe("Device User Page", () => {
|
||||
it("renders the software empty message if the device has no software", async () => {
|
||||
const render = createCustomRenderer({
|
||||
@ -16,7 +40,11 @@ describe("Device User Page", () => {
|
||||
|
||||
// TODO: fix return type from render
|
||||
const { user } = render(
|
||||
<DeviceUserPage params={{ device_auth_token: "testToken" }} />
|
||||
<DeviceUserPage
|
||||
router={mockRouter}
|
||||
params={{ device_auth_token: "testToken" }}
|
||||
location={mockLocation}
|
||||
/>
|
||||
);
|
||||
|
||||
// waiting for the device data to render
|
||||
@ -37,7 +65,11 @@ describe("Device User Page", () => {
|
||||
});
|
||||
|
||||
const { user } = await render(
|
||||
<DeviceUserPage params={{ device_auth_token: "testToken" }} />
|
||||
<DeviceUserPage
|
||||
router={mockRouter}
|
||||
params={{ device_auth_token: "testToken" }}
|
||||
location={mockLocation}
|
||||
/>
|
||||
);
|
||||
|
||||
// waiting for the device data to render
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React, { useState, useContext, useCallback } from "react";
|
||||
import { Params } from "react-router/lib/Router";
|
||||
import { InjectedRouter, Params } from "react-router/lib/Router";
|
||||
import { useQuery } from "react-query";
|
||||
import { Tab, Tabs, TabList, TabPanel } from "react-tabs";
|
||||
|
||||
import { pick } from "lodash";
|
||||
import { pick, findIndex } from "lodash";
|
||||
|
||||
import { NotificationContext } from "context/notification";
|
||||
import deviceUserAPI from "services/entities/device_user";
|
||||
@ -28,6 +28,7 @@ import {
|
||||
wrapFleetHelper,
|
||||
humanHostDiskEncryptionEnabled,
|
||||
} from "utilities/helpers";
|
||||
import PATHS from "router/paths";
|
||||
|
||||
import HostSummaryCard from "../cards/HostSummary";
|
||||
import AboutCard from "../cards/About";
|
||||
@ -47,6 +48,18 @@ import BootstrapPackageModal from "../HostDetailsPage/modals/BootstrapPackageMod
|
||||
const baseClass = "device-user";
|
||||
|
||||
interface IDeviceUserPageProps {
|
||||
location: {
|
||||
pathname: string;
|
||||
query: {
|
||||
vulnerable?: string;
|
||||
page?: string;
|
||||
query?: string;
|
||||
order_key?: string;
|
||||
order_direction?: "asc" | "desc";
|
||||
};
|
||||
search?: string;
|
||||
};
|
||||
router: InjectedRouter;
|
||||
params: Params;
|
||||
}
|
||||
|
||||
@ -56,9 +69,12 @@ interface IHostDiskEncryptionProps {
|
||||
}
|
||||
|
||||
const DeviceUserPage = ({
|
||||
location,
|
||||
router,
|
||||
params: { device_auth_token },
|
||||
}: IDeviceUserPageProps): JSX.Element => {
|
||||
const deviceAuthToken = device_auth_token;
|
||||
const queryParams = location.query;
|
||||
const { renderFlash } = useContext(NotificationContext);
|
||||
|
||||
const [isPremiumTier, setIsPremiumTier] = useState(false);
|
||||
@ -347,6 +363,15 @@ const DeviceUserPage = ({
|
||||
host?.mdm.macos_settings?.disk_encryption === "action_required" &&
|
||||
host?.mdm.macos_settings?.action_required === "rotate_key";
|
||||
|
||||
const tabPaths = [
|
||||
PATHS.DEVICE_USER_DETAILS(deviceAuthToken),
|
||||
PATHS.DEVICE_USER_DETAILS_SOFTWARE(deviceAuthToken),
|
||||
PATHS.DEVICE_USER_DETAILS_POLICIES(deviceAuthToken),
|
||||
];
|
||||
|
||||
const findSelectedTab = (pathname: string) =>
|
||||
findIndex(tabPaths, (x) => x.startsWith(pathname.split("?")[0]));
|
||||
|
||||
return (
|
||||
<div className="fleet-desktop-wrapper">
|
||||
{isLoadingHost ? (
|
||||
@ -394,7 +419,10 @@ const DeviceUserPage = ({
|
||||
deviceUser
|
||||
/>
|
||||
<TabsWrapper>
|
||||
<Tabs>
|
||||
<Tabs
|
||||
selectedIndex={findSelectedTab(location.pathname)}
|
||||
onSelect={(i) => router.push(tabPaths[i])}
|
||||
>
|
||||
<TabList>
|
||||
<Tab>Details</Tab>
|
||||
<Tab>Software</Tab>
|
||||
@ -419,11 +447,15 @@ const DeviceUserPage = ({
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<SoftwareCard
|
||||
router={router}
|
||||
isLoading={isLoadingHost}
|
||||
software={hostSoftware}
|
||||
deviceUser
|
||||
hostId={host?.id || 0}
|
||||
pathname={location.pathname}
|
||||
pathPrefix={PATHS.DEVICE_USER_DETAILS_SOFTWARE(
|
||||
deviceAuthToken
|
||||
)}
|
||||
queryParams={queryParams}
|
||||
/>
|
||||
</TabPanel>
|
||||
{isPremiumTier && (
|
||||
|
@ -746,8 +746,8 @@ const HostDetailsPage = ({
|
||||
router={router}
|
||||
queryParams={queryParams}
|
||||
routeTemplate={routeTemplate}
|
||||
hostId={host?.id || 0}
|
||||
pathname={pathname}
|
||||
pathPrefix={PATHS.HOST_SOFTWARE(host?.id || 0)}
|
||||
/>
|
||||
{host?.platform === "darwin" && macadmins && (
|
||||
<MunkiIssuesCard
|
||||
|
@ -44,8 +44,8 @@ interface ISoftwareTableProps {
|
||||
order_direction?: "asc" | "desc";
|
||||
};
|
||||
routeTemplate?: string;
|
||||
hostId: number;
|
||||
pathname: string;
|
||||
pathPrefix: string;
|
||||
}
|
||||
|
||||
interface IRowProps extends Row {
|
||||
@ -67,7 +67,7 @@ const SoftwareTable = ({
|
||||
router,
|
||||
queryParams,
|
||||
routeTemplate,
|
||||
hostId,
|
||||
pathPrefix,
|
||||
pathname,
|
||||
}: ISoftwareTableProps): JSX.Element => {
|
||||
const { isSandboxMode, setFilteredSoftwarePath } = useContext(AppContext);
|
||||
@ -118,8 +118,9 @@ const SoftwareTable = ({
|
||||
) {
|
||||
newQueryParams.page = 0;
|
||||
}
|
||||
|
||||
const locationPath = getNextLocationPath({
|
||||
pathPrefix: PATHS.HOST_SOFTWARE(hostId),
|
||||
pathPrefix,
|
||||
routeTemplate,
|
||||
queryParams: newQueryParams,
|
||||
});
|
||||
@ -132,7 +133,7 @@ const SoftwareTable = ({
|
||||
const onClientSidePaginationChange = useCallback(
|
||||
(pageIndex: number) => {
|
||||
const locationPath = getNextLocationPath({
|
||||
pathPrefix: PATHS.HOST_SOFTWARE(hostId),
|
||||
pathPrefix,
|
||||
routeTemplate,
|
||||
queryParams: {
|
||||
...queryParams,
|
||||
@ -163,17 +164,16 @@ const SoftwareTable = ({
|
||||
);
|
||||
|
||||
const handleVulnFilterDropdownChange = (isFilterVulnerable: string) => {
|
||||
router?.replace(
|
||||
getNextLocationPath({
|
||||
pathPrefix: PATHS.HOST_SOFTWARE(hostId),
|
||||
routeTemplate,
|
||||
queryParams: {
|
||||
...queryParams,
|
||||
page: 0,
|
||||
vulnerable: isFilterVulnerable,
|
||||
},
|
||||
})
|
||||
);
|
||||
const nextPath = getNextLocationPath({
|
||||
pathPrefix,
|
||||
routeTemplate,
|
||||
queryParams: {
|
||||
...queryParams,
|
||||
page: 0,
|
||||
vulnerable: isFilterVulnerable,
|
||||
},
|
||||
});
|
||||
router?.replace(nextPath);
|
||||
};
|
||||
|
||||
const handleRowSelect = (row: IRowProps) => {
|
||||
|
@ -231,7 +231,16 @@ const routes = (
|
||||
/>
|
||||
</Route>
|
||||
</Route>
|
||||
<Route path="/device/:device_auth_token" component={DeviceUserPage} />
|
||||
<Route path="device">
|
||||
<IndexRedirect to=":device_auth_token" />
|
||||
|
||||
<Route component={DeviceUserPage}>
|
||||
<Route path=":device_auth_token" component={DeviceUserPage}>
|
||||
<Route path="software" component={DeviceUserPage} />
|
||||
<Route path="policies" component={DeviceUserPage} />
|
||||
</Route>
|
||||
</Route>
|
||||
</Route>
|
||||
</Route>
|
||||
<Route path="/apionlyuser" component={ApiOnlyUser} />
|
||||
<Route path="/404" component={Fleet404} />
|
||||
|
@ -75,6 +75,12 @@ export default {
|
||||
DEVICE_USER_DETAILS: (deviceAuthToken: any): string => {
|
||||
return `${URL_PREFIX}/device/${deviceAuthToken}`;
|
||||
},
|
||||
DEVICE_USER_DETAILS_SOFTWARE: (deviceAuthToken: string): string => {
|
||||
return `${URL_PREFIX}/device/${deviceAuthToken}/software`;
|
||||
},
|
||||
DEVICE_USER_DETAILS_POLICIES: (deviceAuthToken: string): string => {
|
||||
return `${URL_PREFIX}/device/${deviceAuthToken}/policies`;
|
||||
},
|
||||
MANAGE_SOFTWARE: `${URL_PREFIX}/software/manage`,
|
||||
SOFTWARE_DETAILS: (id: string): string => {
|
||||
return `${URL_PREFIX}/software/${id}`;
|
||||
|
Loading…
Reference in New Issue
Block a user