-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
Fix copy link to logs functionality #15368
Changes from 4 commits
4d84bdb
7aefd6f
4d393d2
71e82a3
1527d19
00f717a
f57a686
1a18a30
60b0082
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,7 @@ import { Spinner } from "components"; | |
import { SynchronousJobReadWithStatus } from "core/request/LogsRequestError"; | ||
import { JobsWithJobs } from "pages/ConnectionPage/pages/ConnectionItemPage/components/JobsList"; | ||
|
||
import { AttemptRead, JobStatus } from "../../core/request/AirbyteClient"; | ||
import { AttemptRead, CheckConnectionReadStatus, JobStatus } from "../../core/request/AirbyteClient"; | ||
import { useAttemptLink } from "./attemptLinkUtils"; | ||
import ContentWrapper from "./components/ContentWrapper"; | ||
import ErrorDetails from "./components/ErrorDetails"; | ||
|
@@ -32,28 +32,28 @@ const LoadLogs = styled.div` | |
`; | ||
|
||
interface JobItemProps { | ||
shortInfo?: boolean; | ||
job: SynchronousJobReadWithStatus | JobsWithJobs; | ||
} | ||
|
||
const didJobSucceed = (job: SynchronousJobReadWithStatus | JobsWithJobs) => { | ||
return getJobStatus(job) !== "failed"; | ||
}; | ||
|
||
export const getJobStatus: (job: SynchronousJobReadWithStatus | JobsWithJobs) => JobStatus = (job) => { | ||
return (job as JobsWithJobs).job?.status ?? (job as SynchronousJobReadWithStatus).status; | ||
export const getJobStatus: ( | ||
job: SynchronousJobReadWithStatus | JobsWithJobs | ||
) => JobStatus | CheckConnectionReadStatus = (job) => { | ||
return "status" in job ? job.status : job.job.status; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ℹ️ The casting also caused TypeScript to lose the real return type here, so changed this as well. |
||
}; | ||
|
||
export const getJobAttemps: (job: SynchronousJobReadWithStatus | JobsWithJobs) => AttemptRead[] | undefined = (job) => { | ||
return "attempts" in job ? job.attempts : undefined; | ||
}; | ||
|
||
export const getJobId = (job: SynchronousJobReadWithStatus | JobsWithJobs) => | ||
(job as SynchronousJobReadWithStatus).id ?? (job as JobsWithJobs).job.id; | ||
export const getJobId = (job: SynchronousJobReadWithStatus | JobsWithJobs) => ("id" in job ? job.id : job.job.id); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ℹ️ Doing this without casting now causes this method to understand that its return type is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When I was initially going through here I thought there was a bug. But no, we unfortunately get back both from the backend :/ |
||
|
||
export const JobItem: React.FC<JobItemProps> = ({ shortInfo, job }) => { | ||
export const JobItem: React.FC<JobItemProps> = ({ job }) => { | ||
const { jobId: linkedJobId } = useAttemptLink(); | ||
const [isOpen, setIsOpen] = useState(linkedJobId === getJobId(job)); | ||
const [isOpen, setIsOpen] = useState(() => linkedJobId === String(getJobId(job))); | ||
const scrollAnchor = useRef<HTMLDivElement>(null); | ||
|
||
const didSucceed = didJobSucceed(job); | ||
|
@@ -63,24 +63,25 @@ export const JobItem: React.FC<JobItemProps> = ({ shortInfo, job }) => { | |
}; | ||
|
||
useEffectOnce(() => { | ||
if (linkedJobId) { | ||
scrollAnchor.current?.scrollIntoView({ | ||
behavior: "smooth", | ||
block: "start", | ||
}); | ||
if (linkedJobId === String(getJobId(job))) { | ||
timroes marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// We need to wait here a bit, so the page has a chance to finish rendering, before starting to scroll | ||
// since otherwise this scroll won't really do anything. | ||
const timeout = window.setTimeout(() => { | ||
scrollAnchor.current?.scrollIntoView({ | ||
behavior: "smooth", | ||
timroes marked this conversation as resolved.
Show resolved
Hide resolved
|
||
block: "start", | ||
}); | ||
}, 1000); | ||
return () => { | ||
window.clearTimeout(timeout); | ||
}; | ||
} | ||
return undefined; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This unfortunately doesn't help (I barely ever had a case where useLayoutEffect actually helped :D). This will just cause it to slip into the execution slot after the next rendering, which unfortunately isn't enough in this case. There is just too much (async) rendering still ongoing, that even setting a timeout of like 300ms isn't enough to get this work. Tested also with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it's a better idea, but could do a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We unfortunately also don't have a way to determine whether it's loaded in that sense. The DOM reference IS there from thebeginning and mounted, so there is no clear way to determine that the browser is done with rendering everything around it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh good call. Yeah we def can use the animationComplete there to trigger the scroll to. Will change this tomorrow. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can push this if you'd like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pushed to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added this to this PR, as discussed offline this won't work in Chrome (on Linux) apparently, but since it'll work in Firefox stable, we'll still keep this code in. |
||
}); | ||
|
||
return ( | ||
<Item isFailed={!didSucceed} ref={scrollAnchor}> | ||
<MainInfo | ||
shortInfo={shortInfo} | ||
isOpen={isOpen} | ||
isFailed={!didSucceed} | ||
onExpand={onExpand} | ||
job={job} | ||
attempts={getJobAttemps(job)} | ||
/> | ||
<MainInfo isOpen={isOpen} isFailed={!didSucceed} onExpand={onExpand} job={job} attempts={getJobAttemps(job)} /> | ||
<ContentWrapper isOpen={isOpen}> | ||
<div> | ||
<Suspense | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
import { faBan, faCheck, faExclamationTriangle, faTimes, IconDefinition } from "@fortawesome/free-solid-svg-icons"; | ||
import { faBan, faCheck, faExclamationTriangle, faTimes } from "@fortawesome/free-solid-svg-icons"; | ||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | ||
import React from "react"; | ||
import styled from "styled-components"; | ||
|
@@ -8,7 +8,7 @@ import { MoonIcon } from "components/icons/MoonIcon"; | |
import PauseIcon from "../icons/PauseIcon"; | ||
import CircleLoader from "./CircleLoader"; | ||
|
||
export type StatusIconStatus = "sleep" | "inactive" | "success" | "warning" | "loading"; | ||
export type StatusIconStatus = "sleep" | "inactive" | "success" | "warning" | "loading" | "error"; | ||
|
||
interface StatusIconProps { | ||
className?: string; | ||
|
@@ -20,20 +20,22 @@ interface StatusIconProps { | |
|
||
const getBadgeWidth = (props: StatusIconProps) => (props.big ? (props.value ? 57 : 40) : props.value ? 37 : 20); | ||
|
||
const _iconByStatus: Partial<Record<StatusIconStatus, IconDefinition | undefined>> = { | ||
const _iconByStatus = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ℹ️ By changing this just to a |
||
sleep: faBan, | ||
success: faCheck, | ||
warning: faExclamationTriangle, | ||
}; | ||
error: faTimes, | ||
} as const; | ||
|
||
const _themeByStatus: Partial<Record<StatusIconStatus, string>> = { | ||
const _themeByStatus = { | ||
sleep: "lightTextColor", | ||
inactive: "lightTextColor", | ||
success: "successColor", | ||
warning: "warningColor", | ||
}; | ||
error: "dangerColor", | ||
} as const; | ||
|
||
const Container = styled.div<StatusIconProps>` | ||
const Container = styled.div<Pick<StatusIconProps, "big" | "value">>` | ||
width: ${(props) => getBadgeWidth(props)}px; | ||
height: ${({ big }) => (big ? 40 : 20)}px; | ||
margin-right: 10px; | ||
|
@@ -44,8 +46,8 @@ const Container = styled.div<StatusIconProps>` | |
vertical-align: middle; | ||
`; | ||
|
||
const Badge = styled(Container)<StatusIconProps>` | ||
background: ${(props) => props.theme[(props.status && _themeByStatus[props.status]) || "dangerColor"]}; | ||
const Badge = styled(Container)<{ status: Exclude<StatusIconStatus, "loading"> }>` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ℹ️ Just require the properties that are actually used here (and in the |
||
background: ${({ theme, status }) => theme[_themeByStatus[status]]}; | ||
border-radius: ${({ value }) => (value ? "15px" : "50%")}; | ||
color: ${({ theme }) => theme.whiteColor}; | ||
padding-top: ${({ status }) => (status === "warning" || status === "inactive" ? 3 : 4)}px; | ||
|
@@ -66,7 +68,7 @@ const Value = styled.span` | |
padding-left: 3px; | ||
`; | ||
|
||
const StatusIcon: React.FC<StatusIconProps> = ({ title, status, ...props }) => { | ||
const StatusIcon: React.FC<StatusIconProps> = ({ title, status = "error", ...props }) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ℹ️ Make |
||
const valueElement = props.value ? <Value>{props.value}</Value> : null; | ||
|
||
if (status === "loading") { | ||
|
@@ -85,7 +87,7 @@ const StatusIcon: React.FC<StatusIconProps> = ({ title, status, ...props }) => { | |
) : status === "sleep" ? ( | ||
<MoonIcon title={title} /> | ||
) : ( | ||
<FontAwesomeIcon icon={(status && _iconByStatus[status]) || faTimes} title={title} /> | ||
<FontAwesomeIcon icon={_iconByStatus[status]} title={title} /> | ||
)} | ||
{valueElement} | ||
</Badge> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ℹ️ This was never passed into this component, so removed it.