|
|
|
import { Menu } from '@mui/material';
|
|
|
|
import { forwardRef, useImperativeHandle, useMemo, useState } from 'react';
|
|
|
|
|
|
|
|
import API_BASE_URL from '../lib/consts/API_BASE_URL';
|
|
|
|
|
|
|
|
import { ProgressBar } from './Bars';
|
|
|
|
import FlexBox from './FlexBox';
|
|
|
|
import Link from './Link';
|
|
|
|
import List from './List';
|
|
|
|
import periodicFetch from '../lib/fetchers/periodicFetch';
|
|
|
|
import { BodyText } from './Text';
|
|
|
|
import useProtect from '../hooks/useProtect';
|
|
|
|
import useProtectedState from '../hooks/useProtectedState';
|
|
|
|
|
|
|
|
type AnvilJobs = {
|
|
|
|
[jobUUID: string]: {
|
|
|
|
jobCommand: string;
|
|
|
|
jobName: string;
|
|
|
|
jobProgress: number;
|
|
|
|
jobUUID: string;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
type JobSummaryOptionalPropsWithDefault = {
|
|
|
|
openInitially?: boolean;
|
|
|
|
refreshInterval?: number;
|
|
|
|
};
|
|
|
|
|
|
|
|
type JobSummaryOptionalPropsWithoutDefault = {
|
|
|
|
onFetchSuccessAppend?: (data: AnvilJobs) => void;
|
|
|
|
};
|
|
|
|
|
|
|
|
type JobSummaryOptionalProps = JobSummaryOptionalPropsWithDefault &
|
|
|
|
JobSummaryOptionalPropsWithoutDefault;
|
|
|
|
|
|
|
|
type JobSummaryProps = JobSummaryOptionalProps;
|
|
|
|
|
|
|
|
type JobSummaryForwardedRefContent = {
|
|
|
|
setAnchor?: (element: HTMLElement | undefined) => void;
|
|
|
|
setOpen?: (value: boolean) => void;
|
|
|
|
};
|
|
|
|
|
|
|
|
const JOB_LIST_LENGTH = '20em';
|
|
|
|
const JOB_SUMMARY_DEFAULT_PROPS: Required<JobSummaryOptionalPropsWithDefault> &
|
|
|
|
JobSummaryOptionalPropsWithoutDefault = {
|
|
|
|
onFetchSuccessAppend: undefined,
|
|
|
|
openInitially: false,
|
|
|
|
refreshInterval: 10000,
|
|
|
|
};
|
|
|
|
|
|
|
|
const JobSummary = forwardRef<JobSummaryForwardedRefContent, JobSummaryProps>(
|
|
|
|
(
|
|
|
|
{
|
|
|
|
onFetchSuccessAppend,
|
|
|
|
openInitially = JOB_SUMMARY_DEFAULT_PROPS.openInitially,
|
|
|
|
refreshInterval = JOB_SUMMARY_DEFAULT_PROPS.refreshInterval,
|
|
|
|
},
|
|
|
|
ref,
|
|
|
|
) => {
|
|
|
|
const { protect } = useProtect();
|
|
|
|
|
|
|
|
const [anvilJobs, setAnvilJobs] = useProtectedState<AnvilJobs>({}, protect);
|
|
|
|
const [isOpenJobSummary, setIsOpenJobSummary] =
|
|
|
|
useState<boolean>(openInitially);
|
|
|
|
const [menuAnchorElement, setMenuAnchorElement] = useState<
|
|
|
|
HTMLElement | undefined
|
|
|
|
>();
|
|
|
|
|
|
|
|
const loadTimestamp = useMemo(() => Math.floor(Date.now() / 1000), []);
|
|
|
|
|
|
|
|
periodicFetch<AnvilJobs>(`${API_BASE_URL}/job?start=${loadTimestamp}`, {
|
|
|
|
onError: () => {
|
|
|
|
setAnvilJobs({});
|
|
|
|
},
|
|
|
|
onSuccess: (rawAnvilJobs) => {
|
|
|
|
setAnvilJobs(rawAnvilJobs);
|
|
|
|
|
|
|
|
onFetchSuccessAppend?.call(null, rawAnvilJobs);
|
|
|
|
},
|
|
|
|
refreshInterval,
|
|
|
|
});
|
|
|
|
|
|
|
|
useImperativeHandle(
|
|
|
|
ref,
|
|
|
|
() => ({
|
|
|
|
setAnchor: (value) => setMenuAnchorElement(value),
|
|
|
|
setOpen: (value) => setIsOpenJobSummary(value),
|
|
|
|
}),
|
|
|
|
[],
|
|
|
|
);
|
|
|
|
|
|
|
|
const jobList = useMemo(
|
|
|
|
() => (
|
|
|
|
<FlexBox>
|
|
|
|
<List
|
|
|
|
scroll
|
|
|
|
listEmpty="No currently running and recently completed jobs."
|
|
|
|
listItems={anvilJobs}
|
|
|
|
listProps={{
|
|
|
|
sx: { maxHeight: JOB_LIST_LENGTH, width: JOB_LIST_LENGTH },
|
|
|
|
}}
|
|
|
|
renderListItem={(jobUUID, { jobName, jobProgress }) => (
|
|
|
|
<FlexBox sm="row" sx={{ width: '97%' }} xs="column">
|
|
|
|
<FlexBox spacing={0} sx={{ width: 'inherit' }}>
|
|
|
|
<BodyText
|
|
|
|
sx={{
|
|
|
|
overflowX: 'hidden',
|
|
|
|
textOverflow: 'ellipsis',
|
|
|
|
whiteSpace: 'nowrap',
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{jobName}
|
|
|
|
</BodyText>
|
|
|
|
<ProgressBar progressPercentage={jobProgress} />
|
|
|
|
</FlexBox>
|
|
|
|
</FlexBox>
|
|
|
|
)}
|
|
|
|
/>
|
|
|
|
<Link href="cgi-bin/striker?jobs=true">More details</Link>
|
|
|
|
</FlexBox>
|
|
|
|
),
|
|
|
|
[anvilJobs],
|
|
|
|
);
|
|
|
|
const jobSummary = useMemo(
|
|
|
|
() => (
|
|
|
|
<Menu
|
|
|
|
anchorEl={menuAnchorElement}
|
|
|
|
MenuListProps={{ sx: { padding: '.8em 1.6em' } }}
|
|
|
|
onClose={() => {
|
|
|
|
setIsOpenJobSummary(false);
|
|
|
|
setMenuAnchorElement(undefined);
|
|
|
|
}}
|
|
|
|
open={isOpenJobSummary}
|
|
|
|
variant="menu"
|
|
|
|
>
|
|
|
|
{jobList}
|
|
|
|
</Menu>
|
|
|
|
),
|
|
|
|
[isOpenJobSummary, jobList, menuAnchorElement],
|
|
|
|
);
|
|
|
|
|
|
|
|
return jobSummary;
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
JobSummary.defaultProps = JOB_SUMMARY_DEFAULT_PROPS;
|
|
|
|
JobSummary.displayName = 'JobSummary';
|
|
|
|
|
|
|
|
export type { JobSummaryForwardedRefContent, JobSummaryProps };
|
|
|
|
|
|
|
|
export default JobSummary;
|