Skip to content
Open
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
7 changes: 7 additions & 0 deletions web/src/app/api/jobs/jobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,10 @@ export const getJobStatus = async () => {
const response = await fetch(`${API_URL}/job/statuses`)
return await response.json()
}

export const cancelJob = async (id: string) => {
const response = await fetch(`${API_URL}/job/${id}/cancel`, {
method: 'POST',
})
return await response.json()
}
7 changes: 7 additions & 0 deletions web/src/common/ClientLayout/ClientLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,16 @@ const LeftNavContainer = dynamic(
{ ssr: false },
)

const PatternToastContainer = dynamic(
() => import('@patterninc/react-ui').then((mod) => mod.PatternToastContainer),
{
ssr: false,
},
)
const ClientLayout = ({ children }: { children: ReactNode }) => {
return (
<ReactQueryProvider>
<PatternToastContainer />
<div className='App'>
<BreadcrumbProvidercontainer>
<AutoRefreshProvidercontainer>
Expand Down
1 change: 1 addition & 0 deletions web/src/modules/Jobs/Helper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export type JobType = {
created_at: number
updated_at: number
status: string
is_sync: boolean
command_criteria: string[]
cluster_criteria: string[]
command_id: string
Expand Down
89 changes: 81 additions & 8 deletions web/src/modules/Jobs/JobDetails/JobDetailsHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,69 @@
'use client'

import { Alert, PageHeader, SectionHeader } from '@patterninc/react-ui'
import {
Alert,
Ellipsis,
PageFooter,
PageHeader,
SectionHeader,
toast,
} from '@patterninc/react-ui'
import { JobDataTypesProps } from '../Helper'
import SyntaxHighlighter from 'react-syntax-highlighter'
import { github } from 'react-syntax-highlighter/dist/esm/styles/hljs'
import ApiResponseButton from '@/components/ApiResponseButton/ApiResponseButton'
import { cancelJob } from '@/app/api/jobs/jobs'
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { useMemo } from 'react'

const CANCELABLE_STATUSES = ['NEW', 'ACCEPTED', 'RUNNING']

const JobDetailsHeader = ({
jobData,
}: JobDataTypesProps): React.JSX.Element => {
const queryClient = useQueryClient()
const cancelMutation = useMutation({
mutationFn: (id: string) => cancelJob(id),
onSuccess: (response) => {
if (response.status === 'CANCELLING') {
toast({
type: 'info',
message: `Job is being canceled...`,
})
queryClient.invalidateQueries({ queryKey: ['job', jobData?.id] })
} else {
toast({
type: 'error',
message: response.error || 'Failed to cancel job',
})
}
},
onError: () => {
toast({
type: 'error',
message: 'Failed to cancel job',
})
},
})

// Only async jobs in active states can be cancelled
const isCancelable = useMemo(
() =>
CANCELABLE_STATUSES.includes(jobData?.status ?? '') &&
jobData?.is_sync !== true,
[jobData?.status, jobData?.is_sync],
)

const isCancelling = jobData?.status === 'CANCELLING'

return (
<div className='w-full'>
<PageHeader
rightSectionChildren={
<ApiResponseButton link={`/api/v1/job/${jobData?.id}`} />
}
bottomSectionChildren={
<div
className='rounded overflow-auto bg-white border-t border-medium-purple'
>
<div className='border-medium-purple overflow-auto rounded border-t bg-white'>
<div className='flex flex-col gap-4 p-4'>
{jobData?.status === 'FAILED' ? (
<Alert type='error' text={jobData?.error} />
Expand All @@ -42,17 +87,19 @@ const JobDetailsHeader = ({
<div>
<SectionHeader title='Tags' />
<ul>
{jobData?.tags.map((value) => <li key={value}>{value}</li>)}
{jobData?.tags.map((value) => (
<li key={value}>{value}</li>
))}
</ul>
</div>
) : null}
<div>
{jobData?.context?.query ? (
<>
<SectionHeader title='SQL Query' />
<SyntaxHighlighter language='sql' style={github}>
{jobData.context.query}
</SyntaxHighlighter>
<SyntaxHighlighter language='sql' style={github}>
{jobData.context.query}
</SyntaxHighlighter>
</>
) : null}
</div>
Expand Down Expand Up @@ -88,6 +135,32 @@ const JobDetailsHeader = ({
value: <></>,
}}
/>
<PageFooter
rightSection={[
{
as: 'confirmation',
confirmation: {
header: 'Cancel Job',
body: 'Are you sure you want to cancel this job?',
confirmCallout: () => {
if (jobData?.id) cancelMutation.mutate(jobData.id)
},
type: 'red',
},
children: isCancelling ? (
<span>
Canceling job
<Ellipsis />
</span>
) : (
'Cancel Job'
),
styleType: 'primary-red',
type: 'button',
disabled: !isCancelable || isCancelling,
},
]}
/>
</div>
)
}
Expand Down
Loading