Skip to content
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

Feat/workflow list enhancement #305

Draft
wants to merge 1 commit into
base: dev
Choose a base branch
from
Draft
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
45 changes: 45 additions & 0 deletions frontend/src/features/myWorkflows/api/runs/useStartRuns.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { type MutationConfig } from "@services/clients/react-query.client";
import { useMutation } from "@tanstack/react-query";
import { type AxiosError } from "axios";
import { type IBatchWorkflowActionResponse } from "features/myWorkflows/types/workflow";
import { toast } from "react-toastify";
import { dominoApiClient } from "services/clients/domino.client";

interface StartRunsParams {
workflowIds: number[];
}

interface UseStartRuns {
workspaceId?: string;
}

export const useStartRuns = (
{ workspaceId }: UseStartRuns,
config: MutationConfig<StartRunsParams, IBatchWorkflowActionResponse> = {},
) => {
return useMutation({
mutationFn: async ({ workflowIds }) => {
if (!workflowIds) throw new Error("No workflow selected");
return await postWorkflowRunIds({ workflowIds, workspaceId });
},
onError: (e: AxiosError<{ detail: string }>) => {
const message =
(e.response?.data?.detail ?? e?.message) || "Something went wrong";

toast.error(message, {
toastId: message,
});
},
...config,
});
};

const postWorkflowRunIds = async ({
workflowIds,
workspaceId,
}: StartRunsParams & UseStartRuns): Promise<IBatchWorkflowActionResponse> => {
return await dominoApiClient.post(
`/batch/workspaces/${workspaceId}/workflows/runs`,
workflowIds,
);
};
45 changes: 45 additions & 0 deletions frontend/src/features/myWorkflows/api/runs/useStopRuns.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { type MutationConfig } from "@services/clients/react-query.client";
import { useMutation } from "@tanstack/react-query";
import { type AxiosError } from "axios";
import { type IBatchWorkflowActionResponse } from "features/myWorkflows/types/workflow";
import { toast } from "react-toastify";
import { dominoApiClient } from "services/clients/domino.client";

interface StopRunsParams {
workflowIds: number[];
}

interface UseStopRuns {
workspaceId?: string;
}

export const useStopRuns = (
{ workspaceId }: UseStopRuns,
config: MutationConfig<StopRunsParams, IBatchWorkflowActionResponse> = {},
) => {
return useMutation({
mutationFn: async ({ workflowIds }) => {
if (!workflowIds) throw new Error("No workflow selected");
return await postWorkflowStopIds({ workflowIds, workspaceId });
},
onError: (e: AxiosError<{ detail: string }>) => {
const message =
(e.response?.data?.detail ?? e?.message) || "Something went wrong";

toast.error(message, {
toastId: message,
});
},
...config,
});
};

