fleet/frontend/pages/admin/OrgSettingsPage/OrgSettingsPage.tsx

153 lines
4.5 KiB
TypeScript
Raw Normal View History

import React, { useCallback, useContext, useState } from "react";
import { InjectedRouter, Params } from "react-router/lib/Router";
import { useQuery } from "react-query";
import { useErrorHandler } from "react-error-boundary";
import { IConfig } from "interfaces/config";
import { IApiError } from "interfaces/errors";
import configAPI from "services/entities/config";
import { AppContext } from "context/app";
import { NotificationContext } from "context/notification";
import deepDifference from "utilities/deep_difference";
import Spinner from "components/Spinner";
import paths from "router/paths";
import SideNav from "../components/SideNav";
import ORG_SETTINGS_NAV_ITEMS from "./OrgSettingsNavItems";
interface IOrgSettingsPageProps {
params: Params;
router: InjectedRouter; // v3
}
export const baseClass = "org-settings";
const OrgSettingsPage = ({ params, router }: IOrgSettingsPageProps) => {
const { section } = params;
const DEFAULT_SETTINGS_SECTION = ORG_SETTINGS_NAV_ITEMS[0];
const [isUpdatingSettings, setIsUpdatingSettings] = useState(false);
const { isFreeTier, isPremiumTier, setConfig, isSandboxMode } = useContext(
AppContext
);
if (isSandboxMode) {
// redirect to Integrations page in sandbox mode
router.push(paths.ADMIN_INTEGRATIONS);
}
const { renderFlash } = useContext(NotificationContext);
const handlePageError = useErrorHandler();
const {
data: appConfig,
isLoading: isLoadingAppConfig,
refetch: refetchConfig,
} = useQuery<IConfig, Error, IConfig>(["config"], () => configAPI.loadAll(), {
select: (data: IConfig) => data,
onSuccess: (data) => {
setConfig(data);
},
});
const onFormSubmit = useCallback(
(formUpdates: Partial<IConfig>) => {
if (!appConfig) {
return false;
}
setIsUpdatingSettings(true);
const diff = deepDifference(formUpdates, appConfig);
// send all formUpdates.agent_options because diff overrides all agent options
diff.agent_options = formUpdates.agent_options;
configAPI
.update(diff)
.then(() => {
renderFlash("success", "Successfully updated settings.");
refetchConfig();
})
.catch((response: { data: IApiError }) => {
if (
response?.data.errors[0].reason.includes("could not dial smtp host")
) {
renderFlash(
"error",
"Could not connect to SMTP server. Please try again."
);
} else if (response?.data.errors) {
const agentOptionsInvalid =
response.data.errors[0].reason.includes(
"unsupported key provided"
) ||
response.data.errors[0].reason.includes("invalid value type");
renderFlash(
"error",
<>
Could not update settings. {response.data.errors[0].reason}
{agentOptionsInvalid && (
<>
<br />
If youre not using the latest osquery, use the fleetctl
apply --force command to override validation.
</>
)}
</>
);
}
})
.finally(() => {
setIsUpdatingSettings(false);
});
},
[appConfig, refetchConfig, renderFlash]
);
// filter out non-premium options
let navItems = ORG_SETTINGS_NAV_ITEMS;
if (!isPremiumTier) {
navItems = ORG_SETTINGS_NAV_ITEMS.filter(
(item) => item.urlSection !== "fleet-desktop"
);
}
const currentFormSection =
navItems.find((item) => item.urlSection === section) ??
DEFAULT_SETTINGS_SECTION;
const CurrentCard = currentFormSection.Card;
if (isFreeTier && section === "fleet-desktop") {
handlePageError({ status: 403 });
return null;
}
return (
<div className={`${baseClass}`}>
<p className={`${baseClass}__page-description`}>
Set your organization information and configure SSO and SMTP
</p>
<SideNav
className={`${baseClass}__side-nav`}
navItems={navItems}
activeItem={currentFormSection.urlSection}
CurrentCard={
!isLoadingAppConfig && appConfig ? (
<CurrentCard
appConfig={appConfig}
handleSubmit={onFormSubmit}
isUpdatingSettings={isUpdatingSettings}
isPremiumTier={isPremiumTier}
/>
) : (
<Spinner />
)
}
/>
</div>
);
};
export default OrgSettingsPage;