mirror of
https://github.com/fleetdm/fleet
synced 2026-04-21 13:37:30 +00:00
Implements patch policies #31914 - https://github.com/fleetdm/fleet/pull/40816 - https://github.com/fleetdm/fleet/pull/41248 - https://github.com/fleetdm/fleet/pull/41276 - https://github.com/fleetdm/fleet/pull/40948 - https://github.com/fleetdm/fleet/pull/40837 - https://github.com/fleetdm/fleet/pull/40956 - https://github.com/fleetdm/fleet/pull/41168 - https://github.com/fleetdm/fleet/pull/41171 - https://github.com/fleetdm/fleet/pull/40691 - https://github.com/fleetdm/fleet/pull/41524 - https://github.com/fleetdm/fleet/pull/41674 --------- Co-authored-by: Jonathan Katz <44128041+jkatz01@users.noreply.github.com> Co-authored-by: jkatz01 <yehonatankatz@gmail.com> Co-authored-by: RachelElysia <71795832+RachelElysia@users.noreply.github.com> Co-authored-by: Jahziel Villasana-Espinoza <jahziel@fleetdm.com>
164 lines
4.7 KiB
TypeScript
164 lines
4.7 KiB
TypeScript
import React, { useCallback, useContext } from "react";
|
|
import { Tab, TabList, Tabs } from "react-tabs";
|
|
import { InjectedRouter } from "react-router";
|
|
import { Location } from "history";
|
|
|
|
import PATHS from "router/paths";
|
|
import { getPathWithQueryParams } from "utilities/url";
|
|
import { QueryContext } from "context/query";
|
|
import useToggleSidePanel from "hooks/useToggleSidePanel";
|
|
import { APP_CONTEXT_NO_TEAM_ID } from "interfaces/team";
|
|
|
|
import SidePanelPage from "components/SidePanelPage";
|
|
import MainContent from "components/MainContent";
|
|
import BackButton from "components/BackButton";
|
|
import TabNav from "components/TabNav";
|
|
import TabText from "components/TabText";
|
|
import SidePanelContent from "components/SidePanelContent";
|
|
import QuerySidePanel from "components/side_panels/QuerySidePanel";
|
|
import PageDescription from "components/PageDescription";
|
|
|
|
import {
|
|
FmaPlatformValue,
|
|
FmaStatusValue,
|
|
} from "./SoftwareFleetMaintained/FleetMaintainedAppsTable/FmaFilters/FmaFilters";
|
|
|
|
const baseClass = "software-add-page";
|
|
|
|
interface IAddSoftwareSubNavItem {
|
|
name: string;
|
|
pathname: string;
|
|
}
|
|
|
|
const addSoftwareSubNav: IAddSoftwareSubNavItem[] = [
|
|
{
|
|
name: "Fleet-maintained",
|
|
pathname: PATHS.SOFTWARE_ADD_FLEET_MAINTAINED,
|
|
},
|
|
{
|
|
name: "App store",
|
|
pathname: PATHS.SOFTWARE_ADD_APP_STORE,
|
|
},
|
|
{
|
|
name: "Custom package",
|
|
pathname: PATHS.SOFTWARE_ADD_PACKAGE,
|
|
},
|
|
];
|
|
|
|
const getTabIndex = (path: string): number => {
|
|
return addSoftwareSubNav.findIndex((navItem) => {
|
|
// tab stays highlighted for paths that start with same pathname
|
|
return path.startsWith(navItem.pathname);
|
|
});
|
|
};
|
|
|
|
export interface ISoftwareAddPageQueryParams {
|
|
fleet_id?: string;
|
|
query?: string;
|
|
page?: string;
|
|
order_key?: string;
|
|
order_direction?: "asc" | "desc";
|
|
platform: FmaPlatformValue;
|
|
status: FmaStatusValue;
|
|
}
|
|
|
|
interface ISoftwareAddPageProps {
|
|
children: JSX.Element;
|
|
location: Location<ISoftwareAddPageQueryParams>;
|
|
router: InjectedRouter;
|
|
}
|
|
|
|
const SoftwareAddPage = ({
|
|
children,
|
|
location,
|
|
router,
|
|
}: ISoftwareAddPageProps) => {
|
|
const { selectedOsqueryTable, setSelectedOsqueryTable } = useContext(
|
|
QueryContext
|
|
);
|
|
const { isSidePanelOpen, setSidePanelOpen } = useToggleSidePanel(false);
|
|
|
|
const navigateToNav = useCallback(
|
|
(i: number): void => {
|
|
setSidePanelOpen(false);
|
|
// Only query param to persist between tabs is team id
|
|
const navPath = getPathWithQueryParams(addSoftwareSubNav[i].pathname, {
|
|
fleet_id: location.query.fleet_id,
|
|
});
|
|
router.replace(navPath);
|
|
},
|
|
[location.query.fleet_id, router, setSidePanelOpen]
|
|
);
|
|
|
|
// Quick exit if no fleet_id param. This page must have a team id to function
|
|
// correctly. We redirect to the same page with the "No team" context if it
|
|
// is not provieded.
|
|
if (!location.query.fleet_id) {
|
|
router.replace(
|
|
getPathWithQueryParams(location.pathname, {
|
|
fleet_id: APP_CONTEXT_NO_TEAM_ID,
|
|
})
|
|
);
|
|
return null;
|
|
}
|
|
|
|
const onOsqueryTableSelect = (tableName: string) => {
|
|
setSelectedOsqueryTable(tableName);
|
|
};
|
|
|
|
const backUrl = getPathWithQueryParams(PATHS.SOFTWARE_TITLES, {
|
|
fleet_id: location.query.fleet_id,
|
|
});
|
|
|
|
return (
|
|
<SidePanelPage>
|
|
<>
|
|
<MainContent className={baseClass}>
|
|
<div className={`${baseClass}__header-links`}>
|
|
<BackButton
|
|
text="Back to software"
|
|
path={backUrl}
|
|
className={`${baseClass}__back-to-software`}
|
|
/>
|
|
</div>
|
|
<h1>Add software</h1>
|
|
<PageDescription content="Add software to your library. You can add it to self-service later." />
|
|
<TabNav>
|
|
<Tabs
|
|
selectedIndex={getTabIndex(location?.pathname || "")}
|
|
onSelect={navigateToNav}
|
|
>
|
|
<TabList>
|
|
{addSoftwareSubNav.map((navItem) => {
|
|
return (
|
|
<Tab key={navItem.name} data-text={navItem.name}>
|
|
<TabText>{navItem.name}</TabText>
|
|
</Tab>
|
|
);
|
|
})}
|
|
</TabList>
|
|
</Tabs>
|
|
</TabNav>
|
|
{React.cloneElement(children, {
|
|
router,
|
|
currentTeamId: parseInt(location.query.fleet_id, 10),
|
|
isSidePanelOpen,
|
|
setSidePanelOpen,
|
|
})}
|
|
</MainContent>
|
|
{isSidePanelOpen && (
|
|
<SidePanelContent>
|
|
<QuerySidePanel
|
|
key="query-side-panel"
|
|
onOsqueryTableSelect={onOsqueryTableSelect}
|
|
selectedOsqueryTable={selectedOsqueryTable}
|
|
onClose={() => setSidePanelOpen(false)}
|
|
/>
|
|
</SidePanelContent>
|
|
)}
|
|
</>
|
|
</SidePanelPage>
|
|
);
|
|
};
|
|
|
|
export default SoftwareAddPage;
|