fleet/frontend/pages/ManageControlsPage/Scripts/Scripts.tsx
Martin Angers ca435eb244
Queued scripts feature (#16300)
This is the feature branch for the [queued
scripts](https://github.com/fleetdm/fleet/issues/15529) story.

---------

Co-authored-by: Jahziel Villasana-Espinoza <jahziel@fleetdm.com>
Co-authored-by: Gabriel Hernandez <ghernandez345@gmail.com>
Co-authored-by: Sarah Gillespie <73313222+gillespi314@users.noreply.github.com>
Co-authored-by: Roberto Dip <dip.jesusr@gmail.com>
2024-01-29 11:37:54 -03:00

169 lines
4.6 KiB
TypeScript

import React, { useCallback, useContext, useRef, useState } from "react";
import { useQuery } from "react-query";
import { AxiosError } from "axios";
import { InjectedRouter } from "react-router";
import { AppContext } from "context/app";
import PATHS from "router/paths";
import scriptAPI, {
IListScriptsQueryKey,
IScriptsResponse,
} from "services/entities/scripts";
import { IScript } from "interfaces/script";
import CustomLink from "components/CustomLink";
import Spinner from "components/Spinner";
import DataError from "components/DataError";
import InfoBanner from "components/InfoBanner";
import ScriptListHeading from "./components/ScriptListHeading";
import ScriptListItem from "./components/ScriptListItem";
import ScriptListPagination from "./components/ScriptListPagination";
import DeleteScriptModal from "./components/DeleteScriptModal";
import UploadList from "../components/UploadList";
import ScriptUploader from "./components/ScriptUploader";
const baseClass = "scripts";
const SCRIPTS_PER_PAGE = 10;
interface IScriptsProps {
router: InjectedRouter; // v3
teamIdForApi: number;
currentPage: number;
}
const Scripts = ({ router, currentPage, teamIdForApi }: IScriptsProps) => {
const [showDeleteScriptModal, setShowDeleteScriptModal] = useState(false);
const selectedScript = useRef<IScript | null>(null);
const {
data: { scripts, meta } = {},
isLoading,
isError,
refetch: refetchScripts,
} = useQuery<
IScriptsResponse,
AxiosError,
IScriptsResponse,
IListScriptsQueryKey[]
>(
[
{
scope: "scripts",
team_id: teamIdForApi,
page: currentPage,
per_page: SCRIPTS_PER_PAGE,
},
],
({ queryKey: [{ team_id, page, per_page }] }) =>
scriptAPI.getScripts({ team_id, page, per_page }),
{
retry: false,
refetchOnWindowFocus: false,
staleTime: 3000,
}
);
// pagination controls
const path = PATHS.CONTROLS_SCRIPTS.concat(`?team_id=${teamIdForApi}`);
const onPrevPage = useCallback(() => {
router.push(path.concat(`&page=${currentPage - 1}`));
}, [router, path, currentPage]);
const onNextPage = useCallback(() => {
router.push(path.concat(`&page=${currentPage + 1}`));
}, [router, path, currentPage]);
const { config } = useContext(AppContext);
if (!config) return null;
const onClickDelete = (script: IScript) => {
selectedScript.current = script;
setShowDeleteScriptModal(true);
};
const onCancelDelete = () => {
selectedScript.current = null;
setShowDeleteScriptModal(false);
};
const onDeleteScript = () => {
selectedScript.current = null;
setShowDeleteScriptModal(false);
refetchScripts();
};
const onUploadScript = () => {
refetchScripts();
};
const renderScriptsList = () => {
if (isLoading) {
return <Spinner />;
}
if (isError) {
return <DataError />;
}
if (currentPage === 0 && !scripts?.length) {
return null;
}
return (
<>
<UploadList
keyAttribute="id"
listItems={scripts || []}
HeadingComponent={ScriptListHeading}
ListItemComponent={({ listItem }) => (
<ScriptListItem script={listItem} onDelete={onClickDelete} />
)}
/>
<ScriptListPagination
meta={meta}
isLoading={isLoading}
onPrevPage={onPrevPage}
onNextPage={onNextPage}
/>
</>
);
};
const renderScriptsDisabledBanner = () => (
<InfoBanner color="yellow">
<div>
<b>Running scripts is disabled in organization settings.</b> You can
still manage your library of macOS and Windows scripts below.
</div>
</InfoBanner>
);
return (
<div className={baseClass}>
<p className={`${baseClass}__description`}>
Upload scripts to change configuration and remediate issues on macOS and
Windows hosts. You can run scripts on individual hosts.{" "}
<CustomLink
text="Learn more"
url="https://fleetdm.com/docs/using-fleet/scripts"
newTab
/>
</p>
{config.server_settings.scripts_disabled && renderScriptsDisabledBanner()}
{renderScriptsList()}
<ScriptUploader currentTeamId={teamIdForApi} onUpload={onUploadScript} />
{showDeleteScriptModal && selectedScript.current && (
<DeleteScriptModal
scriptName={selectedScript.current?.name}
scriptId={selectedScript.current?.id}
onCancel={onCancelDelete}
onDone={onDeleteScript}
/>
)}
</div>
);
};
export default Scripts;