Fleet UI: Enable and disable automation slider (#4554)
This commit is contained in:
@@ -0,0 +1 @@
|
||||
* Add the ability to turn on and off software automations and failing policies automations from the UI
|
||||
@@ -127,6 +127,7 @@ describe("Policies flow (seeded)", () => {
|
||||
cy.findByRole("button", { name: /manage automations/i }).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
cy.getAttached(".fleet-checkbox__input").check({ force: true });
|
||||
});
|
||||
cy.getAttached("#webhook-url").click().type("www.foo.com/bar");
|
||||
|
||||
@@ -197,15 +197,25 @@ describe(
|
||||
cy.loginWithCySession("anna@organization.com", "user123#");
|
||||
cy.visit("/software/manage");
|
||||
});
|
||||
it("allows global admin to click 'Manage automations' button", () => {
|
||||
it("allows global admin to update software vulnerability automation", () => {
|
||||
cy.getAttached(".manage-software-page__header-wrap").within(() => {
|
||||
cy.findByRole("button", { name: /manage automations/i }).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal__button-wrap").within(() => {
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
});
|
||||
cy.getAttached("#webhook-url").click().type("www.foo.com/bar");
|
||||
cy.findByRole("button", { name: /^Save$/ }).click();
|
||||
// Confirm manage automations webhook was added successfully
|
||||
cy.findByText(/updated vulnerability automations/i).should("exist");
|
||||
cy.getAttached(".button-wrap").within(() => {
|
||||
cy.findByRole("button", {
|
||||
name: /cancel/i,
|
||||
name: /manage automations/i,
|
||||
}).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider--active").should("exist");
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("Query pages", () => {
|
||||
|
||||
@@ -114,18 +114,28 @@ describe("Premium tier - Admin user", () => {
|
||||
});
|
||||
describe("Manage software page", () => {
|
||||
beforeEach(() => cy.visit("/software/manage"));
|
||||
it("allows global admin to click 'Manage automations' button", () => {
|
||||
it("allows global admin to update software vulnerability automation", () => {
|
||||
cy.getAttached(".manage-software-page__header-wrap").within(() => {
|
||||
cy.getAttached(".Select").within(() => {
|
||||
cy.findByText(/all teams/i).should("exist");
|
||||
});
|
||||
cy.findByRole("button", { name: /manage automations/i }).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal__button-wrap").within(() => {
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider").click();
|
||||
});
|
||||
cy.getAttached("#webhook-url").click().type("www.foo.com/bar");
|
||||
cy.findByRole("button", { name: /^Save$/ }).click();
|
||||
// Confirm manage automations webhook was added successfully
|
||||
cy.findByText(/updated vulnerability automations/i).should("exist");
|
||||
cy.getAttached(".button-wrap").within(() => {
|
||||
cy.findByRole("button", {
|
||||
name: /cancel/i,
|
||||
name: /manage automations/i,
|
||||
}).click();
|
||||
});
|
||||
cy.getAttached(".manage-automations-modal").within(() => {
|
||||
cy.getAttached(".fleet-slider--active").should("exist");
|
||||
});
|
||||
});
|
||||
it("hides manage automations button since all teams not selected", () => {
|
||||
cy.getAttached(".manage-software-page__header-wrap").within(() => {
|
||||
|
||||
@@ -37,4 +37,8 @@
|
||||
&--checkbox {
|
||||
margin-bottom: $pad-medium;
|
||||
}
|
||||
|
||||
&--slider {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
+26
-19
@@ -1,13 +1,21 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import classnames from "classnames";
|
||||
import { pick } from "lodash";
|
||||
|
||||
import FormField from "components/forms/FormField";
|
||||
import { IFormFieldProps } from "components/forms/FormField/FormField";
|
||||
|
||||
const Slider = (props) => {
|
||||
const { onChange, value, inactiveText = "Off", activeText = "On" } = props;
|
||||
const baseClass = "fleet-slider";
|
||||
interface ISliderProps {
|
||||
onChange: () => void;
|
||||
value: boolean;
|
||||
inactiveText: string;
|
||||
activeText: string;
|
||||
}
|
||||
|
||||
const baseClass = "fleet-slider";
|
||||
|
||||
const Slider = (props: ISliderProps): JSX.Element => {
|
||||
const { onChange, value, inactiveText, activeText } = props;
|
||||
|
||||
const sliderBtnClass = classnames(baseClass, {
|
||||
[`${baseClass}--active`]: value,
|
||||
@@ -17,39 +25,38 @@ const Slider = (props) => {
|
||||
[`${baseClass}__dot--active`]: value,
|
||||
});
|
||||
|
||||
const handleClick = (evt) => {
|
||||
const handleClick = (evt: React.MouseEvent) => {
|
||||
evt.preventDefault();
|
||||
|
||||
return onChange(!value);
|
||||
return onChange();
|
||||
};
|
||||
|
||||
const formFieldProps = pick(props, ["hint", "label", "error", "name"]);
|
||||
const formFieldProps = pick(props, [
|
||||
"hint",
|
||||
"label",
|
||||
"error",
|
||||
"name",
|
||||
]) as IFormFieldProps;
|
||||
|
||||
return (
|
||||
<FormField {...formFieldProps} type="slider">
|
||||
<div className={`${baseClass}__wrapper`}>
|
||||
<span className={`${baseClass}__label ${baseClass}__label--inactive`}>
|
||||
{inactiveText}
|
||||
</span>
|
||||
<button
|
||||
className={`button button--unstyled ${sliderBtnClass}`}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<div className={sliderDotClass} />
|
||||
</button>
|
||||
<span className={`${baseClass}__label ${baseClass}__label--active`}>
|
||||
{activeText}
|
||||
<span
|
||||
className={`${baseClass}__label ${baseClass}__label--${
|
||||
value ? "active" : "inactive"
|
||||
}`}
|
||||
>
|
||||
{value ? activeText : inactiveText}
|
||||
</span>
|
||||
</div>
|
||||
</FormField>
|
||||
);
|
||||
};
|
||||
|
||||
Slider.propTypes = {
|
||||
value: PropTypes.bool,
|
||||
onChange: PropTypes.func,
|
||||
inactiveText: PropTypes.string,
|
||||
activeText: PropTypes.string,
|
||||
};
|
||||
|
||||
export default Slider;
|
||||
@@ -1,19 +1,16 @@
|
||||
.fleet-slider {
|
||||
transition: background-color 150ms ease-in-out;
|
||||
background-color: $core-fleet-black;
|
||||
background-color: $ui-fleet-black-50;
|
||||
border-radius: 12px;
|
||||
border: 1px solid #eaeaea;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
height: 22px;
|
||||
min-width: 40px;
|
||||
height: 20px;
|
||||
min-width: 35px;
|
||||
position: relative;
|
||||
width: 40px;
|
||||
box-shadow: inset 0 1px 6px 0 rgba(0, 0, 0, 0.2);
|
||||
width: 35px;
|
||||
|
||||
&:hover {
|
||||
background-color: $core-fleet-black;
|
||||
box-shadow: inset 0 1px 6px 0 rgba(0, 0, 0, 0.2);
|
||||
background-color: $ui-fleet-black-50;
|
||||
}
|
||||
|
||||
&--active {
|
||||
@@ -31,31 +28,22 @@
|
||||
}
|
||||
|
||||
&__dot {
|
||||
@include size(14px);
|
||||
@include position(absolute, 0 null null 5px);
|
||||
@include size(16px);
|
||||
@include position(absolute, 2px null null 2px);
|
||||
transition: left 150ms ease-in-out;
|
||||
margin-top: 3px;
|
||||
border-radius: 50%;
|
||||
background-color: $core-white;
|
||||
box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.25);
|
||||
|
||||
&--active {
|
||||
left: 21px;
|
||||
left: 17px;
|
||||
}
|
||||
}
|
||||
|
||||
&__label {
|
||||
font-size: $small;
|
||||
font-size: $x-small;
|
||||
font-weight: $regular;
|
||||
text-align: left;
|
||||
vertical-align: text-bottom;
|
||||
margin-right: 10px;
|
||||
color: $core-fleet-blue;
|
||||
|
||||
&--active {
|
||||
color: $core-vibrant-blue;
|
||||
margin-right: 0;
|
||||
margin-left: 10px;
|
||||
}
|
||||
margin-left: $pad-small;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,6 +517,11 @@ const ManagePolicyPage = ({
|
||||
failingPoliciesWebhook.destination_url) ||
|
||||
""
|
||||
}
|
||||
enableFailingPoliciesWebhook={
|
||||
(failingPoliciesWebhook &&
|
||||
failingPoliciesWebhook.enable_failing_policies_webhook) ||
|
||||
false
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{showAddPolicyModal && (
|
||||
|
||||
+75
-49
@@ -7,6 +7,7 @@ import { size } from "lodash";
|
||||
|
||||
import Modal from "components/Modal";
|
||||
import Button from "components/buttons/Button";
|
||||
import Slider from "components/forms/fields/Slider";
|
||||
// @ts-ignore
|
||||
import Checkbox from "components/forms/fields/Checkbox";
|
||||
// @ts-ignore
|
||||
@@ -21,6 +22,7 @@ interface IManageAutomationsModalProps {
|
||||
availablePolicies: IPolicy[];
|
||||
currentAutomatedPolicies?: number[];
|
||||
currentDestinationUrl?: string;
|
||||
enableFailingPoliciesWebhook: boolean;
|
||||
}
|
||||
|
||||
interface ICheckedPolicy {
|
||||
@@ -92,11 +94,16 @@ const ManageAutomationsModal = ({
|
||||
availablePolicies,
|
||||
currentAutomatedPolicies,
|
||||
currentDestinationUrl,
|
||||
enableFailingPoliciesWebhook,
|
||||
}: IManageAutomationsModalProps): JSX.Element => {
|
||||
const [destination_url, setDestinationUrl] = useState<string>(
|
||||
currentDestinationUrl || ""
|
||||
);
|
||||
const [errors, setErrors] = useState<{ [key: string]: string }>({});
|
||||
const [
|
||||
policyAutomationEnabled,
|
||||
setPolicyAutomationEnabled,
|
||||
] = useState<boolean>(enableFailingPoliciesWebhook);
|
||||
|
||||
const { policyItems, updatePolicyItems } = useCheckboxListStateManagement(
|
||||
availablePolicies,
|
||||
@@ -127,14 +134,13 @@ const ManageAutomationsModal = ({
|
||||
policyItems
|
||||
.filter((policy) => policy.isChecked)
|
||||
.map((policy) => policy.id);
|
||||
const enable_failing_policies_webhook = true; // Leave nearest component in case we decide to add disabling as a UI feature
|
||||
|
||||
// URL validation only needed if at least one policy is checked
|
||||
if (valid || policy_ids.length === 0) {
|
||||
if (valid || !enableFailingPoliciesWebhook) {
|
||||
onCreateWebhookSubmit({
|
||||
destination_url,
|
||||
policy_ids,
|
||||
enable_failing_policies_webhook,
|
||||
enable_failing_policies_webhook: policyAutomationEnabled,
|
||||
});
|
||||
|
||||
onReturnToApp();
|
||||
@@ -152,55 +158,75 @@ const ManageAutomationsModal = ({
|
||||
className={baseClass}
|
||||
>
|
||||
<div className={baseClass}>
|
||||
{availablePolicies && availablePolicies.length > 0 ? (
|
||||
<div className={`${baseClass}__policy-select-items`}>
|
||||
<p> Choose which policies you would like to listen to:</p>
|
||||
{policyItems &&
|
||||
policyItems.map((policyItem) => {
|
||||
const { isChecked, name, id } = policyItem;
|
||||
return (
|
||||
<div key={id} className={`${baseClass}__team-item`}>
|
||||
<Checkbox
|
||||
value={isChecked}
|
||||
name={name}
|
||||
onChange={() => updatePolicyItems(policyItem.id)}
|
||||
>
|
||||
{name}
|
||||
</Checkbox>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
<div className={`${baseClass}__no-policies`}>
|
||||
<b>You have no policies.</b>
|
||||
<p>Add a policy to turn on automations.</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="tooltip-wrap tooltip-wrap--input">
|
||||
<InputField
|
||||
inputWrapperClass={`${baseClass}__url-input`}
|
||||
name="webhook-url"
|
||||
label={"Destination URL"}
|
||||
type={"text"}
|
||||
value={destination_url}
|
||||
onChange={onURLChange}
|
||||
error={errors.url}
|
||||
hint={
|
||||
'For each policy, Fleet will send a JSON payload to this URL with a list of the hosts that updated their answer to "No."'
|
||||
<div className={`${baseClass}__software-select-items`}>
|
||||
<Slider
|
||||
value={policyAutomationEnabled}
|
||||
onChange={() =>
|
||||
setPolicyAutomationEnabled(!policyAutomationEnabled)
|
||||
}
|
||||
placeholder={"https://server.com/example"}
|
||||
tooltip="Provide a URL to deliver a webhook request to."
|
||||
inactiveText={"Vulnerability automations disabled"}
|
||||
activeText={"Vulnerability automations enabled"}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
variant="text-link"
|
||||
onClick={togglePreviewPayloadModal}
|
||||
>
|
||||
Preview payload
|
||||
</Button>
|
||||
|
||||
<div className={`${baseClass}__overlay-container`}>
|
||||
<div className={`${baseClass}__policy-automation-enabled`}>
|
||||
{availablePolicies && availablePolicies.length > 0 ? (
|
||||
<div className={`${baseClass}__policy-select-items`}>
|
||||
<p>
|
||||
<strong>
|
||||
Choose which policies you would like to listen to:
|
||||
</strong>
|
||||
</p>
|
||||
{policyItems &&
|
||||
policyItems.map((policyItem) => {
|
||||
const { isChecked, name, id } = policyItem;
|
||||
return (
|
||||
<div key={id} className={`${baseClass}__team-item`}>
|
||||
<Checkbox
|
||||
value={isChecked}
|
||||
name={name}
|
||||
onChange={() => updatePolicyItems(policyItem.id)}
|
||||
>
|
||||
{name}
|
||||
</Checkbox>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
) : (
|
||||
<div className={`${baseClass}__no-policies`}>
|
||||
<b>You have no policies.</b>
|
||||
<p>Add a policy to turn on automations.</p>
|
||||
</div>
|
||||
)}
|
||||
<div className="tooltip-wrap tooltip-wrap--input">
|
||||
<InputField
|
||||
inputWrapperClass={`${baseClass}__url-input`}
|
||||
name="webhook-url"
|
||||
label={"Destination URL"}
|
||||
type={"text"}
|
||||
value={destination_url}
|
||||
onChange={onURLChange}
|
||||
error={errors.url}
|
||||
hint={
|
||||
'For each policy, Fleet will send a JSON payload to this URL with a list of the hosts that updated their answer to "No."'
|
||||
}
|
||||
placeholder={"https://server.com/example"}
|
||||
tooltip="Provide a URL to deliver a webhook request to."
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
variant="text-link"
|
||||
onClick={togglePreviewPayloadModal}
|
||||
>
|
||||
Preview payload
|
||||
</Button>
|
||||
</div>
|
||||
{!policyAutomationEnabled && (
|
||||
<div className={`${baseClass}__overlay`} />
|
||||
)}
|
||||
</div>
|
||||
<div className={`${baseClass}__button-wrap`}>
|
||||
<Button
|
||||
className={`${baseClass}__btn`}
|
||||
|
||||
+15
@@ -26,6 +26,21 @@
|
||||
color: $ui-error;
|
||||
}
|
||||
|
||||
&__overlay-container {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
&__policy-automation-enabled,
|
||||
&__overlay {
|
||||
grid-area: 1 / 1;
|
||||
}
|
||||
|
||||
&__overlay {
|
||||
background-color: $core-white;
|
||||
z-index: 0;
|
||||
opacity: 75%;
|
||||
}
|
||||
|
||||
.tooltip-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
+50
-130
@@ -2,8 +2,7 @@ import React, { useState } from "react";
|
||||
|
||||
import Modal from "components/Modal";
|
||||
import Button from "components/buttons/Button";
|
||||
// @ts-ignore
|
||||
import Checkbox from "components/forms/fields/Checkbox";
|
||||
import Slider from "components/forms/fields/Slider";
|
||||
// @ts-ignore
|
||||
import InputField from "components/forms/fields/InputField";
|
||||
|
||||
@@ -22,75 +21,6 @@ interface IManageAutomationsModalProps {
|
||||
currentDestinationUrl?: string;
|
||||
}
|
||||
|
||||
interface ICheckedSoftwareAutomation {
|
||||
name?: string;
|
||||
accessor: string;
|
||||
isChecked?: boolean;
|
||||
}
|
||||
|
||||
const useCheckboxListStateManagement = (
|
||||
softwareVulnerabilityWebhookEnabled = false
|
||||
) => {
|
||||
// Ability to add future software automations
|
||||
const availableSoftwareAutomations: ICheckedSoftwareAutomation[] = [
|
||||
{ accessor: "vulnerability", name: "Enable vulnerability automations" },
|
||||
];
|
||||
const currentSoftwareAutomations: ICheckedSoftwareAutomation[] = softwareVulnerabilityWebhookEnabled
|
||||
? availableSoftwareAutomations
|
||||
: [];
|
||||
|
||||
const [softwareAutomationsItems, setSoftwareAutomationsItems] = useState<
|
||||
ICheckedSoftwareAutomation[]
|
||||
>(() => {
|
||||
return (
|
||||
availableSoftwareAutomations &&
|
||||
availableSoftwareAutomations.map(
|
||||
(automation: ICheckedSoftwareAutomation) => {
|
||||
return {
|
||||
name: automation.name,
|
||||
accessor: automation.accessor,
|
||||
isChecked: currentSoftwareAutomations.some(
|
||||
(currentSoftwareAutomationItem: ICheckedSoftwareAutomation) =>
|
||||
currentSoftwareAutomationItem.accessor === automation.accessor
|
||||
),
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
const updateSoftwareAutomationsItems = (
|
||||
softwareAutomationAccessor: string
|
||||
) => {
|
||||
setSoftwareAutomationsItems((prevState) => {
|
||||
const selectedSoftwareAutomation = softwareAutomationsItems.find(
|
||||
(softwareAutomationItem) =>
|
||||
softwareAutomationItem.accessor === softwareAutomationAccessor
|
||||
);
|
||||
|
||||
const updatedSoftwareAutomation = selectedSoftwareAutomation && {
|
||||
...selectedSoftwareAutomation,
|
||||
isChecked:
|
||||
!!selectedSoftwareAutomation && !selectedSoftwareAutomation.isChecked,
|
||||
};
|
||||
|
||||
// this is replacing the softwareAutomation object with the updatedSoftwareAutomation we just created
|
||||
const newState = prevState.map((currentSoftwareAutomation) => {
|
||||
return currentSoftwareAutomation.accessor ===
|
||||
softwareAutomationAccessor && updatedSoftwareAutomation
|
||||
? updatedSoftwareAutomation
|
||||
: currentSoftwareAutomation;
|
||||
});
|
||||
return newState;
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
softwareAutomationsItems,
|
||||
updateSoftwareAutomationsItems,
|
||||
};
|
||||
};
|
||||
|
||||
const validateWebhookURL = (url: string) => {
|
||||
const errors: { [key: string]: string } = {};
|
||||
|
||||
@@ -117,10 +47,10 @@ const ManageAutomationsModal = ({
|
||||
);
|
||||
const [errors, setErrors] = useState<{ [key: string]: string }>({});
|
||||
|
||||
const {
|
||||
softwareAutomationsItems,
|
||||
updateSoftwareAutomationsItems,
|
||||
} = useCheckboxListStateManagement(softwareVulnerabilityWebhookEnabled);
|
||||
const [
|
||||
softwareAutomationsEnabled,
|
||||
setSoftwareAutomationsEnabled,
|
||||
] = useState<boolean>(softwareVulnerabilityWebhookEnabled || false);
|
||||
|
||||
useDeepEffect(() => {
|
||||
if (destination_url) {
|
||||
@@ -135,12 +65,6 @@ const ManageAutomationsModal = ({
|
||||
const handleSaveAutomation = (evt: React.MouseEvent<HTMLFormElement>) => {
|
||||
evt.preventDefault();
|
||||
|
||||
// Ability to add future software automations
|
||||
const vulnerabilityWebhook = softwareAutomationsItems.find(
|
||||
(softwareAutomationItem) =>
|
||||
softwareAutomationItem.accessor === "vulnerability"
|
||||
);
|
||||
|
||||
const { valid, errors: newErrors } = validateWebhookURL(destination_url);
|
||||
setErrors({
|
||||
...errors,
|
||||
@@ -148,10 +72,10 @@ const ManageAutomationsModal = ({
|
||||
});
|
||||
|
||||
// URL validation only needed if software automation is checked
|
||||
if (valid || !vulnerabilityWebhook?.isChecked) {
|
||||
if (valid || !softwareAutomationsEnabled) {
|
||||
onCreateWebhookSubmit({
|
||||
destination_url,
|
||||
enable_vulnerabilities_webhook: vulnerabilityWebhook?.isChecked,
|
||||
enable_vulnerabilities_webhook: softwareAutomationsEnabled,
|
||||
});
|
||||
|
||||
onReturnToApp();
|
||||
@@ -170,56 +94,52 @@ const ManageAutomationsModal = ({
|
||||
>
|
||||
<div className={baseClass}>
|
||||
<div className={`${baseClass}__software-select-items`}>
|
||||
{softwareAutomationsItems &&
|
||||
softwareAutomationsItems.map(
|
||||
(softwareItem: ICheckedSoftwareAutomation) => {
|
||||
const { isChecked, name, accessor } = softwareItem;
|
||||
return (
|
||||
<div key={accessor} className={`${baseClass}__team-item`}>
|
||||
<Checkbox
|
||||
value={isChecked}
|
||||
name={name}
|
||||
onChange={() =>
|
||||
updateSoftwareAutomationsItems(softwareItem.accessor)
|
||||
}
|
||||
>
|
||||
{name}
|
||||
</Checkbox>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
<div className={`${baseClass}__software-automation-description`}>
|
||||
<p>
|
||||
A request will be sent to your configured <b>Destination URL</b> if
|
||||
a detected vulnerability (CVE) was published in the last 2 days.
|
||||
</p>
|
||||
</div>
|
||||
<div className="tooltip-wrap tooltip-wrap--input">
|
||||
<InputField
|
||||
inputWrapperClass={`${baseClass}__url-input`}
|
||||
name="webhook-url"
|
||||
label={"Destination URL"}
|
||||
type={"text"}
|
||||
value={destination_url}
|
||||
onChange={onURLChange}
|
||||
error={errors.url}
|
||||
hint={
|
||||
"For each new vulnerability detected, Fleet will send a JSON payload to this URL with a list of the affected hosts."
|
||||
<Slider
|
||||
value={softwareAutomationsEnabled}
|
||||
onChange={() =>
|
||||
setSoftwareAutomationsEnabled(!softwareAutomationsEnabled)
|
||||
}
|
||||
placeholder={"https://server.com/example"}
|
||||
tooltip="Provide a URL to deliver a webhook request to."
|
||||
inactiveText={"Vulnerability automations disabled"}
|
||||
activeText={"Vulnerability automations enabled"}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
variant="text-link"
|
||||
onClick={togglePreviewPayloadModal}
|
||||
>
|
||||
Preview payload
|
||||
</Button>
|
||||
|
||||
<div className={`${baseClass}__overlay-container`}>
|
||||
<div className={`${baseClass}__software-automation-enabled`}>
|
||||
<div className={`${baseClass}__software-automation-description`}>
|
||||
<p>
|
||||
A request will be sent to your configured <b>Destination URL</b>{" "}
|
||||
if a detected vulnerability (CVE) was published in the last 2
|
||||
days.
|
||||
</p>
|
||||
</div>
|
||||
<div className="tooltip-wrap tooltip-wrap--input">
|
||||
<InputField
|
||||
inputWrapperClass={`${baseClass}__url-input`}
|
||||
name="webhook-url"
|
||||
label={"Destination URL"}
|
||||
type={"text"}
|
||||
value={destination_url}
|
||||
onChange={onURLChange}
|
||||
error={errors.url}
|
||||
hint={
|
||||
"For each new vulnerability detected, Fleet will send a JSON payload to this URL with a list of the affected hosts."
|
||||
}
|
||||
placeholder={"https://server.com/example"}
|
||||
tooltip="Provide a URL to deliver a webhook request to."
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
variant="text-link"
|
||||
onClick={togglePreviewPayloadModal}
|
||||
>
|
||||
Preview payload
|
||||
</Button>
|
||||
</div>
|
||||
{!softwareAutomationsEnabled && (
|
||||
<div className={`${baseClass}__overlay`} />
|
||||
)}
|
||||
</div>
|
||||
<div className={`${baseClass}__button-wrap`}>
|
||||
<Button
|
||||
className={`${baseClass}__btn`}
|
||||
|
||||
+15
@@ -26,6 +26,21 @@
|
||||
color: $ui-error;
|
||||
}
|
||||
|
||||
&__overlay-container {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
&__software-automation-enabled,
|
||||
&__overlay {
|
||||
grid-area: 1 / 1;
|
||||
}
|
||||
|
||||
&__overlay {
|
||||
background-color: $core-white;
|
||||
z-index: 0;
|
||||
opacity: 75%;
|
||||
}
|
||||
|
||||
&__software-automation-description {
|
||||
p {
|
||||
margin: $pad-large 0;
|
||||
|
||||
Reference in New Issue
Block a user