import React, { useCallback, useEffect, useRef, useState } from "react"; import { useQueryClient } from "react-query"; import { Tab, TabList, TabPanel, Tabs } from "react-tabs"; import PATHS from "router/paths"; import scriptsAPI, { IScriptBatchSummaryV2 } from "services/entities/scripts"; import { isValidScriptBatchStatus, ScriptBatchStatus } from "interfaces/script"; import { COLORS } from "styles/var/colors"; import Spinner from "components/Spinner"; import ProgressBar from "components/ProgressBar"; import SectionHeader from "components/SectionHeader"; import TabNav from "components/TabNav"; import TabText from "components/TabText"; import PaginatedList, { IPaginatedListHandle } from "components/PaginatedList"; import Icon from "components/Icon/Icon"; import { IScriptsCommonProps } from "../../ScriptsNavItems"; import getWhen from "../../helpers"; const baseClass = "script-batch-progress"; const STATUS_BY_INDEX: ScriptBatchStatus[] = [ "started", "scheduled", "finished", ]; export const EMPTY_STATE_DETAILS: Record = { started: "When a script is run on multiple hosts, progress will appear here.", scheduled: "When a script is scheduled to run in the future, it will appear here.", finished: "When a batch script is completed or canceled, historical results will appear here.", }; const getEmptyState = (status: ScriptBatchStatus) => { return (
No batch scripts {status} for this team

{EMPTY_STATE_DETAILS[status]}

); }; export type IScriptBatchProgressProps = IScriptsCommonProps; const ScriptBatchProgress = ({ location, router, teamId, }: IScriptBatchProgressProps) => { const [batchCount, setBatchCount] = useState(null); const [updating, setUpdating] = useState(false); const paginatedListRef = useRef>( null ); const statusParam = location?.query.status; const selectedStatus = statusParam as ScriptBatchStatus; const queryClient = useQueryClient(); const DEFAULT_PAGE_SIZE = 10; const fetchPage = useCallback( (pageNumber: number) => { setUpdating(true); return queryClient.fetchQuery( [ { team_id: teamId, status: selectedStatus, page: pageNumber, per_page: DEFAULT_PAGE_SIZE, }, ], ({ queryKey }) => { return scriptsAPI .getRunScriptBatchSummaries(queryKey[0]) .then((r) => { setBatchCount(r.count); return r.batch_executions ?? []; }) .finally(() => { setUpdating(false); }); }, { staleTime: 100, } ); }, [queryClient, selectedStatus, teamId] ); const handleTabChange = useCallback( (index: number) => { const newStatus = STATUS_BY_INDEX[index]; const newParams = new URLSearchParams(location?.search); newParams.set("status", newStatus); const newQuery = newParams.toString(); router.push( PATHS.CONTROLS_SCRIPTS_BATCH_PROGRESS.concat( newQuery ? `?${newQuery}` : "" ) ); setBatchCount(null); setUpdating(false); }, [location?.search, router] ); const onClickRow = (r: IScriptBatchSummaryV2) => { router.push(PATHS.CONTROLS_SCRIPTS_BATCH_DETAILS(r.batch_execution_id)); // return satisfies caller expectations, not used in this case return r; }; const renderRow = (summary: IScriptBatchSummaryV2) => { const { script_name, targeted_host_count, ran_host_count, errored_host_count, } = summary; const when = getWhen(summary); return ( <>
{script_name}
{when}
{summary.status !== "scheduled" && (
{ran_host_count + errored_host_count} / {targeted_host_count}{" "} hosts
{" "}
{errored_host_count}
)} ); }; // Fetch the first page of the list when first visiting a tab. useEffect(() => { if (batchCount === null && !updating) { fetchPage(0); } }, [batchCount, updating, fetchPage]); // Reset to first tab if status is invalid. useEffect(() => { if (!isValidScriptBatchStatus(statusParam)) { handleTabChange(0); } }, [statusParam, handleTabChange]); const renderTabContent = (status: ScriptBatchStatus) => { // If we're switching to a new tab, show the loading spinner // while we get the first page and # of results. if (updating && batchCount === null) { return (
); } if (batchCount === 0) { return getEmptyState(status); } return (
{!updating && batchCount && (
{batchCount} batch script{batchCount > 1 ? "s" : ""}
)} ref={paginatedListRef} count={batchCount || 0} fetchPage={fetchPage} onClickRow={onClickRow} renderItemRow={renderRow} useCheckBoxes={false} />
); }; return ( <>
Started Scheduled Finished {renderTabContent(STATUS_BY_INDEX[0])} {renderTabContent(STATUS_BY_INDEX[1])} {renderTabContent(STATUS_BY_INDEX[2])}
); }; export default ScriptBatchProgress;