2022-08-08 14:33:57 -07:00
|
|
|
import { DownloadOutlined } from '@ant-design/icons';
|
|
|
|
import { Button, message, Modal, Typography } from 'antd';
|
|
|
|
import React, { useEffect, useState } from 'react';
|
2022-01-27 10:33:12 -08:00
|
|
|
import styled from 'styled-components';
|
2023-10-18 13:42:03 -04:00
|
|
|
import YAML from 'yamljs';
|
2022-08-29 19:11:59 -04:00
|
|
|
import { useGetIngestionExecutionRequestQuery } from '../../../../graphql/ingestion.generated';
|
|
|
|
import { ANTD_GRAY } from '../../../entity/shared/constants';
|
|
|
|
import { downloadFile } from '../../../search/utils/csvUtils';
|
|
|
|
import { Message } from '../../../shared/Message';
|
|
|
|
import IngestedAssets from '../IngestedAssets';
|
2022-08-08 14:33:57 -07:00
|
|
|
import {
|
|
|
|
getExecutionRequestStatusDisplayColor,
|
|
|
|
getExecutionRequestStatusDisplayText,
|
|
|
|
getExecutionRequestStatusIcon,
|
2022-08-16 19:01:26 -04:00
|
|
|
getExecutionRequestSummaryText,
|
|
|
|
RUNNING,
|
2022-08-08 14:33:57 -07:00
|
|
|
SUCCESS,
|
2022-08-29 19:11:59 -04:00
|
|
|
} from '../utils';
|
2022-08-08 14:33:57 -07:00
|
|
|
|
|
|
|
const StyledTitle = styled(Typography.Title)`
|
|
|
|
padding: 0px;
|
|
|
|
margin: 0px;
|
|
|
|
`;
|
2022-01-27 10:33:12 -08:00
|
|
|
|
|
|
|
const Section = styled.div`
|
|
|
|
display: flex;
|
|
|
|
flex-direction: column;
|
|
|
|
padding-bottom: 12px;
|
|
|
|
`;
|
|
|
|
|
2022-08-08 14:33:57 -07:00
|
|
|
const SectionHeader = styled(Typography.Title)`
|
2022-01-27 10:33:12 -08:00
|
|
|
&&&& {
|
|
|
|
padding: 0px;
|
|
|
|
margin: 0px;
|
|
|
|
margin-bottom: 12px;
|
|
|
|
}
|
|
|
|
`;
|
|
|
|
|
2022-08-08 14:33:57 -07:00
|
|
|
const SectionSubHeader = styled.div`
|
|
|
|
display: flex;
|
|
|
|
justify-content: space-between;
|
|
|
|
align-items: center;
|
|
|
|
`;
|
|
|
|
|
|
|
|
const SubHeaderParagraph = styled(Typography.Paragraph)`
|
|
|
|
margin-bottom: 0px;
|
|
|
|
`;
|
|
|
|
|
|
|
|
const HeaderSection = styled.div``;
|
|
|
|
|
|
|
|
const StatusSection = styled.div`
|
|
|
|
border-bottom: 1px solid ${ANTD_GRAY[4]};
|
|
|
|
padding: 16px;
|
|
|
|
padding-left: 30px;
|
|
|
|
padding-right: 30px;
|
|
|
|
`;
|
|
|
|
|
|
|
|
const ResultText = styled.div`
|
|
|
|
margin-bottom: 4px;
|
|
|
|
`;
|
|
|
|
|
|
|
|
const IngestedAssetsSection = styled.div`
|
|
|
|
border-bottom: 1px solid ${ANTD_GRAY[4]};
|
|
|
|
padding: 16px;
|
|
|
|
padding-left: 30px;
|
|
|
|
padding-right: 30px;
|
|
|
|
`;
|
|
|
|
|
2023-10-18 13:42:03 -04:00
|
|
|
const RecipeSection = styled.div`
|
|
|
|
border-top: 1px solid ${ANTD_GRAY[4]};
|
|
|
|
padding-top: 16px;
|
|
|
|
padding-left: 30px;
|
|
|
|
padding-right: 30px;
|
|
|
|
`;
|
|
|
|
|
2022-08-08 14:33:57 -07:00
|
|
|
const LogsSection = styled.div`
|
|
|
|
padding-top: 16px;
|
|
|
|
padding-left: 30px;
|
|
|
|
padding-right: 30px;
|
|
|
|
`;
|
|
|
|
|
|
|
|
const ShowMoreButton = styled(Button)`
|
|
|
|
padding: 0px;
|
|
|
|
`;
|
|
|
|
|
2023-11-10 22:52:04 +05:30
|
|
|
const LogsContainer = styled.div<LogsContainerProps>`
|
|
|
|
margin-bottom: -25px;
|
|
|
|
${(props) =>
|
|
|
|
props.areLogsExpandable &&
|
|
|
|
!props.showExpandedLogs &&
|
|
|
|
`
|
|
|
|
-webkit-mask-image: linear-gradient(to bottom, rgba(0,0,0,1) 50%, rgba(255,0,0,0.5) 60%, rgba(255,0,0,0) 90% );
|
|
|
|
mask-image: linear-gradient(to bottom, rgba(0,0,0,1) 50%, rgba(255,0,0,0.5) 60%, rgba(255,0,0,0) 90%);
|
|
|
|
`}
|
|
|
|
`;
|
|
|
|
|
2022-08-08 14:33:57 -07:00
|
|
|
const modalStyle = {
|
|
|
|
top: 100,
|
|
|
|
};
|
|
|
|
|
|
|
|
const modalBodyStyle = {
|
|
|
|
padding: 0,
|
|
|
|
};
|
|
|
|
|
2023-11-10 22:52:04 +05:30
|
|
|
type LogsContainerProps = {
|
|
|
|
showExpandedLogs: boolean;
|
|
|
|
areLogsExpandable: boolean;
|
|
|
|
};
|
|
|
|
|
2022-01-27 10:33:12 -08:00
|
|
|
type Props = {
|
|
|
|
urn: string;
|
|
|
|
visible: boolean;
|
|
|
|
onClose: () => void;
|
|
|
|
};
|
|
|
|
|
|
|
|
export const ExecutionDetailsModal = ({ urn, visible, onClose }: Props) => {
|
2022-08-18 11:37:14 -04:00
|
|
|
const [showExpandedLogs, setShowExpandedLogs] = useState(false);
|
2023-10-18 13:42:03 -04:00
|
|
|
const [showExpandedRecipe, setShowExpandedRecipe] = useState(false);
|
|
|
|
|
2022-08-16 19:01:26 -04:00
|
|
|
const { data, loading, error, refetch } = useGetIngestionExecutionRequestQuery({ variables: { urn } });
|
2022-01-27 10:33:12 -08:00
|
|
|
const output = data?.executionRequest?.result?.report || 'No output found.';
|
|
|
|
|
2022-08-08 14:33:57 -07:00
|
|
|
const downloadLogs = () => {
|
|
|
|
downloadFile(output, `exec-${urn}.log`);
|
|
|
|
};
|
|
|
|
|
2023-11-10 22:52:04 +05:30
|
|
|
const logs = (showExpandedLogs && output) || output.slice(0, 250);
|
2022-08-08 14:33:57 -07:00
|
|
|
const result = data?.executionRequest?.result?.status;
|
|
|
|
|
2022-08-16 19:01:26 -04:00
|
|
|
useEffect(() => {
|
|
|
|
const interval = setInterval(() => {
|
|
|
|
if (result === RUNNING) refetch();
|
|
|
|
}, 2000);
|
|
|
|
|
|
|
|
return () => clearInterval(interval);
|
|
|
|
});
|
|
|
|
|
2022-08-08 14:33:57 -07:00
|
|
|
const ResultIcon = result && getExecutionRequestStatusIcon(result);
|
|
|
|
const resultColor = result && getExecutionRequestStatusDisplayColor(result);
|
|
|
|
const resultText = result && (
|
|
|
|
<Typography.Text style={{ color: resultColor, fontSize: 14 }}>
|
|
|
|
{ResultIcon && <ResultIcon style={{ marginRight: 4 }} />}
|
|
|
|
{getExecutionRequestStatusDisplayText(result)}
|
|
|
|
</Typography.Text>
|
|
|
|
);
|
|
|
|
const resultSummaryText =
|
2022-08-16 19:01:26 -04:00
|
|
|
(result && <Typography.Text type="secondary">{getExecutionRequestSummaryText(result)}</Typography.Text>) ||
|
2022-08-08 14:33:57 -07:00
|
|
|
undefined;
|
2023-10-18 13:42:03 -04:00
|
|
|
|
|
|
|
const recipeJson = data?.executionRequest?.input.arguments?.find((arg) => arg.key === 'recipe')?.value;
|
|
|
|
let recipeYaml: string;
|
|
|
|
try {
|
|
|
|
recipeYaml = recipeJson && YAML.stringify(JSON.parse(recipeJson), 8, 2).trim();
|
|
|
|
} catch (e) {
|
|
|
|
recipeYaml = '';
|
|
|
|
}
|
|
|
|
const recipe = showExpandedRecipe ? recipeYaml : recipeYaml?.split('\n').slice(0, 1).join('\n');
|
|
|
|
|
2023-11-10 22:52:04 +05:30
|
|
|
const areLogsExpandable = output.length > 250;
|
2023-10-18 13:42:03 -04:00
|
|
|
const isRecipeExpandable = recipeYaml?.includes('\n');
|
2022-08-08 14:33:57 -07:00
|
|
|
|
2022-01-27 10:33:12 -08:00
|
|
|
return (
|
|
|
|
<Modal
|
2022-08-08 14:33:57 -07:00
|
|
|
width={800}
|
|
|
|
footer={<Button onClick={onClose}>Close</Button>}
|
|
|
|
style={modalStyle}
|
|
|
|
bodyStyle={modalBodyStyle}
|
|
|
|
title={
|
|
|
|
<HeaderSection>
|
|
|
|
<StyledTitle level={4}>Ingestion Run Details</StyledTitle>
|
|
|
|
</HeaderSection>
|
|
|
|
}
|
2022-01-27 10:33:12 -08:00
|
|
|
visible={visible}
|
|
|
|
onCancel={onClose}
|
|
|
|
>
|
|
|
|
{!data && loading && <Message type="loading" content="Loading execution details..." />}
|
|
|
|
{error && message.error('Failed to load execution details :(')}
|
|
|
|
<Section>
|
2022-08-08 14:33:57 -07:00
|
|
|
<StatusSection>
|
|
|
|
<Typography.Title level={5}>Status</Typography.Title>
|
|
|
|
<ResultText>{resultText}</ResultText>
|
|
|
|
<SubHeaderParagraph>{resultSummaryText}</SubHeaderParagraph>
|
|
|
|
</StatusSection>
|
|
|
|
{result === SUCCESS && (
|
|
|
|
<IngestedAssetsSection>
|
|
|
|
{data?.executionRequest?.id && <IngestedAssets id={data?.executionRequest?.id} />}
|
|
|
|
</IngestedAssetsSection>
|
|
|
|
)}
|
|
|
|
<LogsSection>
|
|
|
|
<SectionHeader level={5}>Logs</SectionHeader>
|
|
|
|
<SectionSubHeader>
|
|
|
|
<SubHeaderParagraph type="secondary">
|
|
|
|
View logs that were collected during the ingestion run.
|
|
|
|
</SubHeaderParagraph>
|
|
|
|
<Button type="text" onClick={downloadLogs}>
|
|
|
|
<DownloadOutlined />
|
|
|
|
Download
|
|
|
|
</Button>
|
|
|
|
</SectionSubHeader>
|
2023-11-10 22:52:04 +05:30
|
|
|
<LogsContainer areLogsExpandable={areLogsExpandable} showExpandedLogs={showExpandedLogs}>
|
|
|
|
<Typography.Paragraph ellipsis>
|
|
|
|
<pre>{`${logs}${!showExpandedLogs && areLogsExpandable ? '...' : ''}`}</pre>
|
|
|
|
</Typography.Paragraph>
|
|
|
|
</LogsContainer>
|
|
|
|
{areLogsExpandable && (
|
|
|
|
<ShowMoreButton type="link" onClick={() => setShowExpandedLogs(!showExpandedLogs)}>
|
|
|
|
{showExpandedLogs ? 'Hide' : 'Show More'}
|
|
|
|
</ShowMoreButton>
|
|
|
|
)}
|
2022-08-08 14:33:57 -07:00
|
|
|
</LogsSection>
|
2023-10-18 13:42:03 -04:00
|
|
|
{recipe && (
|
|
|
|
<RecipeSection>
|
|
|
|
<SectionHeader level={5}>Recipe</SectionHeader>
|
|
|
|
<SectionSubHeader>
|
|
|
|
<SubHeaderParagraph type="secondary">
|
|
|
|
The recipe used for this ingestion run.
|
|
|
|
</SubHeaderParagraph>
|
|
|
|
</SectionSubHeader>
|
|
|
|
<Typography.Paragraph ellipsis>
|
|
|
|
<pre>{`${recipe}${!showExpandedRecipe && isRecipeExpandable ? '\n...' : ''}`}</pre>
|
|
|
|
</Typography.Paragraph>
|
|
|
|
{isRecipeExpandable && (
|
|
|
|
<ShowMoreButton type="link" onClick={() => setShowExpandedRecipe((v) => !v)}>
|
|
|
|
{showExpandedRecipe ? 'Hide' : 'Show More'}
|
|
|
|
</ShowMoreButton>
|
|
|
|
)}
|
|
|
|
</RecipeSection>
|
|
|
|
)}
|
2022-01-27 10:33:12 -08:00
|
|
|
</Section>
|
|
|
|
</Modal>
|
|
|
|
);
|
|
|
|
};
|