const postWorkflowStopIds = async ({
workflowIds,
workspaceId,
}: StopRunsParams & UseStopRuns): Promise<IBatchWorkflowActionResponse> => {
return await dominoApiClient.patch(
`/batch/workspaces/${workspaceId}/workflows/runs`,
workflowIds,
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { type MutationConfig } from "@services/clients/react-query.client";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { type AxiosError } from "axios";
import { type IBatchWorkflowActionResponse } from "features/myWorkflows/types/workflow";
import { toast } from "react-toastify";
import { dominoApiClient } from "services/clients/domino.client";

interface DeleteWorkflowsParams {
workflowIds: number[];
}

interface UseDeleteWorkflows {
workspaceId?: string;
}

export const useDeleteWorkflows = (
{ workspaceId }: UseDeleteWorkflows,
config: MutationConfig<
DeleteWorkflowsParams,
IBatchWorkflowActionResponse
> = {},
) => {
const queryClient = useQueryClient();

return useMutation({
mutationFn: async ({ workflowIds }) => {
if (!workspaceId) throw new Error("No workspace selected");
return await deleteWorkflowByIds({ workflowIds, workspaceId });
},
onSuccess: async (_, { workflowIds }) => {
await queryClient.invalidateQueries({
queryKey: ["WORKFLOWS", workspaceId],
});
await queryClient.invalidateQueries({
queryKey: ["WORKFLOW", workspaceId, workflowIds],
});
},
onError: (e: AxiosError<{ detail: string }>) => {
const message =
(e.response?.data?.detail ?? e?.message) || "Something went wrong";

toast.error(message, {
toastId: message,
});
},
...config,
});
};

const deleteWorkflowByIds = async (
params: DeleteWorkflowsParams & UseDeleteWorkflows,
): Promise<IBatchWorkflowActionResponse> => {
return await dominoApiClient.delete(
`/batch/workspaces/${params.workspaceId}/workflows`,
{
data: params.workflowIds,
},
);
};
106 changes: 41 additions & 65 deletions frontend/src/features/myWorkflows/components/WorkflowsList/Actions.tsx
Original file line number Diff line number Diff line change
@@ -1,94 +1,70 @@
import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
import PauseCircleOutlineIcon from "@mui/icons-material/PauseCircleOutline";
import PlayCircleOutlineIcon from "@mui/icons-material/PlayCircleOutline";
import { IconButton, Tooltip, useTheme } from "@mui/material";
import {
DeleteOutlined,
PlayCircleOutlined,
StopCircleOutlined,
} from "@mui/icons-material";
import { Button, Divider } from "@mui/material";
import { type CommonProps } from "@mui/material/OverridableComponent";
import { Modal, type ModalRef } from "components/Modal";
import { GridToolbarContainer } from "@mui/x-data-grid";
import { type IWorkflow } from "features/myWorkflows/types";
import React, { useRef, useState } from "react";
import React, { useState } from "react";

import { ConfirmDeleteModal } from "./ConfirmDeleteModal";

interface Props extends CommonProps {
id: IWorkflow["id"];
deleteFn: () => void;
ids: Array<IWorkflow["id"]>;
runFn: () => void;
pauseFn: () => void;
stopFn: () => void;
deleteFn: () => void;
disabled: boolean;
}

export const Actions: React.FC<Props> = ({
ids,
runFn,
stopFn,
deleteFn,
className,
disabled = false,
disabled,
}) => {
const theme = useTheme();

const [deleteModalOpen, setDeleteModalOpen] = useState(false);
const newFeatureModal = useRef<ModalRef>(null);

return (
<>
{disabled ? (
<Tooltip title="Can't run future workflows." arrow>
<span>
<IconButton
className={className}
onClick={runFn}
disabled={disabled}
>
<PlayCircleOutlineIcon
style={{
pointerEvents: "none",
color: theme.palette.grey[500],
}}
/>
</IconButton>
</span>
</Tooltip>
) : (
<IconButton className={className} onClick={runFn}>
<PlayCircleOutlineIcon
style={{
pointerEvents: "none",
color: theme.palette.success.main,
}}
/>
</IconButton>
)}
<IconButton
className={className}
onClick={() => {
newFeatureModal.current?.open();
}}
<GridToolbarContainer sx={{ borderBottom: 1 }}>
<Button
color="primary"
startIcon={<PlayCircleOutlined />}
onClick={runFn}
disabled={disabled}
>
<PauseCircleOutlineIcon
style={{ pointerEvents: "none", color: theme.palette.info.main }}
/>
</IconButton>
<IconButton
className={className}
Start
</Button>
<Divider orientation="vertical" variant="middle" flexItem />
<Button
color="primary"
startIcon={<StopCircleOutlined />}
onClick={stopFn}
disabled={disabled}
>
Stop
</Button>
<Divider orientation="vertical" variant="middle" flexItem />
<Button
color="error"
startIcon={<DeleteOutlined />}
onClick={() => {
setDeleteModalOpen(true);
}}
disabled={disabled}
>
<DeleteOutlineIcon
style={{ pointerEvents: "none", color: theme.palette.error.main }}
/>
</IconButton>
<Modal
title="New Feature"
content="This feature is not ready yet! We launch new versions every time,
check out our changelog for more information !"
ref={newFeatureModal}
/>
Delete
</Button>
<ConfirmDeleteModal
isOpen={deleteModalOpen}
title="Confirm Workflow Deletion"
content={
<span>
Are you sure you want to delete this workflow? This action{" "}
Are you sure you want to delete selected {ids.length} workflows?
This action{" "}
<span style={{ fontWeight: "bold" }}>cannot be undone</span>.
</span>
}
@@ -101,6 +77,6 @@ export const Actions: React.FC<Props> = ({
}}
confirmText="Delete"
/>
</>
</GridToolbarContainer>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { type IBatchWorkflowActionDetail } from "@features/myWorkflows/types";
import { Dialog, DialogContent, DialogTitle } from "@mui/material";
import { DataGrid, type GridColDef } from "@mui/x-data-grid";
import { useCallback } from "react";

interface Props {
isOpen: boolean;
title: string;
data: IBatchWorkflowActionDetail[];
cancelCb: () => void;
}

const columns: Array<GridColDef<IBatchWorkflowActionDetail>> = [
{ field: "id", headerName: "ID", width: 90 },
{
field: "message",
headerName: "Message",
width: 400,
},
];

export const FailureDetailsModal: React.FC<Props> = ({
isOpen,
title,
data,
cancelCb,
}) => {
const cancel = useCallback(() => {
cancelCb();
}, [cancelCb]);
return (
<Dialog
open={isOpen}
onClose={cancel}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">{title}</DialogTitle>
<DialogContent>
<DataGrid
density="compact"
columns={columns}
rows={data}
disableDensitySelector
disableRowSelectionOnClick
hideFooterSelectedRowCount
disableColumnMenu
disableColumnSelector
/>
</DialogContent>
</Dialog>
);
};
Loading