Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve jobs logs error handling #9585

Merged
merged 2 commits into from
Jan 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import { faRedoAlt } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useResource } from "rest-hooks";

import { Button } from "components";
import { Button, ContentCard } from "components";
import LoadingSchema from "components/LoadingSchema";
import ContentCard from "components/ContentCard";
import { JobsLogItem } from "components/JobItem";
import JobItem from "components/JobItem";
import ConnectionForm from "views/Connection/ConnectionForm";
import TryAfterErrorBlock from "./components/TryAfterErrorBlock";

Expand Down Expand Up @@ -94,6 +93,7 @@ const CreateConnectionContent: React.FC<IProps> = ({
}

if (schemaErrorStatus) {
const jobInfo = LogsRequestError.extractJobInfo(schemaErrorStatus);
return (
<ContentCard
title={
Expand All @@ -104,9 +104,7 @@ const CreateConnectionContent: React.FC<IProps> = ({
onClick={onDiscoverSchema}
additionControl={<SkipButton>{additionBottomControls}</SkipButton>}
/>
<JobsLogItem
jobInfo={LogsRequestError.extractJobInfo(schemaErrorStatus)}
/>
{jobInfo && <JobItem jobInfo={jobInfo} />}
</ContentCard>
);
}
Expand Down
57 changes: 44 additions & 13 deletions airbyte-webapp/src/components/JobItem/JobItem.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import React, { Suspense, useState } from "react";
import styled from "styled-components";

import { JobItem as JobApiItem, Attempt } from "core/resources/Job";
import Spinner from "../Spinner";
import { Spinner } from "components";

import { JobInfo, JobListItem, Logs } from "core/domain/job/Job";
import Status from "core/statuses";

import JobLogs from "./components/JobLogs";
import ContentWrapper from "./components/ContentWrapper";
import MainInfo from "./components/MainInfo";
import Status from "core/statuses";

type IProps = {
job: JobApiItem;
attempts: Attempt[];
};
import { LogsDetails } from "./components/LogsDetails";

const Item = styled.div<{ isFailed: boolean }>`
border-bottom: 1px solid ${({ theme }) => theme.greyColor20};
Expand All @@ -31,19 +29,42 @@ const LoadLogs = styled.div`
min-height: 58px;
`;

const JobItem: React.FC<IProps> = ({ job, attempts }) => {
const isJobEntity = (
props: { job: JobListItem } | { jobInfo: JobInfo }
): props is { job: JobListItem } => {
return props.hasOwnProperty("job");
};

const JobCurrentLogs: React.FC<{
id: number | string;
jobIsFailed?: boolean;
logs?: Logs;
}> = (props) => {
const path = ["/tmp/workspace", props.id, "logs.log"].join("/");

return <LogsDetails {...props} path={path} />;
};

type IProps = {
shortInfo?: boolean;
} & ({ job: JobListItem } | { jobInfo: JobInfo });

const JobItem: React.FC<IProps> = ({ shortInfo, ...props }) => {
const [isOpen, setIsOpen] = useState(false);
const onExpand = () => setIsOpen(!isOpen);
const isFailed = job.status === Status.FAILED;

const jobMeta = isJobEntity(props) ? props.job.job : props.jobInfo;
const isFailed = jobMeta.status === Status.FAILED;

return (
<Item isFailed={isFailed}>
<MainInfo
shortInfo={shortInfo}
isOpen={isOpen}
isFailed={isFailed}
onExpand={onExpand}
job={job}
attempts={attempts}
job={jobMeta}
attempts={isJobEntity(props) ? props.job.attempts : undefined}
/>
<ContentWrapper isOpen={isOpen}>
<div>
Expand All @@ -54,7 +75,17 @@ const JobItem: React.FC<IProps> = ({ job, attempts }) => {
</LoadLogs>
}
>
{isOpen && <JobLogs id={job.id} jobIsFailed={isFailed} />}
{isOpen ? (
isJobEntity(props) ? (
<JobLogs id={jobMeta.id} jobIsFailed={isFailed} />
) : (
<JobCurrentLogs
id={jobMeta.id}
jobIsFailed={isFailed}
logs={props.jobInfo.logs}
/>
)
) : null}
</Suspense>
</div>
</ContentWrapper>
Expand Down
61 changes: 0 additions & 61 deletions airbyte-webapp/src/components/JobItem/JobsLogItem.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { FormattedMessage } from "react-intl";
import styled from "styled-components";
import dayjs from "dayjs";

import { Attempt } from "core/resources/Job";
import { Attempt } from "core/domain/job/Job";
import Status from "core/statuses";

type IProps = {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faFileDownload } from "@fortawesome/free-solid-svg-icons";

import { Button } from "components";
type IProps = {
logs: string[];
fileName: string;
};

const Download = styled(Button)`
position: absolute;
top: 9px;
right: 11px;
`;

type IProps = {
logs: string[];
fileName: string;
};

const DownloadButton: React.FC<IProps> = ({ logs, fileName }) => {
const formatMessage = useIntl().formatMessage;

Expand Down
71 changes: 0 additions & 71 deletions airbyte-webapp/src/components/JobItem/components/JobCurrenLogs.tsx

This file was deleted.

48 changes: 19 additions & 29 deletions airbyte-webapp/src/components/JobItem/components/JobLogs.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
import React, { useState } from "react";
import { useResource, useSubscription } from "rest-hooks";
import { FormattedMessage } from "react-intl";

import JobResource from "core/resources/Job";
import AttemptDetails from "./AttemptDetails";
import DownloadButton from "./DownloadButton";
import Status from "core/statuses";
import { useGetJob } from "services/job/JobService";

import Logs from "./Logs";
import Tabs from "./Tabs";
import CenteredDetails from "./CenteredDetails";
import Status from "core/statuses";
import { LogsDetails } from "./LogsDetails";

type IProps = {
id: number | string;
jobIsFailed?: boolean;
};

const JobLogs: React.FC<IProps> = ({ id, jobIsFailed }) => {
const job = useResource(JobResource.detailShape(), { id });
useSubscription(JobResource.detailShape(), { id });
const job = useGetJob(id);

const [attemptNumber, setAttemptNumber] = useState<number>(
job.attempts.length ? job.attempts.length - 1 : 0
Expand All @@ -27,11 +24,16 @@ const JobLogs: React.FC<IProps> = ({ id, jobIsFailed }) => {
return <Logs />;
}

const data = job.attempts.map((item, index) => ({
const currentAttempt = job.attempts[attemptNumber].attempt;
const logs = job.attempts[attemptNumber]?.logs;
const path = ["/tmp/workspace", id, currentAttempt.id, "logs.log"].join("/");

const attemptsTabs = job.attempts.map((item, index) => ({
id: index.toString(),
status:
item.status === Status.FAILED || item.status === Status.SUCCEEDED
? item.status
item.attempt.status === Status.FAILED ||
item.attempt.status === Status.SUCCEEDED
? item.attempt.status
: undefined,
name: (
<FormattedMessage
Expand All @@ -41,33 +43,21 @@ const JobLogs: React.FC<IProps> = ({ id, jobIsFailed }) => {
),
}));

const hasLogs = !!job.logsByAttempt[attemptNumber]?.logLines?.length;
return (
<>
{job.attempts.length > 1 ? (
<Tabs
activeStep={attemptNumber.toString()}
onSelect={(at) => setAttemptNumber(parseInt(at))}
data={data}
data={attemptsTabs}
isFailed={jobIsFailed}
/>
) : null}
<CenteredDetails>
{job.attempts.length > 1 && (
<AttemptDetails attempt={job.attempts[attemptNumber]} />
)}
<div>{`/tmp/workspace/${id}/${job.attempts[attemptNumber].id}/logs.log.`}</div>
{hasLogs ? (
<DownloadButton
logs={job.logsByAttempt[attemptNumber].logLines}
fileName={`logs-${id}-${job.attempts[attemptNumber].id}`}
/>
) : null}
</CenteredDetails>
<Logs
logsArray={
hasLogs ? job.logsByAttempt[attemptNumber].logLines : undefined
}
<LogsDetails
id={job.job.id}
path={path}
currentAttempt={job.attempts.length > 1 ? currentAttempt : null}
logs={logs}
/>
</>
);
Expand Down
Loading