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
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,19 @@ export class ClientApi {
return queryString
}

fetchData = async <T, P = undefined>(url: string, method: 'GET' | 'POST', params?: P): Promise<ApiResponse<T>> => {
fetchData = async <T, P = undefined>(
url: string,
method: 'GET' | 'POST' | 'PUT',
params?: P
): Promise<ApiResponse<T>> => {
try {
let response: AxiosResponse<T>
if (method === 'GET') {
response = await this.axiosInstance.get(url)
} else if (method === 'POST') {
response = await this.axiosInstance.post(url, params)
} else if (method === 'PUT') {
response = await this.axiosInstance.put(url, params)
} else {
throw new Error(`Unsupported HTTP method: ${method}`)
}
Expand Down Expand Up @@ -64,6 +70,10 @@ export class ClientApi {
post = async <T>(url: string, body: Record<string, string> = {}): Promise<ApiResponse<T>> => {
return this.fetchData(url, 'POST', body)
}

put = async <T>(url: string, body: string | Record<string, string> = {}): Promise<ApiResponse<T>> => {
return this.fetchData(url, 'PUT', body)
}
}

export const api = new ClientApi()
Original file line number Diff line number Diff line change
Expand Up @@ -389,3 +389,7 @@ export async function queryApi(): Promise<ApiResponse<QueryInfo[]>> {
export async function queryStatusApi(queryId: string, pruned: boolean = false): Promise<ApiResponse<QueryStatusInfo>> {
return await api.get<QueryStatusInfo>(`/ui/api/query/${queryId}${pruned ? '?pruned=true' : ''}`)
}

export async function killQueryApi(queryId: string): Promise<ApiResponse<void>> {
return await api.put<void>(`/ui/api/query/${queryId}/killed`, 'Canceled via web UI')
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { QueryProgressBar } from './QueryProgressBar'
import {
Alert,
Box,
Button,
CircularProgress,
Divider,
Grid,
Expand All @@ -29,7 +30,15 @@ import {
} from '@mui/material'
import { SparkLineChart } from '@mui/x-charts/SparkLineChart'
import { Texts } from '../constant.ts'
import { StackInfo, queryStatusApi, QueryStatusInfo, QueryStage, QueryStages, Session } from '../api/webapp/api.ts'
import {
StackInfo,
killQueryApi,
queryStatusApi,
QueryStage,
QueryStages,
QueryStatusInfo,
Session,
} from '../api/webapp/api.ts'
import { ApiResponse } from '../api/base.ts'
import {
addToHistory,
Expand Down Expand Up @@ -90,6 +99,8 @@ export const QueryOverview = () => {
const [queryStatus, setQueryStatus] = useState<IQueryStatus>(initialQueryStatus)
const [loading, setLoading] = useState<boolean>(true)
const [error, setError] = useState<string | null>(null)
const [queryActionError, setQueryActionError] = useState<string | null>(null)
const [queryActionRunning, setQueryActionRunning] = useState<boolean>(false)
const queryStatusRef = useRef(queryStatus)

useEffect(() => {
Expand All @@ -107,6 +118,7 @@ export const QueryOverview = () => {

if (queryId) {
queryStatusRef.current = initialQueryStatus
setQueryActionError(null)
}

runLoop()
Expand Down Expand Up @@ -458,7 +470,35 @@ export const QueryOverview = () => {
)
}

const runQueryAction = (queryAction: (queryId: string) => Promise<ApiResponse<void>>, actionName: string) => {
if (!queryId || queryActionRunning || queryStatus.info?.finalQueryInfo) {
return
}

setQueryActionError(null)
setQueryActionRunning(true)
queryAction(queryId)
.then((apiResponse: ApiResponse<void>) => {
if (apiResponse.status === 403) {
setQueryActionError(
`${Texts.Error.Forbidden}: You do not have permission to ${actionName} this query.`
)
} else if (apiResponse.status !== 202 && apiResponse.status !== 409) {
setQueryActionError(`${Texts.Error.Communication} ${apiResponse.status}: ${apiResponse.message}`)
}
getQueryStatus()
})
.finally(() => {
setQueryActionRunning(false)
})
}

const handleCancel = () => {
runQueryAction(killQueryApi, 'cancel')
}

const taskRetriesEnabled = queryStatus.info?.retryPolicy == 'TASK'
const queryActionDisabled = queryActionRunning || !!queryStatus.info?.finalQueryInfo
return (
<>
{loading && <CircularProgress />}
Expand All @@ -467,9 +507,27 @@ export const QueryOverview = () => {
{!loading && !error && queryStatus.info && (
<Grid container spacing={0}>
<Grid size={{ xs: 12 }}>
<Box sx={{ pt: 2 }}>
<QueryProgressBar queryInfoBase={queryStatus.info} />
<Box sx={{ pt: 2, display: 'flex', alignItems: 'center', gap: 1 }}>
<Box sx={{ flexGrow: 1, minWidth: 0 }}>
<QueryProgressBar queryInfoBase={queryStatus.info} />
</Box>
<Box sx={{ display: 'flex', flexShrink: 0, gap: 1 }}>
<Button
variant="outlined"
color="error"
size="small"
disabled={queryActionDisabled || !!queryActionError}
onClick={handleCancel}
>
Cancel query
</Button>
</Box>
</Box>
{queryActionError && (
<Alert severity="error" sx={{ mt: 1 }}>
{queryActionError}
</Alert>
)}
</Grid>

<Grid container spacing={3}>
Expand Down