2023-07-18 21:10:45 +00:00
|
|
|
|
import React, { useState, useEffect } from "react";
|
2023-07-24 13:47:05 +00:00
|
|
|
|
|
|
|
|
|
|
import Modal from "components/Modal";
|
2023-07-18 21:10:45 +00:00
|
|
|
|
import Button from "components/buttons/Button";
|
|
|
|
|
|
import InfoBanner from "components/InfoBanner/InfoBanner";
|
|
|
|
|
|
import CustomLink from "components/CustomLink/CustomLink";
|
|
|
|
|
|
import Checkbox from "components/forms/fields/Checkbox/Checkbox";
|
|
|
|
|
|
import QueryFrequencyIndicator from "components/QueryFrequencyIndicator/QueryFrequencyIndicator";
|
|
|
|
|
|
import LogDestinationIndicator from "components/LogDestinationIndicator/LogDestinationIndicator";
|
2023-07-24 13:47:05 +00:00
|
|
|
|
|
2023-07-18 21:10:45 +00:00
|
|
|
|
import { ISchedulableQuery } from "interfaces/schedulable_query";
|
2023-07-24 13:47:05 +00:00
|
|
|
|
|
2024-01-03 20:35:02 +00:00
|
|
|
|
interface IManageQueryAutomationsModalProps {
|
2023-07-18 21:10:45 +00:00
|
|
|
|
isUpdatingAutomations: boolean;
|
2024-05-30 14:57:55 +00:00
|
|
|
|
onSubmit: (formData: any) => void; // TODO
|
2023-07-18 21:10:45 +00:00
|
|
|
|
onCancel: () => void;
|
2024-02-06 18:12:54 +00:00
|
|
|
|
isShowingPreviewDataModal: boolean;
|
2023-07-18 21:10:45 +00:00
|
|
|
|
togglePreviewDataModal: () => void;
|
|
|
|
|
|
availableQueries?: ISchedulableQuery[];
|
|
|
|
|
|
automatedQueryIds: number[];
|
|
|
|
|
|
logDestination: string;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
interface ICheckedQuery {
|
|
|
|
|
|
name?: string;
|
|
|
|
|
|
id: number;
|
|
|
|
|
|
isChecked: boolean;
|
|
|
|
|
|
interval: number;
|
2023-07-24 13:47:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-07-18 21:10:45 +00:00
|
|
|
|
const useCheckboxListStateManagement = (
|
|
|
|
|
|
allQueries: ISchedulableQuery[],
|
|
|
|
|
|
automatedQueryIds: number[] | undefined
|
|
|
|
|
|
) => {
|
|
|
|
|
|
const [queryItems, setQueryItems] = useState<ICheckedQuery[]>(() => {
|
|
|
|
|
|
return allQueries.map(({ name, id, interval }) => ({
|
|
|
|
|
|
name,
|
|
|
|
|
|
id,
|
|
|
|
|
|
isChecked: !!automatedQueryIds?.includes(id),
|
|
|
|
|
|
interval,
|
|
|
|
|
|
}));
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const updateQueryItems = (queryId: number) => {
|
|
|
|
|
|
setQueryItems((prevItems) =>
|
|
|
|
|
|
prevItems.map((query) =>
|
|
|
|
|
|
query.id !== queryId ? query : { ...query, isChecked: !query.isChecked }
|
|
|
|
|
|
)
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return { queryItems, updateQueryItems };
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-01-03 20:35:02 +00:00
|
|
|
|
const baseClass = "manage-query-automations-modal";
|
2023-07-18 21:10:45 +00:00
|
|
|
|
|
2024-01-03 20:35:02 +00:00
|
|
|
|
const ManageQueryAutomationsModal = ({
|
2023-07-18 21:10:45 +00:00
|
|
|
|
isUpdatingAutomations,
|
|
|
|
|
|
automatedQueryIds,
|
2024-05-30 14:57:55 +00:00
|
|
|
|
onSubmit,
|
2023-07-18 21:10:45 +00:00
|
|
|
|
onCancel,
|
2024-02-06 18:12:54 +00:00
|
|
|
|
isShowingPreviewDataModal,
|
2023-07-18 21:10:45 +00:00
|
|
|
|
togglePreviewDataModal,
|
|
|
|
|
|
availableQueries,
|
|
|
|
|
|
logDestination,
|
2024-01-03 20:35:02 +00:00
|
|
|
|
}: IManageQueryAutomationsModalProps): JSX.Element => {
|
2023-07-18 21:10:45 +00:00
|
|
|
|
// TODO: Error handling, if any
|
2024-02-06 18:12:54 +00:00
|
|
|
|
// const [errors, setErrors] = useState<{ [key: string]: string }>({});
|
2023-07-18 21:10:45 +00:00
|
|
|
|
|
2023-07-24 14:46:52 +00:00
|
|
|
|
// Client side sort queries alphabetically
|
|
|
|
|
|
const sortedAvailableQueries =
|
|
|
|
|
|
availableQueries?.sort((a, b) =>
|
|
|
|
|
|
a.name.toLowerCase().localeCompare(b.name.toLowerCase())
|
|
|
|
|
|
) || [];
|
|
|
|
|
|
|
2023-07-18 21:10:45 +00:00
|
|
|
|
const { queryItems, updateQueryItems } = useCheckboxListStateManagement(
|
2023-07-24 14:46:52 +00:00
|
|
|
|
sortedAvailableQueries,
|
2023-07-18 21:10:45 +00:00
|
|
|
|
automatedQueryIds || []
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2024-05-30 14:57:55 +00:00
|
|
|
|
const onSubmitQueryAutomations = (
|
|
|
|
|
|
evt: React.MouseEvent<HTMLFormElement> | KeyboardEvent
|
|
|
|
|
|
) => {
|
2023-07-18 21:10:45 +00:00
|
|
|
|
evt.preventDefault();
|
|
|
|
|
|
|
|
|
|
|
|
const newQueryIds: number[] = [];
|
|
|
|
|
|
queryItems?.forEach((p) => p.isChecked && newQueryIds.push(p.id));
|
|
|
|
|
|
|
2024-05-30 14:57:55 +00:00
|
|
|
|
onSubmit(newQueryIds);
|
2023-07-18 21:10:45 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
const listener = (event: KeyboardEvent) => {
|
|
|
|
|
|
if (event.code === "Enter" || event.code === "NumpadEnter") {
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
onSubmit(event);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
document.addEventListener("keydown", listener);
|
|
|
|
|
|
return () => {
|
|
|
|
|
|
document.removeEventListener("keydown", listener);
|
|
|
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2023-07-24 13:47:05 +00:00
|
|
|
|
return (
|
2023-07-18 21:10:45 +00:00
|
|
|
|
<Modal
|
2024-01-18 15:48:44 +00:00
|
|
|
|
title="Manage automations"
|
2023-07-18 21:10:45 +00:00
|
|
|
|
onExit={onCancel}
|
|
|
|
|
|
className={baseClass}
|
|
|
|
|
|
width="large"
|
2024-02-06 18:12:54 +00:00
|
|
|
|
isHidden={isShowingPreviewDataModal}
|
2023-07-18 21:10:45 +00:00
|
|
|
|
>
|
2024-01-18 15:48:44 +00:00
|
|
|
|
<div className={`${baseClass} form`}>
|
2023-07-18 21:10:45 +00:00
|
|
|
|
<div className={`${baseClass}__heading`}>
|
|
|
|
|
|
Query automations let you send data to your log destination on a
|
|
|
|
|
|
schedule. Data is sent according to a query’s frequency.
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{availableQueries?.length ? (
|
2024-01-18 15:48:44 +00:00
|
|
|
|
<div className={`${baseClass}__select form-field`}>
|
|
|
|
|
|
<div className="form-field__label">
|
|
|
|
|
|
Choose which queries will send data:
|
|
|
|
|
|
</div>
|
2023-07-18 21:10:45 +00:00
|
|
|
|
<div className={`${baseClass}__checkboxes`}>
|
|
|
|
|
|
{queryItems &&
|
|
|
|
|
|
queryItems.map((queryItem) => {
|
|
|
|
|
|
const { isChecked, name, id, interval } = queryItem;
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div key={id} className={`${baseClass}__query-item`}>
|
|
|
|
|
|
<Checkbox
|
|
|
|
|
|
value={isChecked}
|
|
|
|
|
|
name={name}
|
|
|
|
|
|
onChange={() => {
|
|
|
|
|
|
updateQueryItems(id);
|
2024-02-06 18:12:54 +00:00
|
|
|
|
// !isChecked &&
|
|
|
|
|
|
// setErrors((errs) => omit(errs, "queryItems"));
|
2023-07-18 21:10:45 +00:00
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
{name}
|
|
|
|
|
|
</Checkbox>
|
|
|
|
|
|
<QueryFrequencyIndicator
|
|
|
|
|
|
frequency={interval}
|
|
|
|
|
|
checked={isChecked}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
})}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
) : (
|
|
|
|
|
|
<div className={`${baseClass}__no-queries`}>
|
|
|
|
|
|
<b>You have no queries.</b>
|
|
|
|
|
|
<p>Add a query to turn on automations.</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
2024-01-18 15:48:44 +00:00
|
|
|
|
<div className={`${baseClass}__log-destination form-field`}>
|
|
|
|
|
|
<div className="form-field__label">Log destination:</div>
|
2023-07-18 21:10:45 +00:00
|
|
|
|
<div className={`${baseClass}__selection`}>
|
|
|
|
|
|
<LogDestinationIndicator logDestination={logDestination} />
|
|
|
|
|
|
</div>
|
2024-01-18 15:48:44 +00:00
|
|
|
|
<div className={`${baseClass}__configure form-field__help-text`}>
|
2023-07-18 21:10:45 +00:00
|
|
|
|
Users with the admin role can
|
|
|
|
|
|
<CustomLink
|
|
|
|
|
|
url="https://fleetdm.com/docs/using-fleet/log-destinations"
|
|
|
|
|
|
text="configure a different log destination"
|
|
|
|
|
|
newTab
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<InfoBanner className={`${baseClass}__supported-platforms`}>
|
2023-07-20 23:31:36 +00:00
|
|
|
|
<p>Automations currently run on macOS, Windows, and Linux hosts.</p>
|
|
|
|
|
|
<p>
|
|
|
|
|
|
Interested in query automations for your Chromebooks?
|
|
|
|
|
|
<CustomLink
|
|
|
|
|
|
url="https://fleetdm.com/contact"
|
|
|
|
|
|
text="Let us know"
|
|
|
|
|
|
newTab
|
|
|
|
|
|
/>
|
|
|
|
|
|
</p>
|
2023-07-18 21:10:45 +00:00
|
|
|
|
</InfoBanner>
|
2024-01-18 15:48:44 +00:00
|
|
|
|
<Button
|
|
|
|
|
|
type="button"
|
2024-07-09 13:09:18 +00:00
|
|
|
|
variant="text-link"
|
2024-01-18 15:48:44 +00:00
|
|
|
|
onClick={togglePreviewDataModal}
|
|
|
|
|
|
className={`${baseClass}__preview-data`}
|
|
|
|
|
|
>
|
|
|
|
|
|
Preview data
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
<div className="modal-cta-wrap">
|
|
|
|
|
|
<Button
|
|
|
|
|
|
type="submit"
|
|
|
|
|
|
variant="brand"
|
2024-05-30 14:57:55 +00:00
|
|
|
|
onClick={onSubmitQueryAutomations}
|
2024-01-18 15:48:44 +00:00
|
|
|
|
className="save-loading"
|
|
|
|
|
|
isLoading={isUpdatingAutomations}
|
|
|
|
|
|
>
|
|
|
|
|
|
Save
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
<Button onClick={onCancel} variant="inverse">
|
|
|
|
|
|
Cancel
|
|
|
|
|
|
</Button>
|
2023-07-18 21:10:45 +00:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2023-07-24 13:47:05 +00:00
|
|
|
|
</Modal>
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-01-03 20:35:02 +00:00
|
|
|
|
export default ManageQueryAutomationsModal;
|