mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #35296 This makes the TurnOnMDMMessage component more generic and display a configurage "Turn on" message. We then are able to use this in the End user auth page on the controls page. - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. - [x] QA'd all new/changed functionality manually
254 lines
7.7 KiB
TypeScript
254 lines
7.7 KiB
TypeScript
import React, { useContext, useState } from "react";
|
|
import { useQuery } from "react-query";
|
|
import { AxiosError, AxiosResponse } from "axios";
|
|
|
|
import PATHS from "router/paths";
|
|
import { IApiError } from "interfaces/errors";
|
|
import { IConfig } from "interfaces/config";
|
|
import { API_NO_TEAM_ID, ITeamConfig } from "interfaces/team";
|
|
import { ISoftwareTitle } from "interfaces/software";
|
|
import mdmAPI, {
|
|
IGetBootstrapPackageMetadataResponse,
|
|
IGetSetupExperienceScriptResponse,
|
|
IGetSetupExperienceSoftwareResponse,
|
|
} from "services/entities/mdm";
|
|
import configAPI from "services/entities/config";
|
|
import teamsAPI, { ILoadTeamResponse } from "services/entities/teams";
|
|
import { NotificationContext } from "context/notification";
|
|
import {
|
|
DEFAULT_USE_QUERY_OPTIONS,
|
|
LEARN_MORE_ABOUT_BASE_LINK,
|
|
} from "utilities/constants";
|
|
|
|
import Spinner from "components/Spinner";
|
|
import GenericMsgWithNavButton from "components/GenericMsgWithNavButton";
|
|
import SectionHeader from "components/SectionHeader";
|
|
import CustomLink from "components/CustomLink";
|
|
|
|
import PackageUploader from "./components/BootstrapPackageUploader";
|
|
import UploadedPackageView from "./components/UploadedPackageView";
|
|
import DeleteBootstrapPackageModal from "./components/DeleteBootstrapPackageModal";
|
|
import BootstrapAdvancedOptions from "./components/BootstrapAdvancedOptions";
|
|
import SetupExperienceContentContainer from "../../components/SetupExperienceContentContainer";
|
|
import { getInstallSoftwareDuringSetupCount } from "../InstallSoftware/components/AddInstallSoftware/helpers";
|
|
import { ISetupExperienceCardProps } from "../../SetupExperienceNavItems";
|
|
import getManualAgentInstallSetting from "../../helpers";
|
|
|
|
const baseClass = "bootstrap-package";
|
|
|
|
// This is so large because we want to get all the software titles that are
|
|
// available for install so we can correctly display the selected count.
|
|
const PER_PAGE_SIZE = 3000;
|
|
|
|
const BootstrapPackage = ({
|
|
currentTeamId,
|
|
router,
|
|
}: ISetupExperienceCardProps) => {
|
|
const { renderFlash } = useContext(NotificationContext);
|
|
const [
|
|
selectedManualAgentInstall,
|
|
setSelectedManualAgentInstall,
|
|
] = useState<boolean>(false);
|
|
const [
|
|
showDeleteBootstrapPackageModal,
|
|
setShowDeleteBootstrapPackageModal,
|
|
] = useState(false);
|
|
|
|
const { data: macSoftwareTitles, isLoading: isLoadingSoftware } = useQuery<
|
|
IGetSetupExperienceSoftwareResponse,
|
|
AxiosError,
|
|
ISoftwareTitle[] | null
|
|
>(
|
|
["install-software", currentTeamId],
|
|
() =>
|
|
mdmAPI.getSetupExperienceSoftware({
|
|
platform: "macos",
|
|
team_id: currentTeamId,
|
|
per_page: PER_PAGE_SIZE,
|
|
}),
|
|
{
|
|
...DEFAULT_USE_QUERY_OPTIONS,
|
|
select: (res) => res.software_titles,
|
|
}
|
|
);
|
|
|
|
const { data: script, isLoading: isLoadingScript } = useQuery<
|
|
IGetSetupExperienceScriptResponse,
|
|
AxiosError
|
|
>(
|
|
["setup-experience-script", currentTeamId],
|
|
() => mdmAPI.getSetupExperienceScript(currentTeamId),
|
|
{ ...DEFAULT_USE_QUERY_OPTIONS }
|
|
);
|
|
|
|
const {
|
|
data: globalConfig,
|
|
isLoading: isLoadingGlobalConfig,
|
|
refetch: refetchGlobalConfig,
|
|
} = useQuery<IConfig, Error>(
|
|
["config", currentTeamId],
|
|
() => configAPI.loadAll(),
|
|
{
|
|
...DEFAULT_USE_QUERY_OPTIONS,
|
|
onSuccess: (data) => {
|
|
if (currentTeamId === API_NO_TEAM_ID) {
|
|
setSelectedManualAgentInstall(
|
|
getManualAgentInstallSetting(currentTeamId, data)
|
|
);
|
|
}
|
|
},
|
|
}
|
|
);
|
|
|
|
const {
|
|
isLoading: isLoadingTeamConfig,
|
|
refetch: refetchTeamConfig,
|
|
} = useQuery<ILoadTeamResponse, Error, ITeamConfig>(
|
|
["team", currentTeamId],
|
|
() => teamsAPI.load(currentTeamId),
|
|
{
|
|
...DEFAULT_USE_QUERY_OPTIONS,
|
|
enabled: currentTeamId !== API_NO_TEAM_ID,
|
|
select: (res) => res.team,
|
|
onSuccess: (data) => {
|
|
setSelectedManualAgentInstall(
|
|
getManualAgentInstallSetting(currentTeamId, undefined, data)
|
|
);
|
|
},
|
|
}
|
|
);
|
|
|
|
const {
|
|
data: bootstrapMetadata,
|
|
isLoading: isloadingBootstrapMetadata,
|
|
error: errorBootstrapMetadata,
|
|
refetch: refretchBootstrapMetadata,
|
|
} = useQuery<IGetBootstrapPackageMetadataResponse, AxiosResponse<IApiError>>(
|
|
["bootstrap-metadata", currentTeamId],
|
|
() => mdmAPI.getBootstrapPackageMetadata(currentTeamId),
|
|
{
|
|
...DEFAULT_USE_QUERY_OPTIONS,
|
|
cacheTime: 0,
|
|
}
|
|
);
|
|
|
|
const onUpload = () => {
|
|
refretchBootstrapMetadata();
|
|
};
|
|
|
|
const onDelete = async () => {
|
|
try {
|
|
await mdmAPI.deleteBootstrapPackage(currentTeamId);
|
|
await mdmAPI.updateSetupExperienceSettings({
|
|
team_id: currentTeamId,
|
|
manual_agent_install: false,
|
|
});
|
|
renderFlash("success", "Successfully deleted!");
|
|
} catch {
|
|
renderFlash("error", "Couldn't delete. Please try again.");
|
|
} finally {
|
|
setShowDeleteBootstrapPackageModal(false);
|
|
refretchBootstrapMetadata();
|
|
if (currentTeamId !== API_NO_TEAM_ID) {
|
|
refetchTeamConfig();
|
|
} else {
|
|
refetchGlobalConfig();
|
|
}
|
|
}
|
|
};
|
|
|
|
// we are relying on the API to tell us this resource does not exist to
|
|
// determine if the user has uploaded a bootstrap package.
|
|
const noPackageUploaded =
|
|
(errorBootstrapMetadata && errorBootstrapMetadata.status === 404) ||
|
|
!bootstrapMetadata;
|
|
const hasSetupExperienceInstallSoftware =
|
|
getInstallSoftwareDuringSetupCount(macSoftwareTitles) !== 0;
|
|
const hasSetupExperienceScript = !!script;
|
|
|
|
const renderBootstrapView = () => {
|
|
const bootstrapPackageView = noPackageUploaded ? (
|
|
<PackageUploader currentTeamId={currentTeamId} onUpload={onUpload} />
|
|
) : (
|
|
<UploadedPackageView
|
|
bootstrapPackage={bootstrapMetadata}
|
|
currentTeamId={currentTeamId}
|
|
onDelete={() => setShowDeleteBootstrapPackageModal(true)}
|
|
/>
|
|
);
|
|
|
|
return (
|
|
<SetupExperienceContentContainer className={`${baseClass}__content`}>
|
|
<div className={`${baseClass}__uploader-container`}>
|
|
{bootstrapPackageView}
|
|
<BootstrapAdvancedOptions
|
|
currentTeamId={currentTeamId}
|
|
disableInstallManually={
|
|
noPackageUploaded ||
|
|
hasSetupExperienceInstallSoftware ||
|
|
hasSetupExperienceScript
|
|
}
|
|
selectManualAgentInstall={selectedManualAgentInstall}
|
|
onChange={(manualAgentInstall) => {
|
|
setSelectedManualAgentInstall(manualAgentInstall);
|
|
}}
|
|
/>
|
|
</div>
|
|
</SetupExperienceContentContainer>
|
|
);
|
|
};
|
|
|
|
const isLoading =
|
|
isloadingBootstrapMetadata ||
|
|
isLoadingGlobalConfig ||
|
|
isLoadingTeamConfig ||
|
|
isLoadingScript ||
|
|
isLoadingSoftware;
|
|
|
|
const renderContent = () => {
|
|
if (isLoading) {
|
|
return <Spinner />;
|
|
}
|
|
if (
|
|
!(
|
|
globalConfig?.mdm.enabled_and_configured &&
|
|
globalConfig?.mdm.apple_bm_enabled_and_configured
|
|
)
|
|
) {
|
|
return (
|
|
<GenericMsgWithNavButton
|
|
header="Additional configuration required"
|
|
info="Supported on macOS. To customize, first turn on automatic enrollment."
|
|
buttonText="Turn on"
|
|
path={PATHS.ADMIN_INTEGRATIONS_MDM}
|
|
router={router}
|
|
/>
|
|
);
|
|
}
|
|
return renderBootstrapView();
|
|
};
|
|
|
|
return (
|
|
<section className={baseClass}>
|
|
<SectionHeader
|
|
title="Bootstrap package"
|
|
details={
|
|
<CustomLink
|
|
newTab
|
|
url={`${LEARN_MORE_ABOUT_BASE_LINK}/setup-experience/bootstrap-package`}
|
|
text="Preview end user experience"
|
|
/>
|
|
}
|
|
/>
|
|
{renderContent()}
|
|
{showDeleteBootstrapPackageModal && (
|
|
<DeleteBootstrapPackageModal
|
|
onDelete={onDelete}
|
|
onCancel={() => setShowDeleteBootstrapPackageModal(false)}
|
|
/>
|
|
)}
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export default BootstrapPackage;
|