-
Notifications
You must be signed in to change notification settings - Fork 23
PM-3907 refactor layout, move "rerun" tooltip to button, #1529
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
Changes from all commits
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 |
|---|---|---|
| @@ -1,8 +1,12 @@ | ||
| import { FC, MouseEvent as ReactMouseEvent, useContext, useMemo } from 'react' | ||
| import { FC, MouseEvent as ReactMouseEvent, useCallback, useContext, useMemo, useState } from 'react' | ||
| import { Link } from 'react-router-dom' | ||
| import { toast } from 'react-toastify' | ||
| import { useSWRConfig } from 'swr' | ||
| import { FullConfiguration } from 'swr/dist/types' | ||
| import classNames from 'classnames' | ||
| import moment from 'moment' | ||
|
|
||
| import { handleError } from '~/libs/shared/lib/utils/handle-error' | ||
| import { useWindowSize, WindowSize } from '~/libs/shared' | ||
| import { IconOutline, Tooltip } from '~/libs/ui' | ||
|
|
||
|
|
@@ -12,7 +16,11 @@ import { | |
| AiWorkflowRun, | ||
| AiWorkflowRunsResponse, | ||
| AiWorkflowRunStatusEnum, | ||
| getAiWorkflowRunsCacheKey, | ||
| retriggerAiWorkflowRun, | ||
| useFetchAiWorkflowsRuns, | ||
| useRolePermissions, | ||
| UseRolePermissionsResult, | ||
| } from '../../hooks' | ||
| import { IconAiReview } from '../../assets/icons' | ||
| import { TABLE_DATE_FORMAT } from '../../../config/index.config' | ||
|
|
@@ -170,7 +178,9 @@ const AiReviewsTable: FC<AiReviewsTableProps> = props => { | |
| ?? configured?.workflow?.scorecard?.minimumPassingScore | ||
|
|
||
| const status = fromDecision | ||
| ? normalizeStatus(fromDecision.runStatus, fromDecision.runScore, minScore) | ||
| ? normalizeStatus(run && aiRunInProgress(run) | ||
| ? undefined | ||
| : fromDecision.runStatus, fromDecision.runScore, minScore) | ||
| : undefined | ||
|
|
||
| return { | ||
|
|
@@ -230,6 +240,26 @@ const AiReviewsTable: FC<AiReviewsTableProps> = props => { | |
|
|
||
| const loading = isLoading || isLoadingAiReviewConfig || isLoadingAiReviewDecisions | ||
|
|
||
| const { isAdmin }: UseRolePermissionsResult = useRolePermissions() | ||
| const { mutate }: FullConfiguration = useSWRConfig() | ||
| const [, setRerunningRunId] = useState<string | undefined>(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. [ |
||
|
|
||
| const handleRerun = useCallback(async (runId?: string): Promise<void> => { | ||
|
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. [❗❗ |
||
| if (!runId || runId === '-1') return | ||
|
|
||
| setRerunningRunId(runId) | ||
| try { | ||
| await retriggerAiWorkflowRun(runId) | ||
| await mutate(getAiWorkflowRunsCacheKey(props.submission.id)) | ||
| toast.success('Workflow re-run triggered successfully.') | ||
| } catch (error) { | ||
| handleError(error as Error) | ||
| toast.error('Failed to trigger workflow re-run.') | ||
| } finally { | ||
| setRerunningRunId(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. [ |
||
| } | ||
| }, [mutate, props.submission.id]) | ||
|
|
||
| const failedGatingReviewers = useMemo( | ||
| () => reviewerRows | ||
| .filter(row => row.isGating && (row.status === 'failed' || row.status === 'failed-score')) | ||
|
|
@@ -334,15 +364,24 @@ const AiReviewsTable: FC<AiReviewsTableProps> = props => { | |
| <div className={styles.mobileRow}> | ||
| <div className={styles.label}>Result</div> | ||
| <div className={`${styles.value} ${styles.resultCol}`}> | ||
| {row.status ? ( | ||
| <AiWorkflowRunStatus | ||
| status={row.status} | ||
| score={row.score ?? undefined} | ||
| showScore={false} | ||
| /> | ||
| ) : ( | ||
| <AiWorkflowRunStatus run={row.run} submissionId={props.submission.id} /> | ||
| )} | ||
| <AiWorkflowRunStatus | ||
| run={row.run} | ||
| status={row.status} | ||
| action={ | ||
| row.run?.id | ||
| && row.run?.id !== '-1' | ||
| && isAdmin | ||
| && row.status !== 'pending' | ||
| && ( | ||
| <Tooltip content='Re-run the workflow'> | ||
| <IconOutline.RefreshIcon | ||
| className={classNames('icon-lg', styles.reRunIcon)} | ||
| onClick={function onClick() { handleRerun(row.run!.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. [💡 |
||
| /> | ||
| </Tooltip> | ||
| ) | ||
| } | ||
| /> | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
@@ -427,15 +466,24 @@ const AiReviewsTable: FC<AiReviewsTableProps> = props => { | |
| ) : '-'} | ||
| </td> | ||
| <td className={styles.resultCol}> | ||
| {row.status ? ( | ||
| <AiWorkflowRunStatus | ||
| status={row.status} | ||
| score={row.score ?? undefined} | ||
| showScore={false} | ||
| /> | ||
| ) : ( | ||
| <AiWorkflowRunStatus run={row.run} submissionId={props.submission.id} /> | ||
| )} | ||
| <AiWorkflowRunStatus | ||
| status={row.status} | ||
| run={row.run} | ||
| action={ | ||
| row.run?.id | ||
| && row.run?.id !== '-1' | ||
| && isAdmin | ||
| && row.status !== 'pending' | ||
| && ( | ||
|
Comment on lines
+473
to
+477
Contributor
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. 🟡 Re-run button shown for in-progress runs when row.status is undefined When Prompt for agentsWas this helpful? React with 👍 or 👎 to provide feedback. |
||
| <Tooltip content='Re-run the workflow'> | ||
| <IconOutline.RefreshIcon | ||
| className={classNames('icon-lg', styles.reRunIcon)} | ||
| onClick={function onClick() { handleRerun(row.run!.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. [💡 |
||
| /> | ||
| </Tooltip> | ||
| ) | ||
| } | ||
| /> | ||
| </td> | ||
| </tr> | ||
| ))} | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,31 +1,18 @@ | ||
| import { FC, PropsWithChildren, useCallback, useMemo, useState } from 'react' | ||
| import { toast } from 'react-toastify' | ||
| import { useSWRConfig } from 'swr' | ||
| import { FullConfiguration } from 'swr/dist/types' | ||
| import { FC, ReactNode, useMemo } from 'react' | ||
|
|
||
| import { IconOutline, Tooltip } from '~/libs/ui' | ||
| import { handleError } from '~/libs/shared/lib/utils/handle-error' | ||
| import { IconOutline } from '~/libs/ui' | ||
|
|
||
| import { | ||
| aiRunFailed, | ||
| aiRunInProgress, | ||
| AiWorkflowRun, | ||
| getAiWorkflowRunsCacheKey, | ||
| retriggerAiWorkflowRun, | ||
| useRolePermissions, | ||
| UseRolePermissionsResult, | ||
| } from '../../hooks' | ||
| import { aiRunFailed, aiRunInProgress, AiWorkflowRun } from '../../hooks' | ||
|
|
||
| import StatusLabel from './StatusLabel' | ||
| import styles from './AiWorkflowRunStatus.module.scss' | ||
|
|
||
| interface AiWorkflowRunStatusProps { | ||
| run?: Pick<AiWorkflowRun, 'status'|'score'|'workflow'|'id'> | ||
| status?: 'passed' | 'pending' | 'failed-score' | 'failed' | ||
| score?: number | ||
| hideLabel?: boolean | ||
| showScore?: boolean | ||
| submissionId?: string | ||
| action?: ReactNode | ||
|
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. [ |
||
| } | ||
|
|
||
| const aiRunStatus = (run: Pick<AiWorkflowRun, 'status'|'score'|'workflow'>): string => { | ||
|
|
@@ -41,10 +28,6 @@ const aiRunStatus = (run: Pick<AiWorkflowRun, 'status'|'score'|'workflow'>): str | |
| } | ||
|
|
||
| export const AiWorkflowRunStatus: FC<AiWorkflowRunStatusProps> = props => { | ||
| const [isRerunning, setIsRerunning] = useState(false) | ||
| const { isAdmin }: UseRolePermissionsResult = useRolePermissions() | ||
| const { mutate }: FullConfiguration = useSWRConfig() | ||
|
|
||
| const status = useMemo(() => { | ||
| if (props.status) { | ||
| return props.status | ||
|
|
@@ -58,71 +41,18 @@ export const AiWorkflowRunStatus: FC<AiWorkflowRunStatusProps> = props => { | |
| }, [props.status, props.run]) | ||
|
|
||
| const displayStatus = status | ||
|
|
||
| const handleRerun = useCallback(async (): Promise<void> => { | ||
| const runId = props.run?.id | ||
| if (!runId || runId === '-1') { | ||
| return | ||
| } | ||
|
|
||
| setIsRerunning(true) | ||
|
|
||
| try { | ||
| await retriggerAiWorkflowRun(runId) | ||
|
|
||
| if (props.submissionId) { | ||
| await mutate(getAiWorkflowRunsCacheKey(props.submissionId)) | ||
| } else { | ||
| await mutate( | ||
| (key: unknown) => typeof key === 'string' && key.includes('/workflows/runs?submissionId='), | ||
| ) | ||
| } | ||
|
|
||
| toast.success('Workflow re-run triggered successfully.') | ||
| } catch (error) { | ||
| handleError(error as Error) | ||
| toast.error('Failed to trigger workflow re-run.') | ||
| } finally { | ||
| setIsRerunning(false) | ||
| } | ||
| }, [mutate, props.run, props.submissionId]) | ||
|
|
||
| const score: number | undefined = props.showScore ? (props.score ?? props.run?.score) : undefined | ||
|
|
||
| const Wrapper: FC<PropsWithChildren> = useCallback(({ children }: PropsWithChildren) => { | ||
| if (!isAdmin || displayStatus === 'pending' || !props.run?.id || props.run?.id === '-1') { | ||
| return <>{children}</> | ||
| } | ||
|
|
||
| return ( | ||
| <Tooltip | ||
| clickable | ||
| content={( | ||
| <button | ||
| type='button' | ||
| className={styles.reRunButton} | ||
| disabled={isRerunning} | ||
| onClick={handleRerun} | ||
| > | ||
| <IconOutline.ArrowRightIcon className='icon-sm' style={{ marginRight: '0.5rem' }} /> | ||
| {isRerunning ? 'Re-running...' : 'Re-run'} | ||
| </button> | ||
| )} | ||
| > | ||
| {children} | ||
| </Tooltip> | ||
| ) | ||
| }, [isAdmin, displayStatus, props.run, isRerunning, handleRerun]) | ||
|
|
||
| return ( | ||
| <Wrapper> | ||
| <> | ||
| {displayStatus === 'passed' && ( | ||
| <StatusLabel | ||
| icon={<IconOutline.CheckIcon className='icon-xl' />} | ||
| hideLabel={props.hideLabel} | ||
| label='Passed' | ||
| status={displayStatus} | ||
| score={score} | ||
| action={props.action} | ||
| /> | ||
| )} | ||
| {displayStatus === 'failed-score' && ( | ||
|
|
@@ -132,6 +62,7 @@ export const AiWorkflowRunStatus: FC<AiWorkflowRunStatusProps> = props => { | |
| label='Failed' | ||
| status={displayStatus} | ||
| score={score} | ||
| action={props.action} | ||
| /> | ||
| )} | ||
| {displayStatus === 'pending' && ( | ||
|
|
@@ -141,6 +72,7 @@ export const AiWorkflowRunStatus: FC<AiWorkflowRunStatusProps> = props => { | |
| label='To be filled' | ||
| status={displayStatus} | ||
| score={score} | ||
| action={props.action} | ||
| /> | ||
| )} | ||
| {displayStatus === 'failed' && ( | ||
|
|
@@ -150,8 +82,9 @@ export const AiWorkflowRunStatus: FC<AiWorkflowRunStatusProps> = props => { | |
| status={displayStatus} | ||
| label='Failure' | ||
| score={score} | ||
| action={props.action} | ||
| /> | ||
| )} | ||
| </Wrapper> | ||
| </> | ||
| ) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,7 @@ interface StatusLabelProps { | |
| label?: string | ||
| score?: number | ||
| status: 'pending' | 'failed' | 'passed' | 'failed-score' | ||
| action?: ReactNode | ||
|
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. [❗❗ |
||
| } | ||
|
|
||
| const StatusLabel: FC<StatusLabelProps> = props => ( | ||
|
|
@@ -22,6 +23,7 @@ const StatusLabel: FC<StatusLabelProps> = props => ( | |
| </span> | ||
| )} | ||
| {!props.hideLabel && props.label} | ||
| {props.action} | ||
|
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. [ |
||
| </div> | ||
| ) | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -87,14 +87,15 @@ | |
| } | ||
|
|
||
| .table { | ||
| margin-top: $sp-2; | ||
| margin-left: -1 * $sp-4; | ||
| @include ltelg { | ||
| margin-top: 0; | ||
| margin-left: -1 * $sp-4; | ||
| margin-right: -1 * $sp-4; | ||
| } | ||
| margin-top: -1px; | ||
|
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. [ |
||
| } | ||
| // margin-left: -1 * $sp-4; | ||
|
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. [💡 |
||
| // @include ltelg { | ||
| // margin-top: 0; | ||
| // margin-left: -1 * $sp-4; | ||
| // margin-right: -1 * $sp-4; | ||
| // } | ||
| // } | ||
|
|
||
| .rotated { | ||
| transform: rotate(180deg); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.