mirror of
https://github.com/hexastack/hexabot
synced 2025-06-26 18:27:28 +00:00
fix(frontend): introduce state mode feature
This commit is contained in:
@@ -43,8 +43,9 @@
|
||||
"account_update_success": "Account has been updated successfully",
|
||||
"account_disabled": "Your account has been either disabled or is pending confirmation.",
|
||||
"success_invitation_sent": "Invitation to join has been successfully sent.",
|
||||
"item_delete_confirm": "Are you sure you want to delete this item?",
|
||||
"item_delete_confirm": "Are you sure you want to delete this {{0}} item?",
|
||||
"items_delete_confirm": "Are you sure you want to delete those {{0}} selected items?",
|
||||
"selected": "selected",
|
||||
"item_delete_success": "Item has been deleted successfully",
|
||||
"success_save": "Changes has been saved!",
|
||||
"no_result_found": "No result found",
|
||||
|
||||
@@ -43,8 +43,9 @@
|
||||
"account_update_success": "Le compte a été mis à jour avec succès",
|
||||
"account_disabled": "Votre compte a été désactivé ou est en attente de confirmation.",
|
||||
"success_invitation_sent": "L'invitation a été envoyée avec succès.",
|
||||
"item_delete_confirm": "Êtes-vous sûr de bien vouloir supprimer cet élément?",
|
||||
"item_delete_confirm": "Êtes-vous sûr de bien vouloir supprimer cet élément {{0}}?",
|
||||
"items_delete_confirm": "Êtes-vous sûr de bien vouloir supprimer ces {{0}} éléments sélectionnés?",
|
||||
"selected": "sélectionné",
|
||||
"item_delete_success": "L'élément a été supprimé avec succès",
|
||||
"success_save": "Les modifications ont été enregistrées!",
|
||||
"no_result_found": "Aucun résultat trouvé",
|
||||
|
||||
@@ -26,40 +26,30 @@ import { IEntityMapTypes } from "@/types/base.types";
|
||||
|
||||
export type DeleteDialogProps<T extends string = string> = DialogControl<T>;
|
||||
export const DeleteDialog = <T extends string = string>({
|
||||
open,
|
||||
closeDialog: closeFunction,
|
||||
datum,
|
||||
data: ids,
|
||||
callback,
|
||||
entity = EntityType.ATTACHMENT,
|
||||
setData,
|
||||
onDeleteError = () => {},
|
||||
onDeleteSuccess = () => {},
|
||||
...rest
|
||||
}: DeleteDialogProps<T> & {
|
||||
entity?: keyof IEntityMapTypes;
|
||||
onDeleteError?: (error: Error) => void;
|
||||
onDeleteSuccess?: (data?: unknown) => void;
|
||||
}) => {
|
||||
const { t } = useTranslate();
|
||||
const getItemsFromData = (data: unknown) => (Array.isArray(data) ? data : []);
|
||||
const hasMultipleItems = (data: unknown): boolean =>
|
||||
getItemsFromData(data).length > 1;
|
||||
const onSuccess = (data: unknown) => {
|
||||
setData?.(undefined);
|
||||
onDeleteSuccess(data);
|
||||
const options = {
|
||||
onError: onDeleteError,
|
||||
onSuccess: (data: unknown) => {
|
||||
rest.setData?.(undefined);
|
||||
onDeleteSuccess(data);
|
||||
},
|
||||
};
|
||||
const { mutateAsync: deleteOne } = useDelete(entity, {
|
||||
onError: onDeleteError,
|
||||
onSuccess,
|
||||
});
|
||||
const { mutateAsync: deleteMany } = useDeleteMany(entity, {
|
||||
onError: onDeleteError,
|
||||
onSuccess,
|
||||
});
|
||||
const { mutateAsync: deleteOne } = useDelete(entity, options);
|
||||
const { mutateAsync: deleteMany } = useDeleteMany(entity, options);
|
||||
|
||||
return (
|
||||
<Dialog open={open} fullWidth onClose={closeFunction}>
|
||||
<DialogTitle onClose={closeFunction}>{t("title.warning")}</DialogTitle>
|
||||
<Dialog open={rest.open} fullWidth onClose={rest.closeDialog}>
|
||||
<DialogTitle onClose={rest.closeDialog}>{t("title.warning")}</DialogTitle>
|
||||
<DialogContent>
|
||||
<Grid container gap={1}>
|
||||
<Grid item height="28px">
|
||||
@@ -68,12 +58,15 @@ export const DeleteDialog = <T extends string = string>({
|
||||
<Grid item alignSelf="center">
|
||||
<Typography>
|
||||
{t(
|
||||
`${
|
||||
hasMultipleItems(ids)
|
||||
? "message.items_delete_confirm"
|
||||
: "message.item_delete_confirm"
|
||||
}`,
|
||||
{ "0": getItemsFromData(ids).length.toString() },
|
||||
`message.item${
|
||||
(ids?.length || 0) > 1 ? "s" : ""
|
||||
}_delete_confirm`,
|
||||
{
|
||||
"0":
|
||||
ids?.length === 1
|
||||
? t("message.selected")
|
||||
: ids?.length.toString(),
|
||||
},
|
||||
)}
|
||||
</Typography>
|
||||
</Grid>
|
||||
@@ -84,19 +77,19 @@ export const DeleteDialog = <T extends string = string>({
|
||||
color="error"
|
||||
variant="contained"
|
||||
onClick={async () => {
|
||||
if (callback) {
|
||||
callback(ids);
|
||||
if (rest.callback) {
|
||||
rest.callback(ids);
|
||||
} else if (Array.isArray(ids)) {
|
||||
await deleteMany(ids);
|
||||
} else if (datum) {
|
||||
await deleteOne(datum);
|
||||
} else if (rest.datum) {
|
||||
await deleteOne(rest.datum);
|
||||
}
|
||||
}}
|
||||
autoFocus
|
||||
>
|
||||
{t("button.yes")}
|
||||
</Button>
|
||||
<Button variant="outlined" onClick={closeFunction}>
|
||||
<Button variant="outlined" onClick={rest.closeDialog}>
|
||||
{t("button.no")}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
|
||||
@@ -15,55 +15,51 @@ import {
|
||||
MenuItem,
|
||||
Select,
|
||||
} from "@mui/material";
|
||||
import { FC, useState } from "react";
|
||||
|
||||
import { DialogTitle } from "@/app-components/dialogs/DialogTitle";
|
||||
import { DialogControl } from "@/hooks/useDialog";
|
||||
import { useTranslate } from "@/hooks/useTranslate";
|
||||
import { ICategory } from "@/types/category.types";
|
||||
|
||||
export interface MoveDialogProps
|
||||
extends Omit<DialogControl<string>, "callback"> {
|
||||
export interface MoveDialogProps<T = never>
|
||||
extends Omit<DialogControl<T>, "callback"> {
|
||||
categories: ICategory[];
|
||||
callback?: (newCategoryId?: string) => Promise<void>;
|
||||
openDialog: (data?: string) => void;
|
||||
callback?: (selectedCategoryId?: T, ids?: T[]) => Promise<void>;
|
||||
}
|
||||
|
||||
export const MoveDialog: FC<MoveDialogProps> = ({
|
||||
open,
|
||||
callback,
|
||||
closeDialog,
|
||||
categories,
|
||||
}: MoveDialogProps) => {
|
||||
export const MoveDialog = <T,>({
|
||||
data: ids,
|
||||
datum: selectedCategoryId,
|
||||
...rest
|
||||
}: MoveDialogProps<T>) => {
|
||||
const { t } = useTranslate();
|
||||
const [selectedCategoryId, setSelectedCategoryId] = useState<string>("");
|
||||
const handleMove = async () => {
|
||||
if (selectedCategoryId && callback) {
|
||||
await callback(selectedCategoryId);
|
||||
closeDialog();
|
||||
if (selectedCategoryId && rest.callback) {
|
||||
await rest.callback(selectedCategoryId, ids);
|
||||
rest.closeDialog();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} fullWidth onClose={closeDialog}>
|
||||
<DialogTitle onClose={closeDialog}>
|
||||
<Dialog open={rest.open} fullWidth onClose={rest.closeDialog}>
|
||||
<DialogTitle onClose={rest.closeDialog}>
|
||||
{t("message.select_category")}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<Grid container direction="column" gap={2}>
|
||||
<Grid item>
|
||||
<Select
|
||||
value={selectedCategoryId}
|
||||
onChange={(e) => setSelectedCategoryId(e.target.value as string)}
|
||||
value={selectedCategoryId || ""}
|
||||
onChange={(e) => rest.setDatum?.(e.target.value as T)}
|
||||
fullWidth
|
||||
displayEmpty
|
||||
>
|
||||
<MenuItem value="" disabled>
|
||||
{t("label.category")}
|
||||
</MenuItem>
|
||||
{categories.map((category) => (
|
||||
<MenuItem key={category.id} value={category.id}>
|
||||
{category.label}
|
||||
{rest.categories.map(({ id, label }) => (
|
||||
<MenuItem key={id} value={id}>
|
||||
{label}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
@@ -78,7 +74,7 @@ export const MoveDialog: FC<MoveDialogProps> = ({
|
||||
>
|
||||
{t("button.move")}
|
||||
</Button>
|
||||
<Button variant="outlined" onClick={closeDialog}>
|
||||
<Button variant="outlined" onClick={rest.closeDialog}>
|
||||
{t("button.cancel")}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
|
||||
@@ -75,7 +75,7 @@ const Diagrams = () => {
|
||||
const [canvas, setCanvas] = useState<JSX.Element | undefined>();
|
||||
const [selectedBlockId, setSelectedBlockId] = useState<string | undefined>();
|
||||
const deleteDialogCtl = useDialog<string>(false);
|
||||
const moveDialogCtl = useDialog<string>(false);
|
||||
const moveDialogCtl = useDialog<string>(false, "datumAndData");
|
||||
const addCategoryDialogCtl = useDialog<ICategory>(false);
|
||||
const { mutateAsync: updateBlocks } = useUpdateMany(EntityType.BLOCK);
|
||||
const {
|
||||
@@ -203,8 +203,7 @@ const Diagrams = () => {
|
||||
setter: setSelectedBlockId,
|
||||
updateFn: updateBlock,
|
||||
onRemoveNode: (ids, next) => {
|
||||
deleteDialogCtl.setData?.(ids);
|
||||
deleteDialogCtl.openDialog();
|
||||
deleteDialogCtl.openDialog(ids);
|
||||
deleteCallbackRef.current = next;
|
||||
},
|
||||
onDbClickNode: (event, id) => {
|
||||
@@ -446,8 +445,7 @@ const Diagrams = () => {
|
||||
});
|
||||
engine?.repaintCanvas();
|
||||
};
|
||||
deleteDialogCtl.setData?.(ids);
|
||||
deleteDialogCtl.openDialog();
|
||||
deleteDialogCtl.openDialog(ids);
|
||||
}
|
||||
};
|
||||
const handleMoveButton = () => {
|
||||
@@ -455,8 +453,7 @@ const Diagrams = () => {
|
||||
const ids = selectedEntities?.map((model) => model.getID());
|
||||
|
||||
if (ids && selectedEntities) {
|
||||
moveDialogCtl.setData?.(ids);
|
||||
moveDialogCtl.openDialog();
|
||||
moveDialogCtl.openDialog(ids);
|
||||
}
|
||||
};
|
||||
const onDelete = async (ids: string[]) => {
|
||||
@@ -473,14 +470,12 @@ const Diagrams = () => {
|
||||
|
||||
cleanupAfterDeletion();
|
||||
};
|
||||
const onMove = async (newCategoryId?: string) => {
|
||||
const onMove = async (newCategoryId?: string, ids?: string[]) => {
|
||||
if (!newCategoryId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ids = moveDialogCtl?.data;
|
||||
|
||||
if (ids?.length && Array.isArray(ids)) {
|
||||
if (Array.isArray(ids) && ids?.length) {
|
||||
await updateBlocks({ ids, payload: { category: newCategoryId } });
|
||||
|
||||
queryClient.invalidateQueries({
|
||||
|
||||
@@ -15,24 +15,33 @@ type TCloseDialog = <E extends React.MouseEvent | Event | Object>(
|
||||
reason?: "backdropClick" | "escapeKeyDown",
|
||||
) => void;
|
||||
type TFnVoid<T> = (data?: T) => void;
|
||||
|
||||
type TStatesMode = "datumOrData" | "datumAndData";
|
||||
export type DialogControl<T = never> = DialogProps & {
|
||||
data?: T[];
|
||||
datum?: T;
|
||||
setData?: TFnVoid<T[]>;
|
||||
setDatum?: TFnVoid<T>;
|
||||
callback?: (data?: T | T[]) => Promise<void>;
|
||||
openDialog: TFnVoid<T>;
|
||||
openDialog: TFnVoid<T | T[]>;
|
||||
closeDialog: TCloseDialog;
|
||||
};
|
||||
|
||||
export const useDialog = <T,>(initialState: boolean): DialogControl<T> => {
|
||||
export const useDialog = <T,>(
|
||||
initialState: boolean,
|
||||
statesMode: TStatesMode = "datumOrData",
|
||||
): DialogControl<T> => {
|
||||
const [open, setOpen] = useState(initialState);
|
||||
const [data, setData] = useState<T[] | undefined>(undefined);
|
||||
const [datum, setDatum] = useState<T | undefined>(undefined);
|
||||
const openDialog: TFnVoid<T> = (datum) => {
|
||||
setDatum(datum);
|
||||
if (datum) {
|
||||
setData(undefined);
|
||||
const [data, setData] = useState<T[] | undefined>();
|
||||
const [datum, setDatum] = useState<T | undefined>();
|
||||
const openDialog: TFnVoid<T | T[]> = (value) => {
|
||||
if (statesMode === "datumOrData") {
|
||||
if (value) {
|
||||
setData(Array.isArray(value) ? value : undefined);
|
||||
setDatum(Array.isArray(value) ? undefined : value);
|
||||
}
|
||||
} else if (statesMode === "datumAndData") {
|
||||
setData(Array.isArray(value) ? value : data);
|
||||
setDatum(Array.isArray(value) ? datum : value);
|
||||
}
|
||||
setOpen(true);
|
||||
};
|
||||
@@ -47,6 +56,7 @@ export const useDialog = <T,>(initialState: boolean): DialogControl<T> => {
|
||||
data,
|
||||
datum,
|
||||
setData,
|
||||
setDatum,
|
||||
openDialog,
|
||||
closeDialog,
|
||||
};
|
||||
@@ -54,6 +64,6 @@ export const useDialog = <T,>(initialState: boolean): DialogControl<T> => {
|
||||
|
||||
export const getDisplayDialogs = <T,>({
|
||||
open,
|
||||
closeDialog,
|
||||
datum,
|
||||
closeDialog,
|
||||
}: DialogControl<T>): DialogControlProps<T> => ({ open, datum, closeDialog });
|
||||
|
||||
Reference in New Issue
Block a user