import React, { useCallback, useEffect, useRef, useState } from "react"; import { useQuery } from "react-query"; import { Tab, TabList, TabPanel, Tabs } from "react-tabs"; import PATHS from "router/paths"; import scriptsAPI, { IScriptBatchSummaryV2, IScriptBatchSummariesResponse, } 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 ListItem from "components/ListItem"; import Icon from "components/Icon/Icon"; import EmptyState from "components/EmptyState"; 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 ( ); }; export type IScriptBatchProgressProps = IScriptsCommonProps; const ScriptBatchProgress = ({ location, router, teamId, }: IScriptBatchProgressProps) => { const [pageNumber, setPageNumber] = useState(0); const paginatedListRef = useRef>( null ); const statusParam = location?.query.status; const selectedStatus = statusParam as ScriptBatchStatus; const DEFAULT_PAGE_SIZE = 10; const queryKey = { fleet_id: teamId, status: selectedStatus, page: pageNumber, per_page: DEFAULT_PAGE_SIZE, }; const { data, isFetching: updating } = useQuery< IScriptBatchSummariesResponse, Error, IScriptBatchSummariesResponse >([queryKey], () => scriptsAPI.getRunScriptBatchSummaries(queryKey), { keepPreviousData: true, }); 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}` : "" ) ); setPageNumber(0); }, [location?.search, router] ); const onClickRow = (r: IScriptBatchSummaryV2) => { // explicitly including the status param here avoids triggering the script details page's effect // which would add it automatically, muddying browser history and preventing smooth forward/back navigation router.push( PATHS.CONTROLS_SCRIPTS_BATCH_DETAILS(r.batch_execution_id).concat( "?status=ran" ) ); return r; }; const renderRow = (summary: IScriptBatchSummaryV2) => { const { script_name, targeted_host_count, ran_host_count, errored_host_count, } = summary; const when = getWhen(summary); return ( <> {summary.status !== "scheduled" && (
{ran_host_count + errored_host_count} / {targeted_host_count}{" "} hosts
{" "}
{errored_host_count}
)} ); }; // 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) { return (
); } const count = data?.count || 0; const rows = data?.batch_executions || []; if (count === 0) { return getEmptyState(status); } return (
{!updating && count && (
{count} batch script{count > 1 ? "s" : ""}
)} ref={paginatedListRef} count={count} data={rows} pageSize={DEFAULT_PAGE_SIZE} currentPage={pageNumber} onChangePage={setPageNumber} isLoading={updating} 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;