Fleet UI: Add advanced setting to set expiry window for activity log (#17989)

This commit is contained in:
RachelElysia
2024-04-10 10:48:46 -04:00
committed by GitHub
parent d2d1b8f0ca
commit e99eaf6cd3
14 changed files with 271 additions and 180 deletions
@@ -0,0 +1 @@
- Add advanced setting to set expiry window for activity log
+4
View File
@@ -46,6 +46,10 @@ const DEFAULT_CONFIG_MOCK: IConfig = {
host_expiry_enabled: false,
host_expiry_window: 0,
},
activity_expiry_settings: {
activity_expiry_enabled: true,
activity_expiry_window: 90,
},
agent_options: "",
license: {
tier: "free",
+7 -38
View File
@@ -65,41 +65,6 @@ export interface IFleetDesktopSettings {
transparency_url: string;
}
export interface IConfigFormData {
smtpAuthenticationMethod: string;
smtpAuthenticationType: string;
domain: string;
smtpEnableSslTls: boolean;
enableStartTls: boolean;
serverUrl: string;
orgLogoUrl: string;
orgName: string;
smtpPassword: string;
smtpPort?: number;
smtpSenderAddress: string;
smtpServer: string;
smtpUsername: string;
verifySslCerts: boolean;
entityId: string;
idpImageUrl: string;
metadata: string;
metadataUrl: string;
idpName: string;
enableSso: boolean;
enableSsoIdpLogin: boolean;
enableSmtp: boolean;
enableHostExpiry: boolean;
hostExpiryWindow: number;
disableLiveQuery: boolean;
agentOptions: any;
enableHostStatusWebhook: boolean;
hostStatusWebhookDestinationUrl?: string;
hostStatusWebhookHostPercentage?: number;
hostStatusWebhookDaysCount?: number;
enableUsageStatistics: boolean;
transparencyUrl: string;
}
export interface IConfigFeatures {
enable_host_users: boolean;
enable_software_inventory: boolean;
@@ -125,7 +90,7 @@ export interface IConfig {
server_settings: IConfigServerSettings;
smtp_settings?: {
enable_smtp: boolean;
configured: boolean;
configured?: boolean;
sender_address: string;
server: string;
port?: number;
@@ -152,10 +117,14 @@ export interface IConfig {
};
host_expiry_settings: {
host_expiry_enabled: boolean;
host_expiry_window: number;
host_expiry_window?: number;
};
activity_expiry_settings: {
activity_expiry_enabled: boolean;
activity_expiry_window?: number;
};
features: IConfigFeatures;
agent_options: string;
agent_options: unknown; // Can pass empty object
update_interval: {
osquery_detail: number;
osquery_policy: number;
@@ -1,31 +1,53 @@
import React, { useState, useEffect } from "react";
import React, { useState, useEffect, useMemo } from "react";
import Button from "components/buttons/Button";
import Checkbox from "components/forms/fields/Checkbox";
// @ts-ignore
import InputField from "components/forms/fields/InputField";
import SectionHeader from "components/SectionHeader";
// @ts-ignore
import Dropdown from "components/forms/fields/Dropdown";
import {
IAppConfigFormProps,
IFormField,
IAppConfigFormErrors,
} from "../constants";
import { ACTIVITY_EXPIRY_WINDOW_DROPDOWN_OPTIONS } from "utilities/constants";
import { getCustomDropdownOptions } from "utilities/helpers";
import { IAppConfigFormProps, IFormField } from "../constants";
const baseClass = "app-config-form";
interface IAdvancedConfigFormData {
domain: string;
verifySSLCerts: boolean;
enableStartTLS?: boolean;
enableHostExpiry: boolean;
hostExpiryWindow: number;
deleteActivities: boolean;
activityExpiryWindow: number;
disableLiveQuery: boolean;
disableScripts: boolean;
disableQueryReports: boolean;
}
interface IAdvancedConfigFormErrors {
host_expiry_window?: string | null;
}
const Advanced = ({
appConfig,
handleSubmit,
isUpdatingSettings,
}: IAppConfigFormProps): JSX.Element => {
const [formData, setFormData] = useState({
const [formData, setFormData] = useState<IAdvancedConfigFormData>({
domain: appConfig.smtp_settings?.domain || "",
verifySSLCerts: appConfig.smtp_settings?.verify_ssl_certs || false,
enableStartTLS: appConfig.smtp_settings?.enable_start_tls,
enableHostExpiry:
appConfig.host_expiry_settings.host_expiry_enabled || false,
hostExpiryWindow: appConfig.host_expiry_settings.host_expiry_window || 0,
deleteActivities:
appConfig.activity_expiry_settings?.activity_expiry_enabled || false,
activityExpiryWindow:
appConfig.activity_expiry_settings?.activity_expiry_window || 30,
disableLiveQuery: appConfig.server_settings.live_query_disabled || false,
disableQueryReports:
appConfig.server_settings.query_reports_disabled || false,
@@ -38,20 +60,35 @@ const Advanced = ({
enableStartTLS,
enableHostExpiry,
hostExpiryWindow,
deleteActivities,
activityExpiryWindow,
disableLiveQuery,
disableScripts,
disableQueryReports,
} = formData;
const [formErrors, setFormErrors] = useState<IAppConfigFormErrors>({});
const [formErrors, setFormErrors] = useState<IAdvancedConfigFormErrors>({});
const handleInputChange = ({ name, value }: IFormField) => {
const activityExpiryWindowOptions = useMemo(
() =>
getCustomDropdownOptions(
ACTIVITY_EXPIRY_WINDOW_DROPDOWN_OPTIONS,
activityExpiryWindow,
// it's safe to assume that frequency is a number
(frequency: number | string) => `${frequency as number} days`
),
// intentionally leave activityExpiryWindow out of the dependencies, so that the custom
// options are maintained even if the user changes the frequency in the UI
[deleteActivities]
);
const onInputChange = ({ name, value }: IFormField) => {
setFormData({ ...formData, [name]: value });
};
useEffect(() => {
// validate desired form fields
const errors: IAppConfigFormErrors = {};
const errors: IAdvancedConfigFormErrors = {};
if (enableHostExpiry && (!hostExpiryWindow || hostExpiryWindow <= 0)) {
errors.host_expiry_window =
@@ -72,12 +109,13 @@ const Advanced = ({
enable_analytics: appConfig.server_settings.enable_analytics,
query_reports_disabled: disableQueryReports,
scripts_disabled: disableScripts,
deferred_save_host: appConfig.server_settings.deferred_save_host,
},
smtp_settings: {
enable_smtp: appConfig.smtp_settings?.enable_smtp || false,
sender_address: appConfig.smtp_settings?.sender_address || "",
server: appConfig.smtp_settings?.server || "",
port: Number(appConfig.smtp_settings?.port),
port: appConfig.smtp_settings?.port || undefined,
authentication_type: appConfig.smtp_settings?.authentication_type || "",
user_name: appConfig.smtp_settings?.user_name || "",
password: appConfig.smtp_settings?.password || "",
@@ -86,11 +124,15 @@ const Advanced = ({
appConfig.smtp_settings?.authentication_method || "",
domain,
verify_ssl_certs: verifySSLCerts,
enable_start_tls: enableStartTLS,
enable_start_tls: enableStartTLS || false,
},
host_expiry_settings: {
host_expiry_enabled: enableHostExpiry,
host_expiry_window: Number(hostExpiryWindow),
host_expiry_window: hostExpiryWindow || undefined,
},
activity_expiry_settings: {
activity_expiry_enabled: deleteActivities,
activity_expiry_window: activityExpiryWindow || undefined,
},
};
@@ -107,7 +149,7 @@ const Advanced = ({
</p>
<InputField
label="Domain"
onChange={handleInputChange}
onChange={onInputChange}
name="domain"
value={domain}
parseTarget
@@ -122,7 +164,7 @@ const Advanced = ({
}
/>
<Checkbox
onChange={handleInputChange}
onChange={onInputChange}
name="verifySSLCerts"
value={verifySSLCerts}
parseTarget
@@ -140,7 +182,7 @@ const Advanced = ({
Verify SSL certs
</Checkbox>
<Checkbox
onChange={handleInputChange}
onChange={onInputChange}
name="enableStartTLS"
value={enableStartTLS}
parseTarget
@@ -158,7 +200,7 @@ const Advanced = ({
Enable STARTTLS
</Checkbox>
<Checkbox
onChange={handleInputChange}
onChange={onInputChange}
name="enableHostExpiry"
value={enableHostExpiry}
parseTarget
@@ -187,7 +229,7 @@ const Advanced = ({
<InputField
label="Host expiry window"
type="number"
onChange={handleInputChange}
onChange={onInputChange}
name="hostExpiryWindow"
value={hostExpiryWindow}
parseTarget
@@ -195,7 +237,37 @@ const Advanced = ({
/>
)}
<Checkbox
onChange={handleInputChange}
onChange={onInputChange}
name="deleteActivities"
value={deleteActivities}
parseTarget
tooltipContent={
<>
When enabled, allows automatic cleanup of audit logs older than
the number of days specified in the{" "}
<em>Audit log retention window</em> setting.
<em>
(Default: <strong>Off</strong>)
</em>
</>
}
>
Delete activities
</Checkbox>
{deleteActivities && (
<Dropdown
searchable={false}
options={activityExpiryWindowOptions}
onChange={onInputChange}
placeholder="Select"
value={activityExpiryWindow}
label="Max activity age"
name="Max activity age"
parseTarget
/>
)}
<Checkbox
onChange={onInputChange}
name="disableLiveQuery"
value={disableLiveQuery}
parseTarget
@@ -212,7 +284,7 @@ const Advanced = ({
Disable live queries
</Checkbox>
<Checkbox
onChange={handleInputChange}
onChange={onInputChange}
name="disableScripts"
value={disableScripts}
parseTarget
@@ -229,7 +301,7 @@ const Advanced = ({
Disable scripts
</Checkbox>
<Checkbox
onChange={handleInputChange}
onChange={onInputChange}
name="disableQueryReports"
value={disableQueryReports}
parseTarget
@@ -13,10 +13,18 @@ import YamlAce from "components/YamlAce";
import CustomLink from "components/CustomLink";
import SectionHeader from "components/SectionHeader";
import { IAppConfigFormProps, IAppConfigFormErrors } from "../constants";
import { IAppConfigFormProps } from "../constants";
const baseClass = "app-config-form";
interface IAgentOptionsFormData {
agentOptions?: string;
}
interface IAgentOptionsFormErrors {
agent_options?: string | null;
}
const Agents = ({
appConfig,
handleSubmit,
@@ -25,10 +33,10 @@ const Agents = ({
}: IAppConfigFormProps): JSX.Element => {
const { ADMIN_TEAMS } = paths;
const [formData, setFormData] = useState<any>({
const [formData, setFormData] = useState<IAgentOptionsFormData>({
agentOptions: agentOptionsToYaml(appConfig.agent_options),
});
const [formErrors, setFormErrors] = useState<IAppConfigFormErrors>({});
const [formErrors, setFormErrors] = useState<IAgentOptionsFormErrors>({});
const { agentOptions } = formData;
@@ -37,7 +45,7 @@ const Agents = ({
};
const validateForm = () => {
const errors: IAppConfigFormErrors = {};
const errors: IAgentOptionsFormErrors = {};
if (agentOptions) {
const { error: yamlError, valid: yamlValid } = validateYaml(agentOptions);
@@ -58,7 +66,7 @@ const Agents = ({
evt.preventDefault();
// Formatting of API not UI and allows empty agent options
const formDataToSubmit = agentOptions
const formDataToSubmit: any = agentOptions
? {
agent_options: yaml.load(agentOptions),
}
@@ -1,6 +1,6 @@
import React, { useState } from "react";
import { IConfig, IConfigFormData } from "interfaces/config";
import { IConfig } from "interfaces/config";
import Button from "components/buttons/Button";
// @ts-ignore
@@ -13,9 +13,14 @@ import {
DEFAULT_TRANSPARENCY_URL,
IAppConfigFormProps,
IFormField,
IAppConfigFormErrors,
} from "../constants";
interface IFleetDesktopFormData {
transparencyUrl: string;
}
interface IFleetDesktopFormErrors {
transparency_url?: string | null;
}
const baseClass = "app-config-form";
const FleetDesktop = ({
@@ -24,16 +29,14 @@ const FleetDesktop = ({
isPremiumTier,
isUpdatingSettings,
}: IAppConfigFormProps): JSX.Element => {
const [formData, setFormData] = useState<
Pick<IConfigFormData, "transparencyUrl">
>({
const [formData, setFormData] = useState<IFleetDesktopFormData>({
transparencyUrl:
appConfig.fleet_desktop?.transparency_url || DEFAULT_TRANSPARENCY_URL,
});
const [formErrors, setFormErrors] = useState<IAppConfigFormErrors>({});
const [formErrors, setFormErrors] = useState<IFleetDesktopFormErrors>({});
const handleInputChange = ({ value }: IFormField) => {
const onInputChange = ({ value }: IFormField) => {
setFormData({ transparencyUrl: value.toString() });
setFormErrors({});
};
@@ -41,7 +44,7 @@ const FleetDesktop = ({
const validateForm = () => {
const { transparencyUrl } = formData;
const errors: IAppConfigFormErrors = {};
const errors: IFleetDesktopFormErrors = {};
if (transparencyUrl && !validUrl({ url: transparencyUrl })) {
errors.transparency_url = `${transparencyUrl} is not a valid URL`;
}
@@ -72,7 +75,7 @@ const FleetDesktop = ({
<form onSubmit={onFormSubmit} autoComplete="off">
<InputField
label="Custom transparency URL"
onChange={handleInputChange}
onChange={onInputChange}
name="transparency_url"
value={formData.transparencyUrl}
parseTarget
@@ -18,20 +18,20 @@ import InputField from "components/forms/fields/InputField";
import validUrl from "components/forms/validators/valid_url";
import SectionHeader from "components/SectionHeader";
import {
IAppConfigFormProps,
IFormField,
IAppConfigFormErrors,
} from "../constants";
import { IAppConfigFormProps, IFormField } from "../constants";
const baseClass = "app-config-form";
export type IGlobalHostStatusWebhookFormData = {
interface IGlobalHostStatusWebhookFormData {
enableHostStatusWebhook: boolean;
destination_url: string;
destination_url?: string;
hostStatusWebhookHostPercentage: number;
hostStatusWebhookWindow: number;
};
}
interface IGlobalHostStatusWebhookFormErrors {
destination_url?: string;
}
const baseClass = "app-config-form";
const GlobalHostStatusWebhook = ({
appConfig,
@@ -61,15 +61,18 @@ const GlobalHostStatusWebhook = ({
hostStatusWebhookWindow,
} = formData;
const [formErrors, setFormErrors] = useState<IAppConfigFormErrors>({});
const [
formErrors,
setFormErrors,
] = useState<IGlobalHostStatusWebhookFormErrors>({});
const handleInputChange = ({ name, value }: IFormField) => {
const onInputChange = ({ name, value }: IFormField) => {
setFormData({ ...formData, [name]: value });
setFormErrors({});
};
const validateForm = () => {
const errors: IAppConfigFormErrors = {};
const errors: IGlobalHostStatusWebhookFormErrors = {};
if (enableHostStatusWebhook) {
if (!destination_url) {
@@ -103,6 +106,10 @@ const GlobalHostStatusWebhook = ({
host_percentage: hostStatusWebhookHostPercentage,
days_count: hostStatusWebhookWindow,
},
failing_policies_webhook:
appConfig.webhook_settings.failing_policies_webhook,
vulnerabilities_webhook:
appConfig.webhook_settings.vulnerabilities_webhook,
},
};
@@ -139,7 +146,7 @@ const GlobalHostStatusWebhook = ({
Send an alert if a portion of your hosts go offline.
</p>
<Checkbox
onChange={handleInputChange}
onChange={onInputChange}
name="enableHostStatusWebhook"
value={enableHostStatusWebhook}
parseTarget
@@ -165,7 +172,7 @@ const GlobalHostStatusWebhook = ({
<InputField
placeholder="https://server.com/example"
label="Destination URL"
onChange={handleInputChange}
onChange={onInputChange}
name="destination_url"
value={destination_url}
parseTarget
@@ -181,7 +188,7 @@ const GlobalHostStatusWebhook = ({
<Dropdown
label="Percentage of hosts"
options={percentageHostsOptions}
onChange={handleInputChange}
onChange={onInputChange}
name="hostStatusWebhookHostPercentage"
value={hostStatusWebhookHostPercentage}
parseTarget
@@ -200,7 +207,7 @@ const GlobalHostStatusWebhook = ({
<Dropdown
label="Number of days"
options={windowOptions}
onChange={handleInputChange}
onChange={onInputChange}
name="hostStatusWebhookWindow"
value={hostStatusWebhookWindow}
parseTarget
@@ -8,19 +8,22 @@ import OrgLogoIcon from "components/icons/OrgLogoIcon";
import validUrl from "components/forms/validators/valid_url";
import SectionHeader from "components/SectionHeader";
import {
IAppConfigFormProps,
IFormField,
IAppConfigFormErrors,
} from "../constants";
import { IAppConfigFormProps, IFormField } from "../constants";
interface IOrgInfoFormData {
orgName: string;
orgLogoURL: string;
orgName: string;
orgLogoURLLightBackground: string;
orgSupportURL: string;
}
interface IOrgInfoFormErrors {
org_name?: string | null;
org_logo_url?: string | null;
org_logo_url_light_background?: string | null;
org_support_url?: string | null;
}
// TODO: change base classes to these cards to follow the same pattern as the
// other components in the app.
const baseClass = "app-config-form";
@@ -47,15 +50,15 @@ const Info = ({
orgSupportURL,
} = formData;
const [formErrors, setFormErrors] = useState<IAppConfigFormErrors>({});
const [formErrors, setFormErrors] = useState<IOrgInfoFormErrors>({});
const handleInputChange = ({ name, value }: IFormField) => {
const onInputChange = ({ name, value }: IFormField) => {
setFormData({ ...formData, [name]: value });
setFormErrors({});
};
const validateForm = () => {
const errors: IAppConfigFormErrors = {};
const errors: IOrgInfoFormErrors = {};
if (!orgName) {
errors.org_name = "Organization name must be present";
@@ -96,7 +99,7 @@ const Info = ({
<form onSubmit={onFormSubmit} autoComplete="off">
<InputField
label="Organization name"
onChange={handleInputChange}
onChange={onInputChange}
name="orgName"
value={orgName}
parseTarget
@@ -105,7 +108,7 @@ const Info = ({
/>
<InputField
label="Organization support URL"
onChange={handleInputChange}
onChange={onInputChange}
name="orgSupportURL"
value={orgSupportURL}
parseTarget
@@ -115,7 +118,7 @@ const Info = ({
<div className={`${cardClass}__logo-field-set`}>
<InputField
label="Organization avatar URL (for dark backgrounds)"
onChange={handleInputChange}
onChange={onInputChange}
name="orgLogoURL"
value={orgLogoURL}
parseTarget
@@ -137,7 +140,7 @@ const Info = ({
<div className={`${cardClass}__logo-field-set`}>
<InputField
label="Organization avatar URL (for light backgrounds)"
onChange={handleInputChange}
onChange={onInputChange}
name="orgLogoURLLightBackground"
value={orgLogoURLLightBackground}
parseTarget
@@ -16,11 +16,30 @@ import SectionHeader from "components/SectionHeader";
import {
IAppConfigFormProps,
IFormField,
IAppConfigFormErrors,
authMethodOptions,
authTypeOptions,
} from "../constants";
interface ISmtpConfigFormData {
enableSMTP: boolean;
smtpSenderAddress: string;
smtpServer: string;
smtpPort?: number;
smtpEnableSSLTLS: boolean;
smtpAuthenticationType: string;
smtpUsername: string;
smtpPassword: string;
smtpAuthenticationMethod: string;
}
interface ISmtpConfigFormErrors {
sender_address?: string | null;
server?: string | null;
server_port?: string | null;
user_name?: string | null;
password?: string | null;
}
const baseClass = "app-config-form";
const Smtp = ({
@@ -30,7 +49,7 @@ const Smtp = ({
}: IAppConfigFormProps): JSX.Element => {
const { isPremiumTier } = useContext(AppContext);
const [formData, setFormData] = useState<any>({
const [formData, setFormData] = useState<ISmtpConfigFormData>({
enableSMTP: appConfig.smtp_settings?.enable_smtp || false,
smtpSenderAddress: appConfig.smtp_settings?.sender_address || "",
smtpServer: appConfig.smtp_settings?.server || "",
@@ -55,16 +74,16 @@ const Smtp = ({
smtpAuthenticationMethod,
} = formData;
const [formErrors, setFormErrors] = useState<IAppConfigFormErrors>({});
const [formErrors, setFormErrors] = useState<ISmtpConfigFormErrors>({});
const sesConfigured = appConfig.email?.backend === "ses" || false;
const handleInputChange = ({ name, value }: IFormField) => {
const onInputChange = ({ name, value }: IFormField) => {
setFormData({ ...formData, [name]: value });
};
const validateForm = () => {
const errors: IAppConfigFormErrors = {};
const errors: ISmtpConfigFormErrors = {};
if (enableSMTP) {
if (!smtpSenderAddress) {
@@ -118,7 +137,8 @@ const Smtp = ({
authentication_method: smtpAuthenticationMethod,
domain: appConfig.smtp_settings?.domain || "",
verify_ssl_certs: appConfig.smtp_settings?.verify_ssl_certs || false,
enable_start_tls: appConfig.smtp_settings?.enable_start_tls,
enable_start_tls: appConfig.smtp_settings?.enable_start_tls || false,
configured: appConfig.smtp_settings?.configured || false,
},
};
@@ -134,7 +154,7 @@ const Smtp = ({
<>
<InputField
label="SMTP username"
onChange={handleInputChange}
onChange={onInputChange}
name="smtpUsername"
value={smtpUsername}
parseTarget
@@ -145,7 +165,7 @@ const Smtp = ({
<InputField
label="SMTP password"
type="password"
onChange={handleInputChange}
onChange={onInputChange}
name="smtpPassword"
value={smtpPassword}
parseTarget
@@ -157,7 +177,7 @@ const Smtp = ({
label="Auth method"
options={authMethodOptions}
placeholder=""
onChange={handleInputChange}
onChange={onInputChange}
name="smtpAuthenticationMethod"
value={smtpAuthenticationMethod}
parseTarget
@@ -189,7 +209,7 @@ const Smtp = ({
return (
<form onSubmit={onFormSubmit} autoComplete="off">
<Checkbox
onChange={handleInputChange}
onChange={onInputChange}
name="enableSMTP"
value={enableSMTP}
parseTarget
@@ -198,7 +218,7 @@ const Smtp = ({
</Checkbox>
<InputField
label="Sender address"
onChange={handleInputChange}
onChange={onInputChange}
name="smtpSenderAddress"
value={smtpSenderAddress}
parseTarget
@@ -209,7 +229,7 @@ const Smtp = ({
<div className="smtp-server-inputs">
<InputField
label="SMTP server"
onChange={handleInputChange}
onChange={onInputChange}
name="smtpServer"
value={smtpServer}
parseTarget
@@ -220,7 +240,7 @@ const Smtp = ({
<InputField
label="&nbsp;"
type="number"
onChange={handleInputChange}
onChange={onInputChange}
name="smtpPort"
value={smtpPort}
parseTarget
@@ -229,7 +249,7 @@ const Smtp = ({
/>
</div>
<Checkbox
onChange={handleInputChange}
onChange={onInputChange}
name="smtpEnableSSLTLS"
value={smtpEnableSSLTLS}
parseTarget
@@ -239,7 +259,7 @@ const Smtp = ({
<Dropdown
label="Authentication type"
options={authTypeOptions}
onChange={handleInputChange}
onChange={onInputChange}
name="smtpAuthenticationType"
value={smtpAuthenticationType}
parseTarget
@@ -8,23 +8,27 @@ import InputField from "components/forms/fields/InputField";
import validUrl from "components/forms/validators/valid_url";
import SectionHeader from "components/SectionHeader";
import {
IAppConfigFormProps,
IFormField,
IAppConfigFormErrors,
} from "../constants";
import { IAppConfigFormProps, IFormField } from "../constants";
const baseClass = "app-config-form";
interface ISsoFormData {
enableSso?: boolean;
idpName?: string;
entityId?: string;
idpImageUrl?: string;
metadata?: string;
metadataUrl?: string;
enableSsoIdpLogin?: boolean;
enableJitProvisioning?: boolean;
idpName: string;
enableSso: boolean;
entityId: string;
idpImageUrl: string;
metadata: string;
metadataUrl: string;
enableSsoIdpLogin: boolean;
enableJitProvisioning: boolean;
}
interface ISsoFormErrors {
idp_image_url?: string | null;
metadata?: string | null;
metadata_url?: string | null;
entity_id?: string | null;
idp_name?: string | null;
}
const Sso = ({
@@ -56,14 +60,14 @@ const Sso = ({
enableJitProvisioning,
} = formData;
const [formErrors, setFormErrors] = useState<IAppConfigFormErrors>({});
const [formErrors, setFormErrors] = useState<ISsoFormErrors>({});
const handleInputChange = ({ name, value }: IFormField) => {
const onInputChange = ({ name, value }: IFormField) => {
setFormData({ ...formData, [name]: value });
};
const validateForm = () => {
const errors: IAppConfigFormErrors = {};
const errors: ISsoFormErrors = {};
if (enableSso) {
if (idpImageUrl && !validUrl({ url: idpImageUrl })) {
@@ -113,6 +117,8 @@ const Sso = ({
enable_sso: enableSso,
enable_sso_idp_login: enableSsoIdpLogin,
enable_jit_provisioning: enableJitProvisioning,
issuer_uri: appConfig.sso_settings.issuer_uri,
enable_jit_role_sync: appConfig.sso_settings.enable_jit_role_sync,
},
};
@@ -125,7 +131,7 @@ const Sso = ({
<SectionHeader title="Single sign-on options" />
<form onSubmit={onFormSubmit} autoComplete="off">
<Checkbox
onChange={handleInputChange}
onChange={onInputChange}
name="enableSso"
value={enableSso}
parseTarget
@@ -134,7 +140,7 @@ const Sso = ({
</Checkbox>
<InputField
label="Identity provider name"
onChange={handleInputChange}
onChange={onInputChange}
name="idpName"
value={idpName}
parseTarget
@@ -145,7 +151,7 @@ const Sso = ({
<InputField
label="Entity ID"
helpText="The URI you provide here must exactly match the Entity ID field used in identity provider configuration."
onChange={handleInputChange}
onChange={onInputChange}
name="entityId"
value={entityId}
parseTarget
@@ -155,7 +161,7 @@ const Sso = ({
/>
<InputField
label="IDP image URL"
onChange={handleInputChange}
onChange={onInputChange}
name="idpImageUrl"
value={idpImageUrl}
parseTarget
@@ -167,7 +173,7 @@ const Sso = ({
<InputField
label="Metadata"
type="textarea"
onChange={handleInputChange}
onChange={onInputChange}
name="metadata"
value={metadata}
parseTarget
@@ -179,7 +185,7 @@ const Sso = ({
<InputField
label="Metadata URL"
helpText="If available from the identity provider, this is the preferred means of providing metadata."
onChange={handleInputChange}
onChange={onInputChange}
name="metadataUrl"
value={metadataUrl}
parseTarget
@@ -188,7 +194,7 @@ const Sso = ({
tooltip="A URL that references the identity provider metadata."
/>
<Checkbox
onChange={handleInputChange}
onChange={onInputChange}
name="enableSsoIdpLogin"
value={enableSsoIdpLogin}
parseTarget
@@ -197,7 +203,7 @@ const Sso = ({
</Checkbox>
{isPremiumTier && (
<Checkbox
onChange={handleInputChange}
onChange={onInputChange}
name="enableJitProvisioning"
value={enableJitProvisioning}
parseTarget
@@ -9,19 +9,23 @@ import { IAppConfigFormProps, IFormField } from "../constants";
const baseClass = "app-config-form";
interface IStatisticsFormData {
enableUsageStatistics: boolean;
}
const Statistics = ({
appConfig,
handleSubmit,
isPremiumTier,
isUpdatingSettings,
}: IAppConfigFormProps): JSX.Element => {
const [formData, setFormData] = useState<any>({
const [formData, setFormData] = useState<IStatisticsFormData>({
enableUsageStatistics: appConfig.server_settings.enable_analytics,
});
const { enableUsageStatistics } = formData;
const handleInputChange = ({ name, value }: IFormField) => {
const onInputChange = ({ name, value }: IFormField) => {
setFormData({ ...formData, [name]: value });
};
@@ -35,6 +39,10 @@ const Statistics = ({
live_query_disabled:
appConfig.server_settings.live_query_disabled || false,
enable_analytics: enableUsageStatistics,
deferred_save_host: appConfig.server_settings.deferred_save_host,
query_reports_disabled:
appConfig.server_settings.query_reports_disabled,
scripts_disabled: appConfig.server_settings.scripts_disabled,
},
};
@@ -63,7 +71,7 @@ const Statistics = ({
/>
</p>
<Checkbox
onChange={handleInputChange}
onChange={onInputChange}
name="enableUsageStatistics"
value={isPremiumTier ? true : enableUsageStatistics} // Set to true for all premium customers
parseTarget
@@ -6,11 +6,15 @@ import InputField from "components/forms/fields/InputField";
import validUrl from "components/forms/validators/valid_url";
import SectionHeader from "components/SectionHeader";
import {
IAppConfigFormProps,
IFormField,
IAppConfigFormErrors,
} from "../constants";
import { IAppConfigFormProps, IFormField } from "../constants";
interface IWebAddressFormData {
serverURL: string;
}
interface IWebAddressFormErrors {
server_url?: string | null;
}
const baseClass = "app-config-form";
@@ -19,21 +23,21 @@ const WebAddress = ({
handleSubmit,
isUpdatingSettings,
}: IAppConfigFormProps): JSX.Element => {
const [formData, setFormData] = useState<any>({
const [formData, setFormData] = useState<IWebAddressFormData>({
serverURL: appConfig.server_settings.server_url || "",
});
const { serverURL } = formData;
const [formErrors, setFormErrors] = useState<IAppConfigFormErrors>({});
const [formErrors, setFormErrors] = useState<IWebAddressFormErrors>({});
const handleInputChange = ({ name, value }: IFormField) => {
const onInputChange = ({ name, value }: IFormField) => {
setFormData({ ...formData, [name]: value });
setFormErrors({});
};
const validateForm = () => {
const errors: IAppConfigFormErrors = {};
const errors: IWebAddressFormErrors = {};
if (!serverURL) {
errors.server_url = "Fleet server URL must be present";
} else if (!validUrl({ url: serverURL, protocol: "http" })) {
@@ -52,6 +56,10 @@ const WebAddress = ({
server_url: serverURL,
live_query_disabled: appConfig.server_settings.live_query_disabled,
enable_analytics: appConfig.server_settings.enable_analytics,
deferred_save_host: appConfig.server_settings.deferred_save_host,
query_reports_disabled:
appConfig.server_settings.query_reports_disabled,
scripts_disabled: appConfig.server_settings.scripts_disabled,
},
};
@@ -70,7 +78,7 @@ const WebAddress = ({
Include base path only (eg. no <code>/latest</code>)
</>
}
onChange={handleInputChange}
onChange={onInputChange}
name="serverURL"
value={serverURL}
parseTarget
@@ -6,7 +6,7 @@ export interface IAppConfigFormProps {
appConfig: IConfig;
isPremiumTier?: boolean;
isUpdatingSettings?: boolean;
handleSubmit: any;
handleSubmit: (formUpdates: Partial<IConfig>) => false | undefined;
}
export interface IFormField {
@@ -14,30 +14,6 @@ export interface IFormField {
value: string | boolean | number;
}
export interface IAppConfigFormErrors {
metadata?: string | null;
metadata_url?: string | null;
entity_id?: string | null;
idp_name?: string | null;
server_url?: string | null;
org_name?: string | null;
org_logo_url?: string | null;
org_logo_url_light_background?: string | null;
org_support_url?: string | null;
idp_image_url?: string | null;
sender_address?: string | null;
server?: string | null;
server_port?: string | null;
user_name?: string | null;
password?: string | null;
destination_url?: string | null;
days_count?: string | null;
host_percentage?: string | null;
host_expiry_window?: string | null;
agent_options?: string | null;
transparency_url?: string | null;
}
export const authMethodOptions = [
{ label: "Plain", value: "authmethod_plain" },
{ label: "Cram MD5", value: "authmethod_cram_md5" },
+6
View File
@@ -26,6 +26,12 @@ export const DEFAULT_GRAVATAR_LINK_FALLBACK =
export const DEFAULT_GRAVATAR_LINK_DARK_FALLBACK =
"/assets/images/icon-avatar-default-dark-24x24%402x.png";
export const ACTIVITY_EXPIRY_WINDOW_DROPDOWN_OPTIONS: IDropdownOption[] = [
{ value: 30, label: "30 days" },
{ value: 60, label: "60 days" },
{ value: 90, label: "90 days" },
];
export const FREQUENCY_DROPDOWN_OPTIONS: IDropdownOption[] = [
{ value: 0, label: "Never" },
{ value: 300, label: "Every 5 minutes" },