feat(releases): replay actions (#932)

* feat(releases): replay actions

* feat(releases): replay actions component

* fix: update filter actions

* fix: select filter_id from ras
This commit is contained in:
ze0s 2023-05-15 21:30:04 +02:00 committed by GitHub
parent 97333d334f
commit 6898ad8315
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 752 additions and 189 deletions

View file

@ -5,11 +5,17 @@
import * as React from "react";
import { formatDistanceToNowStrict } from "date-fns";
import { CheckIcon } from "@heroicons/react/24/solid";
import { ArrowPathIcon, CheckIcon } from "@heroicons/react/24/solid";
import { ClockIcon, ExclamationCircleIcon, NoSymbolIcon } from "@heroicons/react/24/outline";
import { classNames, simplifyDate } from "@utils";
import { Tooltip } from "../tooltips/Tooltip";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { APIClient } from "@api/APIClient";
import { filterKeys } from "@screens/filters/list";
import { toast } from "react-hot-toast";
import Toast from "@components/notifications/Toast";
import { RingResizeSpinner } from "@components/Icons";
interface CellProps {
value: string;
@ -57,6 +63,46 @@ export const TitleCell = ({ value }: CellProps) => (
</div>
);
interface RetryActionButtonProps {
status: ReleaseActionStatus;
}
interface RetryAction {
releaseId: number;
actionId: number;
}
const RetryActionButton = ({ status }: RetryActionButtonProps) => {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (vars: RetryAction) => APIClient.release.replayAction(vars.releaseId, vars.actionId),
onSuccess: () => {
// Invalidate filters just in case, most likely not necessary but can't hurt.
queryClient.invalidateQueries({ queryKey: filterKeys.lists() });
toast.custom((t) => (
<Toast type="success" body={`${status?.action} replayed`} t={t} />
));
}
});
const replayAction = () => {
console.log("replay action");
mutation.mutate({ releaseId: status.release_id,actionId: status.id });
};
return (
<button className="flex items-center px-1.5 py-1 ml-2 border-gray-500 bg-gray-700 rounded hover:bg-gray-600" onClick={replayAction}>
<span className="mr-1.5">Retry</span>
{mutation.isLoading
? <RingResizeSpinner className="text-blue-500 w-4 h-4 iconHeight" aria-hidden="true" />
: <ArrowPathIcon className="h-4 w-4" />
}
</button>
);
};
interface ReleaseStatusCellProps {
value: ReleaseActionStatus[];
}
@ -64,69 +110,89 @@ interface ReleaseStatusCellProps {
interface StatusCellMapEntry {
colors: string;
icon: React.ReactElement;
textFormatter: (text: string) => React.ReactElement;
textFormatter: (status: ReleaseActionStatus) => React.ReactElement;
}
const StatusCellMap: Record<string, StatusCellMapEntry> = {
"PUSH_ERROR": {
colors: "bg-pink-100 text-pink-800 hover:bg-pink-300",
icon: <ExclamationCircleIcon className="h-5 w-5" aria-hidden="true" />,
textFormatter: (text: string) => (
textFormatter: (status: ReleaseActionStatus) => (
<>
<span>
Action
{" "}
<span className="font-bold underline underline-offset-2 decoration-2 decoration-red-500">
{" "}
<span className="font-bold underline underline-offset-2 decoration-2 decoration-red-500">
error
</span>
{": "}
{status.action}
</span>
{": "}
{text}
<div>
{status.action_id > 0 && <RetryActionButton status={status} />}
</div>
</>
)
},
"PUSH_REJECTED": {
colors: "bg-blue-100 dark:bg-blue-100 text-blue-400 dark:text-blue-800 hover:bg-blue-300 dark:hover:bg-blue-400",
icon: <NoSymbolIcon className="h-5 w-5" aria-hidden="true" />,
textFormatter: (text: string) => (
textFormatter: (status: ReleaseActionStatus) => (
<>
<span>
Action
{" "}
<span
className="font-bold underline underline-offset-2 decoration-2 decoration-sky-500"
>
{" "}
<span
className="font-bold underline underline-offset-2 decoration-2 decoration-sky-500"
>
rejected
</span>
{": "}
{status.action}
</span>
{": "}
{text}
<div>
{status.action_id > 0 && <RetryActionButton status={status} />}
</div>
</>
)
},
"PUSH_APPROVED": {
colors: "bg-green-100 text-green-800 hover:bg-green-300",
icon: <CheckIcon className="h-5 w-5" aria-hidden="true" />,
textFormatter: (text: string) => (
textFormatter: (status: ReleaseActionStatus) => (
<>
Action
{" "}
<span className="font-bold underline underline-offset-2 decoration-2 decoration-green-500">
<span>
Action
{" "}
<span className="font-bold underline underline-offset-2 decoration-2 decoration-green-500">
approved
</span>
{": "}
{status.action}
</span>
{": "}
{text}
{/*<div>*/}
{/* {status.action_id > 0 && <RetryActionButton status={status} />}*/}
{/*</div>*/}
</>
)
},
"PENDING": {
colors: "bg-yellow-100 text-yellow-800 hover:bg-yellow-200",
icon: <ClockIcon className="h-5 w-5" aria-hidden="true" />,
textFormatter: (text: string) => (
textFormatter: (status: ReleaseActionStatus) => (
<>
Action
{" "}
<span className="font-bold underline underline-offset-2 decoration-2 decoration-yellow-500">
<span>
Action
{" "}
<span className="font-bold underline underline-offset-2 decoration-2 decoration-yellow-500">
pending
</span>
{": "}
{status.action}
</span>
{": "}
{text}
<div>
{status.action_id > 0 && <RetryActionButton status={status} />}
</div>
</>
)
}
@ -156,7 +222,7 @@ export const ReleaseStatusCell = ({ value }: ReleaseStatusCellProps) => (
>
<Tooltip
label={StatusCellMap[v.status].icon}
title={StatusCellMap[v.status].textFormatter(v.action)}
title={StatusCellMap[v.status].textFormatter(v)}
>
<div className="mb-1">
<CellLine title="Type">{v.type}</CellLine>