forked from github/plane
[WEB-570] chore: toast refactor (#3836)
* new toast setup * chore: new toast implementation. * chore: move toast component to ui package. * chore: replace `setToast` with `setPromiseToast` in required places for better UX. * chore: code cleanup. * chore: update theme. * fix: theme switching issue. * chore: remove toast from issue update operations. * chore: add promise toast for add/ remove issue to cycle/ module and remove local spinners. --------- Co-authored-by: rahulramesha <rahulramesham@gmail.com>
This commit is contained in:
parent
c06ef4d1d7
commit
53367a6bc4
@ -198,6 +198,31 @@ module.exports = {
|
|||||||
300: convertToRGB("--color-onboarding-border-300"),
|
300: convertToRGB("--color-onboarding-border-300"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
toast: {
|
||||||
|
text: {
|
||||||
|
success: convertToRGB("--color-toast-success-text"),
|
||||||
|
error: convertToRGB("--color-toast-error-text"),
|
||||||
|
warning: convertToRGB("--color-toast-warning-text"),
|
||||||
|
info: convertToRGB("--color-toast-info-text"),
|
||||||
|
loading: convertToRGB("--color-toast-loading-text"),
|
||||||
|
secondary: convertToRGB("--color-toast-secondary-text"),
|
||||||
|
tertiary: convertToRGB("--color-toast-tertiary-text"),
|
||||||
|
},
|
||||||
|
background: {
|
||||||
|
success: convertToRGB("--color-toast-success-background"),
|
||||||
|
error: convertToRGB("--color-toast-error-background"),
|
||||||
|
warning: convertToRGB("--color-toast-warning-background"),
|
||||||
|
info: convertToRGB("--color-toast-info-background"),
|
||||||
|
loading: convertToRGB("--color-toast-loading-background"),
|
||||||
|
},
|
||||||
|
border: {
|
||||||
|
success: convertToRGB("--color-toast-success-border"),
|
||||||
|
error: convertToRGB("--color-toast-error-border"),
|
||||||
|
warning: convertToRGB("--color-toast-warning-border"),
|
||||||
|
info: convertToRGB("--color-toast-info-border"),
|
||||||
|
loading: convertToRGB("--color-toast-loading-border"),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
keyframes: {
|
keyframes: {
|
||||||
leftToaster: {
|
leftToaster: {
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
"react-color": "^2.19.3",
|
"react-color": "^2.19.3",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-popper": "^2.3.0",
|
"react-popper": "^2.3.0",
|
||||||
|
"sonner": "^1.4.2",
|
||||||
"tailwind-merge": "^2.0.0"
|
"tailwind-merge": "^2.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -10,3 +10,4 @@ export * from "./spinners";
|
|||||||
export * from "./tooltip";
|
export * from "./tooltip";
|
||||||
export * from "./loader";
|
export * from "./loader";
|
||||||
export * from "./control-link";
|
export * from "./control-link";
|
||||||
|
export * from "./toast";
|
||||||
|
35
packages/ui/src/spinners/circular-bar-spinner.tsx
Normal file
35
packages/ui/src/spinners/circular-bar-spinner.tsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
|
||||||
|
interface ICircularBarSpinner extends React.SVGAttributes<SVGElement> {
|
||||||
|
height?: string;
|
||||||
|
width?: string;
|
||||||
|
className?: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CircularBarSpinner: React.FC<ICircularBarSpinner> = ({
|
||||||
|
height = "16px",
|
||||||
|
width = "16px",
|
||||||
|
className = "",
|
||||||
|
}) => (
|
||||||
|
<div role="status">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width={width} height={height} viewBox="0 0 24 24" className={className}>
|
||||||
|
<g>
|
||||||
|
<rect width={2} height={5} x={11} y={1} fill="currentColor" opacity={0.14} />
|
||||||
|
<rect width={2} height={5} x={11} y={1} fill="currentColor" opacity={0.29} transform="rotate(30 12 12)" />
|
||||||
|
<rect width={2} height={5} x={11} y={1} fill="currentColor" opacity={0.43} transform="rotate(60 12 12)" />
|
||||||
|
<rect width={2} height={5} x={11} y={1} fill="currentColor" opacity={0.57} transform="rotate(90 12 12)" />
|
||||||
|
<rect width={2} height={5} x={11} y={1} fill="currentColor" opacity={0.71} transform="rotate(120 12 12)" />
|
||||||
|
<rect width={2} height={5} x={11} y={1} fill="currentColor" opacity={0.86} transform="rotate(150 12 12)" />
|
||||||
|
<rect width={2} height={5} x={11} y={1} fill="currentColor" transform="rotate(180 12 12)" />
|
||||||
|
<animateTransform
|
||||||
|
attributeName="transform"
|
||||||
|
calcMode="discrete"
|
||||||
|
dur="0.75s"
|
||||||
|
repeatCount="indefinite"
|
||||||
|
type="rotate"
|
||||||
|
values="0 12 12;30 12 12;60 12 12;90 12 12;120 12 12;150 12 12;180 12 12;210 12 12;240 12 12;270 12 12;300 12 12;330 12 12;360 12 12"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
);
|
@ -1 +1,2 @@
|
|||||||
export * from "./circular-spinner";
|
export * from "./circular-spinner";
|
||||||
|
export * from "./circular-bar-spinner";
|
||||||
|
206
packages/ui/src/toast/index.tsx
Normal file
206
packages/ui/src/toast/index.tsx
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
import * as React from "react";
|
||||||
|
import { Toaster, toast } from "sonner";
|
||||||
|
// icons
|
||||||
|
import { AlertTriangle, CheckCircle2, X, XCircle } from "lucide-react";
|
||||||
|
// spinner
|
||||||
|
import { CircularBarSpinner } from "../spinners";
|
||||||
|
// helper
|
||||||
|
import { cn } from "../../helpers";
|
||||||
|
|
||||||
|
export enum TOAST_TYPE {
|
||||||
|
SUCCESS = "success",
|
||||||
|
ERROR = "error",
|
||||||
|
INFO = "info",
|
||||||
|
WARNING = "warning",
|
||||||
|
LOADING = "loading",
|
||||||
|
}
|
||||||
|
|
||||||
|
type SetToastProps =
|
||||||
|
| {
|
||||||
|
type: TOAST_TYPE.LOADING;
|
||||||
|
title?: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
id?: string | number;
|
||||||
|
type: Exclude<TOAST_TYPE, TOAST_TYPE.LOADING>;
|
||||||
|
title: string;
|
||||||
|
message?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type PromiseToastCallback<ToastData> = (data: ToastData) => string;
|
||||||
|
|
||||||
|
type PromiseToastData<ToastData> = {
|
||||||
|
title: string;
|
||||||
|
message?: PromiseToastCallback<ToastData>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type PromiseToastOptions<ToastData> = {
|
||||||
|
loading?: string;
|
||||||
|
success: PromiseToastData<ToastData>;
|
||||||
|
error: PromiseToastData<ToastData>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ToastContentProps = {
|
||||||
|
toastId: string | number;
|
||||||
|
icon?: React.ReactNode;
|
||||||
|
textColorClassName: string;
|
||||||
|
backgroundColorClassName: string;
|
||||||
|
borderColorClassName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ToastProps = {
|
||||||
|
theme: "light" | "dark" | "system";
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Toast = (props: ToastProps) => {
|
||||||
|
const { theme } = props;
|
||||||
|
return <Toaster visibleToasts={5} gap={20} theme={theme} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setToast = (props: SetToastProps) => {
|
||||||
|
const renderToastContent = ({
|
||||||
|
toastId,
|
||||||
|
icon,
|
||||||
|
textColorClassName,
|
||||||
|
backgroundColorClassName,
|
||||||
|
borderColorClassName,
|
||||||
|
}: ToastContentProps) =>
|
||||||
|
props.type === TOAST_TYPE.LOADING ? (
|
||||||
|
<div
|
||||||
|
onMouseDown={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
}}
|
||||||
|
className={cn("w-[350px] h-[67.3px] rounded-lg border shadow-sm p-2", backgroundColorClassName, borderColorClassName)}
|
||||||
|
>
|
||||||
|
<div className="w-full h-full flex items-center justify-center px-4 py-2">
|
||||||
|
{icon && <div className="flex items-center justify-center">{icon}</div>}
|
||||||
|
<div className={cn("w-full flex items-center gap-0.5 pr-1", icon ? "pl-4" : "pl-1")}>
|
||||||
|
<div className={cn("grow text-sm font-semibold", textColorClassName)}>{props.title ?? "Loading..."}</div>
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<X
|
||||||
|
className="text-toast-text-secondary hover:text-toast-text-tertiary cursor-pointer"
|
||||||
|
strokeWidth={1.5}
|
||||||
|
width={14}
|
||||||
|
height={14}
|
||||||
|
onClick={() => toast.dismiss(toastId)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
onMouseDown={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
}}
|
||||||
|
className={cn(
|
||||||
|
"relative flex flex-col w-[350px] rounded-lg border shadow-sm p-2",
|
||||||
|
backgroundColorClassName,
|
||||||
|
borderColorClassName
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<X
|
||||||
|
className="fixed top-2 right-2.5 text-toast-text-secondary hover:text-toast-text-tertiary cursor-pointer"
|
||||||
|
strokeWidth={1.5}
|
||||||
|
width={14}
|
||||||
|
height={14}
|
||||||
|
onClick={() => toast.dismiss(toastId)}
|
||||||
|
/>
|
||||||
|
<div className="w-full flex items-center px-4 py-2">
|
||||||
|
{icon && <div className="flex items-center justify-center">{icon}</div>}
|
||||||
|
<div className={cn("flex flex-col gap-0.5 pr-1", icon ? "pl-6" : "pl-1")}>
|
||||||
|
<div className={cn("text-sm font-semibold", textColorClassName)}>{props.title}</div>
|
||||||
|
{props.message && <div className="text-toast-text-secondary text-xs font-medium">{props.message}</div>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
switch (props.type) {
|
||||||
|
case TOAST_TYPE.SUCCESS:
|
||||||
|
return toast.custom(
|
||||||
|
(toastId) =>
|
||||||
|
renderToastContent({
|
||||||
|
toastId,
|
||||||
|
icon: <CheckCircle2 width={28} height={28} strokeWidth={1.5} className="text-toast-text-success" />,
|
||||||
|
textColorClassName: "text-toast-text-success",
|
||||||
|
backgroundColorClassName: "bg-toast-background-success",
|
||||||
|
borderColorClassName: "border-toast-border-success",
|
||||||
|
}),
|
||||||
|
props.id ? { id: props.id } : {}
|
||||||
|
);
|
||||||
|
case TOAST_TYPE.ERROR:
|
||||||
|
return toast.custom(
|
||||||
|
(toastId) =>
|
||||||
|
renderToastContent({
|
||||||
|
toastId,
|
||||||
|
icon: <XCircle width={28} height={28} strokeWidth={1.5} className="text-toast-text-error" />,
|
||||||
|
textColorClassName: "text-toast-text-error",
|
||||||
|
backgroundColorClassName: "bg-toast-background-error",
|
||||||
|
borderColorClassName: "border-toast-border-error",
|
||||||
|
}),
|
||||||
|
props.id ? { id: props.id } : {}
|
||||||
|
);
|
||||||
|
case TOAST_TYPE.WARNING:
|
||||||
|
return toast.custom(
|
||||||
|
(toastId) =>
|
||||||
|
renderToastContent({
|
||||||
|
toastId,
|
||||||
|
icon: <AlertTriangle width={28} height={28} strokeWidth={1.5} className="text-toast-text-warning" />,
|
||||||
|
textColorClassName: "text-toast-text-warning",
|
||||||
|
backgroundColorClassName: "bg-toast-background-warning",
|
||||||
|
borderColorClassName: "border-toast-border-warning",
|
||||||
|
}),
|
||||||
|
props.id ? { id: props.id } : {}
|
||||||
|
);
|
||||||
|
case TOAST_TYPE.INFO:
|
||||||
|
return toast.custom(
|
||||||
|
(toastId) =>
|
||||||
|
renderToastContent({
|
||||||
|
toastId,
|
||||||
|
textColorClassName: "text-toast-text-info",
|
||||||
|
backgroundColorClassName: "bg-toast-background-info",
|
||||||
|
borderColorClassName: "border-toast-border-info",
|
||||||
|
}),
|
||||||
|
props.id ? { id: props.id } : {}
|
||||||
|
);
|
||||||
|
|
||||||
|
case TOAST_TYPE.LOADING:
|
||||||
|
return toast.custom((toastId) =>
|
||||||
|
renderToastContent({
|
||||||
|
toastId,
|
||||||
|
icon: <CircularBarSpinner className="text-toast-text-tertiary" />,
|
||||||
|
textColorClassName: "text-toast-text-loading",
|
||||||
|
backgroundColorClassName: "bg-toast-background-loading",
|
||||||
|
borderColorClassName: "border-toast-border-loading",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setPromiseToast = <ToastData,>(
|
||||||
|
promise: Promise<ToastData>,
|
||||||
|
options: PromiseToastOptions<ToastData>
|
||||||
|
): void => {
|
||||||
|
const tId = setToast({ type: TOAST_TYPE.LOADING, title: options.loading });
|
||||||
|
|
||||||
|
promise
|
||||||
|
.then((data: ToastData) => {
|
||||||
|
setToast({
|
||||||
|
type: TOAST_TYPE.SUCCESS,
|
||||||
|
id: tId,
|
||||||
|
title: options.success.title,
|
||||||
|
message: options.success.message?.(data),
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((data: ToastData) => {
|
||||||
|
setToast({
|
||||||
|
type: TOAST_TYPE.ERROR,
|
||||||
|
id: tId,
|
||||||
|
title: options.error.title,
|
||||||
|
message: options.error.message?.(data),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
@ -7,9 +7,7 @@ import { mutate } from "swr";
|
|||||||
// hooks
|
// hooks
|
||||||
import { useUser } from "hooks/store";
|
import { useUser } from "hooks/store";
|
||||||
// ui
|
// ui
|
||||||
import { Button } from "@plane/ui";
|
import { Button, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@ -26,7 +24,6 @@ export const DeactivateAccountModal: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
const { setTheme } = useTheme();
|
const { setTheme } = useTheme();
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
@ -39,8 +36,8 @@ export const DeactivateAccountModal: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
await deactivateAccount()
|
await deactivateAccount()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Account deactivated successfully.",
|
message: "Account deactivated successfully.",
|
||||||
});
|
});
|
||||||
@ -50,8 +47,8 @@ export const DeactivateAccountModal: React.FC<Props> = (props) => {
|
|||||||
handleClose();
|
handleClose();
|
||||||
})
|
})
|
||||||
.catch((err) =>
|
.catch((err) =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err?.error,
|
message: err?.error,
|
||||||
})
|
})
|
||||||
@ -90,7 +87,10 @@ export const DeactivateAccountModal: React.FC<Props> = (props) => {
|
|||||||
<div className="">
|
<div className="">
|
||||||
<div className="flex items-start gap-x-4">
|
<div className="flex items-start gap-x-4">
|
||||||
<div className="grid place-items-center rounded-full bg-red-500/20 p-2 sm:p-2 md:p-4 lg:p-4 mt-3 sm:mt-3 md:mt-0 lg:mt-0 ">
|
<div className="grid place-items-center rounded-full bg-red-500/20 p-2 sm:p-2 md:p-4 lg:p-4 mt-3 sm:mt-3 md:mt-0 lg:mt-0 ">
|
||||||
<Trash2 className="h-4 w-4 sm:h-4 sm:w-4 md:h-6 md:w-6 lg:h-6 lg:w-6 text-red-600" aria-hidden="true" />
|
<Trash2
|
||||||
|
className="h-4 w-4 sm:h-4 sm:w-4 md:h-6 md:w-6 lg:h-6 lg:w-6 text-red-600"
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Dialog.Title as="h3" className="my-4 text-2xl font-medium leading-6 text-custom-text-100">
|
<Dialog.Title as="h3" className="my-4 text-2xl font-medium leading-6 text-custom-text-100">
|
||||||
|
@ -3,7 +3,8 @@ import { observer } from "mobx-react-lite";
|
|||||||
import { AuthService } from "services/auth.service";
|
import { AuthService } from "services/auth.service";
|
||||||
// hooks
|
// hooks
|
||||||
import { useApplication } from "hooks/store";
|
import { useApplication } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
// ui
|
||||||
|
import { TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { GitHubSignInButton, GoogleSignInButton } from "components/account";
|
import { GitHubSignInButton, GoogleSignInButton } from "components/account";
|
||||||
|
|
||||||
@ -17,8 +18,6 @@ const authService = new AuthService();
|
|||||||
|
|
||||||
export const OAuthOptions: React.FC<Props> = observer((props) => {
|
export const OAuthOptions: React.FC<Props> = observer((props) => {
|
||||||
const { handleSignInRedirection, type } = props;
|
const { handleSignInRedirection, type } = props;
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// mobx store
|
// mobx store
|
||||||
const {
|
const {
|
||||||
config: { envConfig },
|
config: { envConfig },
|
||||||
@ -39,9 +38,9 @@ export const OAuthOptions: React.FC<Props> = observer((props) => {
|
|||||||
if (response) handleSignInRedirection();
|
if (response) handleSignInRedirection();
|
||||||
} else throw Error("Cant find credentials");
|
} else throw Error("Cant find credentials");
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error signing in!",
|
title: "Error signing in!",
|
||||||
type: "error",
|
|
||||||
message: err?.error || "Something went wrong. Please try again later or contact the support team.",
|
message: err?.error || "Something went wrong. Please try again later or contact the support team.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -60,9 +59,9 @@ export const OAuthOptions: React.FC<Props> = observer((props) => {
|
|||||||
if (response) handleSignInRedirection();
|
if (response) handleSignInRedirection();
|
||||||
} else throw Error("Cant find credentials");
|
} else throw Error("Cant find credentials");
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error signing in!",
|
title: "Error signing in!",
|
||||||
type: "error",
|
|
||||||
message: err?.error || "Something went wrong. Please try again later or contact the support team.",
|
message: err?.error || "Something went wrong. Please try again later or contact the support team.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,8 @@ import { XCircle } from "lucide-react";
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// services
|
// services
|
||||||
import { AuthService } from "services/auth.service";
|
import { AuthService } from "services/auth.service";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { checkEmailValidity } from "helpers/string.helper";
|
import { checkEmailValidity } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
@ -27,7 +25,6 @@ const authService = new AuthService();
|
|||||||
export const SignInEmailForm: React.FC<Props> = observer((props) => {
|
export const SignInEmailForm: React.FC<Props> = observer((props) => {
|
||||||
const { onSubmit, updateEmail } = props;
|
const { onSubmit, updateEmail } = props;
|
||||||
// hooks
|
// hooks
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
formState: { errors, isSubmitting, isValid },
|
formState: { errors, isSubmitting, isValid },
|
||||||
@ -52,8 +49,8 @@ export const SignInEmailForm: React.FC<Props> = observer((props) => {
|
|||||||
.emailCheck(payload)
|
.emailCheck(payload)
|
||||||
.then((res) => onSubmit(res.is_password_autoset))
|
.then((res) => onSubmit(res.is_password_autoset))
|
||||||
.catch((err) =>
|
.catch((err) =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err?.error ?? "Something went wrong. Please try again.",
|
message: err?.error ?? "Something went wrong. Please try again.",
|
||||||
})
|
})
|
||||||
|
@ -3,10 +3,9 @@ import { Controller, useForm } from "react-hook-form";
|
|||||||
// services
|
// services
|
||||||
import { AuthService } from "services/auth.service";
|
import { AuthService } from "services/auth.service";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import { useEventTracker } from "hooks/store";
|
import { useEventTracker } from "hooks/store";
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { checkEmailValidity } from "helpers/string.helper";
|
import { checkEmailValidity } from "helpers/string.helper";
|
||||||
// icons
|
// icons
|
||||||
@ -38,8 +37,6 @@ export const SignInOptionalSetPasswordForm: React.FC<Props> = (props) => {
|
|||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
// store hooks
|
// store hooks
|
||||||
const { captureEvent } = useEventTracker();
|
const { captureEvent } = useEventTracker();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// form info
|
// form info
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
@ -62,8 +59,8 @@ export const SignInOptionalSetPasswordForm: React.FC<Props> = (props) => {
|
|||||||
await authService
|
await authService
|
||||||
.setPassword(payload)
|
.setPassword(payload)
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Password created successfully.",
|
message: "Password created successfully.",
|
||||||
});
|
});
|
||||||
@ -78,8 +75,8 @@ export const SignInOptionalSetPasswordForm: React.FC<Props> = (props) => {
|
|||||||
state: "FAILED",
|
state: "FAILED",
|
||||||
first_time: false,
|
first_time: false,
|
||||||
});
|
});
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err?.error ?? "Something went wrong. Please try again.",
|
message: err?.error ?? "Something went wrong. Please try again.",
|
||||||
});
|
});
|
||||||
|
@ -6,12 +6,11 @@ import { Eye, EyeOff, XCircle } from "lucide-react";
|
|||||||
// services
|
// services
|
||||||
import { AuthService } from "services/auth.service";
|
import { AuthService } from "services/auth.service";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import { useApplication, useEventTracker } from "hooks/store";
|
import { useApplication, useEventTracker } from "hooks/store";
|
||||||
// components
|
// components
|
||||||
import { ESignInSteps, ForgotPasswordPopover } from "components/account";
|
import { ESignInSteps, ForgotPasswordPopover } from "components/account";
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { checkEmailValidity } from "helpers/string.helper";
|
import { checkEmailValidity } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
@ -43,8 +42,6 @@ export const SignInPasswordForm: React.FC<Props> = observer((props) => {
|
|||||||
// states
|
// states
|
||||||
const [isSendingUniqueCode, setIsSendingUniqueCode] = useState(false);
|
const [isSendingUniqueCode, setIsSendingUniqueCode] = useState(false);
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
const {
|
const {
|
||||||
config: { envConfig },
|
config: { envConfig },
|
||||||
} = useApplication();
|
} = useApplication();
|
||||||
@ -83,8 +80,8 @@ export const SignInPasswordForm: React.FC<Props> = observer((props) => {
|
|||||||
await onSubmit();
|
await onSubmit();
|
||||||
})
|
})
|
||||||
.catch((err) =>
|
.catch((err) =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err?.error ?? "Something went wrong. Please try again.",
|
message: err?.error ?? "Something went wrong. Please try again.",
|
||||||
})
|
})
|
||||||
@ -107,8 +104,8 @@ export const SignInPasswordForm: React.FC<Props> = observer((props) => {
|
|||||||
.generateUniqueCode({ email: emailFormValue })
|
.generateUniqueCode({ email: emailFormValue })
|
||||||
.then(() => handleStepChange(ESignInSteps.USE_UNIQUE_CODE_FROM_PASSWORD))
|
.then(() => handleStepChange(ESignInSteps.USE_UNIQUE_CODE_FROM_PASSWORD))
|
||||||
.catch((err) =>
|
.catch((err) =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err?.error ?? "Something went wrong. Please try again.",
|
message: err?.error ?? "Something went wrong. Please try again.",
|
||||||
})
|
})
|
||||||
|
@ -5,11 +5,10 @@ import { XCircle } from "lucide-react";
|
|||||||
import { AuthService } from "services/auth.service";
|
import { AuthService } from "services/auth.service";
|
||||||
import { UserService } from "services/user.service";
|
import { UserService } from "services/user.service";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import useTimer from "hooks/use-timer";
|
import useTimer from "hooks/use-timer";
|
||||||
import { useEventTracker } from "hooks/store";
|
import { useEventTracker } from "hooks/store";
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { checkEmailValidity } from "helpers/string.helper";
|
import { checkEmailValidity } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
@ -42,8 +41,6 @@ export const SignInUniqueCodeForm: React.FC<Props> = (props) => {
|
|||||||
const { email, onSubmit, handleEmailClear, submitButtonText } = props;
|
const { email, onSubmit, handleEmailClear, submitButtonText } = props;
|
||||||
// states
|
// states
|
||||||
const [isRequestingNewCode, setIsRequestingNewCode] = useState(false);
|
const [isRequestingNewCode, setIsRequestingNewCode] = useState(false);
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// store hooks
|
// store hooks
|
||||||
const { captureEvent } = useEventTracker();
|
const { captureEvent } = useEventTracker();
|
||||||
// timer
|
// timer
|
||||||
@ -84,8 +81,8 @@ export const SignInUniqueCodeForm: React.FC<Props> = (props) => {
|
|||||||
captureEvent(CODE_VERIFIED, {
|
captureEvent(CODE_VERIFIED, {
|
||||||
state: "FAILED",
|
state: "FAILED",
|
||||||
});
|
});
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err?.error ?? "Something went wrong. Please try again.",
|
message: err?.error ?? "Something went wrong. Please try again.",
|
||||||
});
|
});
|
||||||
@ -101,8 +98,8 @@ export const SignInUniqueCodeForm: React.FC<Props> = (props) => {
|
|||||||
.generateUniqueCode(payload)
|
.generateUniqueCode(payload)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setResendCodeTimer(30);
|
setResendCodeTimer(30);
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "A new unique code has been sent to your email.",
|
message: "A new unique code has been sent to your email.",
|
||||||
});
|
});
|
||||||
@ -113,8 +110,8 @@ export const SignInUniqueCodeForm: React.FC<Props> = (props) => {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((err) =>
|
.catch((err) =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err?.error ?? "Something went wrong. Please try again.",
|
message: err?.error ?? "Something went wrong. Please try again.",
|
||||||
})
|
})
|
||||||
|
@ -4,10 +4,8 @@ import { XCircle } from "lucide-react";
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// services
|
// services
|
||||||
import { AuthService } from "services/auth.service";
|
import { AuthService } from "services/auth.service";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { checkEmailValidity } from "helpers/string.helper";
|
import { checkEmailValidity } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
@ -27,7 +25,6 @@ const authService = new AuthService();
|
|||||||
export const SignUpEmailForm: React.FC<Props> = observer((props) => {
|
export const SignUpEmailForm: React.FC<Props> = observer((props) => {
|
||||||
const { onSubmit, updateEmail } = props;
|
const { onSubmit, updateEmail } = props;
|
||||||
// hooks
|
// hooks
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
formState: { errors, isSubmitting, isValid },
|
formState: { errors, isSubmitting, isValid },
|
||||||
@ -52,8 +49,8 @@ export const SignUpEmailForm: React.FC<Props> = observer((props) => {
|
|||||||
.emailCheck(payload)
|
.emailCheck(payload)
|
||||||
.then(() => onSubmit())
|
.then(() => onSubmit())
|
||||||
.catch((err) =>
|
.catch((err) =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err?.error ?? "Something went wrong. Please try again.",
|
message: err?.error ?? "Something went wrong. Please try again.",
|
||||||
})
|
})
|
||||||
|
@ -3,14 +3,14 @@ import { Controller, useForm } from "react-hook-form";
|
|||||||
// services
|
// services
|
||||||
import { AuthService } from "services/auth.service";
|
import { AuthService } from "services/auth.service";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import { useEventTracker } from "hooks/store";
|
import { useEventTracker } from "hooks/store";
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { checkEmailValidity } from "helpers/string.helper";
|
import { checkEmailValidity } from "helpers/string.helper";
|
||||||
// constants
|
// components
|
||||||
import { ESignUpSteps } from "components/account";
|
import { ESignUpSteps } from "components/account";
|
||||||
|
// constants
|
||||||
import { PASSWORD_CREATE_SELECTED, PASSWORD_CREATE_SKIPPED, SETUP_PASSWORD } from "constants/event-tracker";
|
import { PASSWORD_CREATE_SELECTED, PASSWORD_CREATE_SKIPPED, SETUP_PASSWORD } from "constants/event-tracker";
|
||||||
// icons
|
// icons
|
||||||
import { Eye, EyeOff } from "lucide-react";
|
import { Eye, EyeOff } from "lucide-react";
|
||||||
@ -41,8 +41,6 @@ export const SignUpOptionalSetPasswordForm: React.FC<Props> = (props) => {
|
|||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
// store hooks
|
// store hooks
|
||||||
const { captureEvent } = useEventTracker();
|
const { captureEvent } = useEventTracker();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// form info
|
// form info
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
@ -65,8 +63,8 @@ export const SignUpOptionalSetPasswordForm: React.FC<Props> = (props) => {
|
|||||||
await authService
|
await authService
|
||||||
.setPassword(payload)
|
.setPassword(payload)
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Password created successfully.",
|
message: "Password created successfully.",
|
||||||
});
|
});
|
||||||
@ -81,8 +79,8 @@ export const SignUpOptionalSetPasswordForm: React.FC<Props> = (props) => {
|
|||||||
state: "FAILED",
|
state: "FAILED",
|
||||||
first_time: true,
|
first_time: true,
|
||||||
});
|
});
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err?.error ?? "Something went wrong. Please try again.",
|
message: err?.error ?? "Something went wrong. Please try again.",
|
||||||
});
|
});
|
||||||
|
@ -5,10 +5,8 @@ import { Controller, useForm } from "react-hook-form";
|
|||||||
import { Eye, EyeOff, XCircle } from "lucide-react";
|
import { Eye, EyeOff, XCircle } from "lucide-react";
|
||||||
// services
|
// services
|
||||||
import { AuthService } from "services/auth.service";
|
import { AuthService } from "services/auth.service";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { checkEmailValidity } from "helpers/string.helper";
|
import { checkEmailValidity } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
@ -34,8 +32,6 @@ export const SignUpPasswordForm: React.FC<Props> = observer((props) => {
|
|||||||
const { onSubmit } = props;
|
const { onSubmit } = props;
|
||||||
// states
|
// states
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// form info
|
// form info
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
@ -59,8 +55,8 @@ export const SignUpPasswordForm: React.FC<Props> = observer((props) => {
|
|||||||
.passwordSignIn(payload)
|
.passwordSignIn(payload)
|
||||||
.then(async () => await onSubmit())
|
.then(async () => await onSubmit())
|
||||||
.catch((err) =>
|
.catch((err) =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err?.error ?? "Something went wrong. Please try again.",
|
message: err?.error ?? "Something went wrong. Please try again.",
|
||||||
})
|
})
|
||||||
|
@ -6,11 +6,10 @@ import { XCircle } from "lucide-react";
|
|||||||
import { AuthService } from "services/auth.service";
|
import { AuthService } from "services/auth.service";
|
||||||
import { UserService } from "services/user.service";
|
import { UserService } from "services/user.service";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import useTimer from "hooks/use-timer";
|
import useTimer from "hooks/use-timer";
|
||||||
import { useEventTracker } from "hooks/store";
|
import { useEventTracker } from "hooks/store";
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { checkEmailValidity } from "helpers/string.helper";
|
import { checkEmailValidity } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
@ -44,8 +43,6 @@ export const SignUpUniqueCodeForm: React.FC<Props> = (props) => {
|
|||||||
const [isRequestingNewCode, setIsRequestingNewCode] = useState(false);
|
const [isRequestingNewCode, setIsRequestingNewCode] = useState(false);
|
||||||
// store hooks
|
// store hooks
|
||||||
const { captureEvent } = useEventTracker();
|
const { captureEvent } = useEventTracker();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// timer
|
// timer
|
||||||
const { timer: resendTimerCode, setTimer: setResendCodeTimer } = useTimer(30);
|
const { timer: resendTimerCode, setTimer: setResendCodeTimer } = useTimer(30);
|
||||||
// form info
|
// form info
|
||||||
@ -84,8 +81,8 @@ export const SignUpUniqueCodeForm: React.FC<Props> = (props) => {
|
|||||||
captureEvent(CODE_VERIFIED, {
|
captureEvent(CODE_VERIFIED, {
|
||||||
state: "FAILED",
|
state: "FAILED",
|
||||||
});
|
});
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err?.error ?? "Something went wrong. Please try again.",
|
message: err?.error ?? "Something went wrong. Please try again.",
|
||||||
});
|
});
|
||||||
@ -101,8 +98,8 @@ export const SignUpUniqueCodeForm: React.FC<Props> = (props) => {
|
|||||||
.generateUniqueCode(payload)
|
.generateUniqueCode(payload)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setResendCodeTimer(30);
|
setResendCodeTimer(30);
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "A new unique code has been sent to your email.",
|
message: "A new unique code has been sent to your email.",
|
||||||
});
|
});
|
||||||
@ -112,8 +109,8 @@ export const SignUpUniqueCodeForm: React.FC<Props> = (props) => {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((err) =>
|
.catch((err) =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err?.error ?? "Something went wrong. Please try again.",
|
message: err?.error ?? "Something went wrong. Please try again.",
|
||||||
})
|
})
|
||||||
|
@ -6,11 +6,10 @@ import { mutate } from "swr";
|
|||||||
import { AnalyticsService } from "services/analytics.service";
|
import { AnalyticsService } from "services/analytics.service";
|
||||||
// hooks
|
// hooks
|
||||||
import { useCycle, useModule, useProject, useUser, useWorkspace } from "hooks/store";
|
import { useCycle, useModule, useProject, useUser, useWorkspace } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// components
|
// components
|
||||||
import { CustomAnalyticsSidebarHeader, CustomAnalyticsSidebarProjectsList } from "components/analytics";
|
import { CustomAnalyticsSidebarHeader, CustomAnalyticsSidebarProjectsList } from "components/analytics";
|
||||||
// ui
|
// ui
|
||||||
import { Button, LayersIcon } from "@plane/ui";
|
import { Button, LayersIcon, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// icons
|
// icons
|
||||||
import { CalendarDays, Download, RefreshCw } from "lucide-react";
|
import { CalendarDays, Download, RefreshCw } from "lucide-react";
|
||||||
// helpers
|
// helpers
|
||||||
@ -34,8 +33,6 @@ export const CustomAnalyticsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// store hooks
|
// store hooks
|
||||||
const { currentUser } = useUser();
|
const { currentUser } = useUser();
|
||||||
const { workspaceProjectIds, getProjectById } = useProject();
|
const { workspaceProjectIds, getProjectById } = useProject();
|
||||||
@ -107,8 +104,8 @@ export const CustomAnalyticsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
analyticsService
|
analyticsService
|
||||||
.exportAnalytics(workspaceSlug.toString(), data)
|
.exportAnalytics(workspaceSlug.toString(), data)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: res.message,
|
message: res.message,
|
||||||
});
|
});
|
||||||
@ -116,8 +113,8 @@ export const CustomAnalyticsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
trackExportAnalytics();
|
trackExportAnalytics();
|
||||||
})
|
})
|
||||||
.catch(() =>
|
.catch(() =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "There was some error in exporting the analytics. Please try again.",
|
message: "There was some error in exporting the analytics. Please try again.",
|
||||||
})
|
})
|
||||||
|
@ -4,10 +4,8 @@ import { mutate } from "swr";
|
|||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
// services
|
// services
|
||||||
import { APITokenService } from "services/api_token.service";
|
import { APITokenService } from "services/api_token.service";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { Button } from "@plane/ui";
|
import { Button, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { IApiToken } from "@plane/types";
|
import { IApiToken } from "@plane/types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
@ -25,8 +23,6 @@ export const DeleteApiTokenModal: FC<Props> = (props) => {
|
|||||||
const { isOpen, onClose, tokenId } = props;
|
const { isOpen, onClose, tokenId } = props;
|
||||||
// states
|
// states
|
||||||
const [deleteLoading, setDeleteLoading] = useState<boolean>(false);
|
const [deleteLoading, setDeleteLoading] = useState<boolean>(false);
|
||||||
// hooks
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
@ -44,8 +40,8 @@ export const DeleteApiTokenModal: FC<Props> = (props) => {
|
|||||||
apiTokenService
|
apiTokenService
|
||||||
.deleteApiToken(workspaceSlug.toString(), tokenId)
|
.deleteApiToken(workspaceSlug.toString(), tokenId)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Token deleted successfully.",
|
message: "Token deleted successfully.",
|
||||||
});
|
});
|
||||||
@ -59,8 +55,8 @@ export const DeleteApiTokenModal: FC<Props> = (props) => {
|
|||||||
handleClose();
|
handleClose();
|
||||||
})
|
})
|
||||||
.catch((err) =>
|
.catch((err) =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error",
|
title: "Error",
|
||||||
message: err?.message ?? "Something went wrong. Please try again.",
|
message: err?.message ?? "Something went wrong. Please try again.",
|
||||||
})
|
})
|
||||||
|
@ -4,8 +4,8 @@ import { mutate } from "swr";
|
|||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
// services
|
// services
|
||||||
import { APITokenService } from "services/api_token.service";
|
import { APITokenService } from "services/api_token.service";
|
||||||
// hooks
|
// ui
|
||||||
import useToast from "hooks/use-toast";
|
import { TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { CreateApiTokenForm, GeneratedTokenDetails } from "components/api-token";
|
import { CreateApiTokenForm, GeneratedTokenDetails } from "components/api-token";
|
||||||
// helpers
|
// helpers
|
||||||
@ -32,8 +32,6 @@ export const CreateApiTokenModal: React.FC<Props> = (props) => {
|
|||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
onClose();
|
onClose();
|
||||||
@ -76,10 +74,10 @@ export const CreateApiTokenModal: React.FC<Props> = (props) => {
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
message: err.message,
|
type: TOAST_TYPE.ERROR,
|
||||||
type: "error",
|
|
||||||
title: "Error",
|
title: "Error",
|
||||||
|
message: err.message,
|
||||||
});
|
});
|
||||||
|
|
||||||
throw err;
|
throw err;
|
||||||
|
@ -3,10 +3,8 @@ import { add } from "date-fns";
|
|||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { DateDropdown } from "components/dropdowns";
|
import { DateDropdown } from "components/dropdowns";
|
||||||
import { Calendar } from "lucide-react";
|
import { Calendar } from "lucide-react";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { Button, CustomSelect, Input, TextArea, ToggleSwitch } from "@plane/ui";
|
import { Button, CustomSelect, Input, TextArea, ToggleSwitch, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { renderFormattedDate, renderFormattedPayloadDate } from "helpers/date-time.helper";
|
import { renderFormattedDate, renderFormattedPayloadDate } from "helpers/date-time.helper";
|
||||||
// types
|
// types
|
||||||
@ -66,8 +64,6 @@ export const CreateApiTokenForm: React.FC<Props> = (props) => {
|
|||||||
const { handleClose, neverExpires, toggleNeverExpires, onSubmit } = props;
|
const { handleClose, neverExpires, toggleNeverExpires, onSubmit } = props;
|
||||||
// states
|
// states
|
||||||
const [customDate, setCustomDate] = useState<Date | null>(null);
|
const [customDate, setCustomDate] = useState<Date | null>(null);
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// form
|
// form
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
@ -80,8 +76,8 @@ export const CreateApiTokenForm: React.FC<Props> = (props) => {
|
|||||||
const handleFormSubmit = async (data: IApiToken) => {
|
const handleFormSubmit = async (data: IApiToken) => {
|
||||||
// if never expires is toggled off, and the user has not selected a custom date or a predefined date, show an error
|
// if never expires is toggled off, and the user has not selected a custom date or a predefined date, show an error
|
||||||
if (!neverExpires && (!data.expired_at || (data.expired_at === "custom" && !customDate)))
|
if (!neverExpires && (!data.expired_at || (data.expired_at === "custom" && !customDate)))
|
||||||
return setToastAlert({
|
return setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Please select an expiration date.",
|
message: "Please select an expiration date.",
|
||||||
});
|
});
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
import { Copy } from "lucide-react";
|
import { Copy } from "lucide-react";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { Button, Tooltip } from "@plane/ui";
|
import { Button, Tooltip, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { renderFormattedDate } from "helpers/date-time.helper";
|
import { renderFormattedDate } from "helpers/date-time.helper";
|
||||||
import { copyTextToClipboard } from "helpers/string.helper";
|
import { copyTextToClipboard } from "helpers/string.helper";
|
||||||
@ -17,12 +15,10 @@ type Props = {
|
|||||||
export const GeneratedTokenDetails: React.FC<Props> = (props) => {
|
export const GeneratedTokenDetails: React.FC<Props> = (props) => {
|
||||||
const { handleClose, tokenDetails } = props;
|
const { handleClose, tokenDetails } = props;
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const copyApiToken = (token: string) => {
|
const copyApiToken = (token: string) => {
|
||||||
copyTextToClipboard(token).then(() =>
|
copyTextToClipboard(token).then(() =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Token copied to clipboard.",
|
message: "Token copied to clipboard.",
|
||||||
})
|
})
|
||||||
|
@ -4,10 +4,8 @@ import { Command } from "cmdk";
|
|||||||
import { LinkIcon, Signal, Trash2, UserMinus2, UserPlus2 } from "lucide-react";
|
import { LinkIcon, Signal, Trash2, UserMinus2, UserPlus2 } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useApplication, useUser, useIssues } from "hooks/store";
|
import { useApplication, useUser, useIssues } from "hooks/store";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { DoubleCircleIcon, UserGroupIcon } from "@plane/ui";
|
import { DoubleCircleIcon, UserGroupIcon, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { copyTextToClipboard } from "helpers/string.helper";
|
import { copyTextToClipboard } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
@ -37,8 +35,6 @@ export const CommandPaletteIssueActions: React.FC<Props> = observer((props) => {
|
|||||||
} = useApplication();
|
} = useApplication();
|
||||||
const { currentUser } = useUser();
|
const { currentUser } = useUser();
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const handleUpdateIssue = async (formData: Partial<TIssue>) => {
|
const handleUpdateIssue = async (formData: Partial<TIssue>) => {
|
||||||
if (!workspaceSlug || !projectId || !issueDetails) return;
|
if (!workspaceSlug || !projectId || !issueDetails) return;
|
||||||
|
|
||||||
@ -71,14 +67,14 @@ export const CommandPaletteIssueActions: React.FC<Props> = observer((props) => {
|
|||||||
const url = new URL(window.location.href);
|
const url = new URL(window.location.href);
|
||||||
copyTextToClipboard(url.href)
|
copyTextToClipboard(url.href)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Copied to clipboard",
|
title: "Copied to clipboard",
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Some error occurred",
|
title: "Some error occurred",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -5,7 +5,8 @@ import { Settings } from "lucide-react";
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// hooks
|
// hooks
|
||||||
import { useUser } from "hooks/store";
|
import { useUser } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
// ui
|
||||||
|
import { TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// constants
|
// constants
|
||||||
import { THEME_OPTIONS } from "constants/themes";
|
import { THEME_OPTIONS } from "constants/themes";
|
||||||
|
|
||||||
@ -21,15 +22,14 @@ export const CommandPaletteThemeActions: FC<Props> = observer((props) => {
|
|||||||
const { updateCurrentUserTheme } = useUser();
|
const { updateCurrentUserTheme } = useUser();
|
||||||
// hooks
|
// hooks
|
||||||
const { setTheme } = useTheme();
|
const { setTheme } = useTheme();
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const updateUserTheme = async (newTheme: string) => {
|
const updateUserTheme = async (newTheme: string) => {
|
||||||
setTheme(newTheme);
|
setTheme(newTheme);
|
||||||
|
|
||||||
return updateCurrentUserTheme(newTheme).catch(() => {
|
return updateCurrentUserTheme(newTheme).catch(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Failed to save user theme settings!",
|
title: "Failed to save user theme settings!",
|
||||||
type: "error",
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -4,7 +4,8 @@ import useSWR from "swr";
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// hooks
|
// hooks
|
||||||
import { useApplication, useEventTracker, useIssues, useUser } from "hooks/store";
|
import { useApplication, useEventTracker, useIssues, useUser } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
// ui
|
||||||
|
import { TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { CommandModal, ShortcutsModal } from "components/command-palette";
|
import { CommandModal, ShortcutsModal } from "components/command-palette";
|
||||||
import { BulkDeleteIssuesModal } from "components/core";
|
import { BulkDeleteIssuesModal } from "components/core";
|
||||||
@ -63,8 +64,6 @@ export const CommandPalette: FC = observer(() => {
|
|||||||
createIssueStoreType,
|
createIssueStoreType,
|
||||||
} = commandPalette;
|
} = commandPalette;
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const { data: issueDetails } = useSWR(
|
const { data: issueDetails } = useSWR(
|
||||||
workspaceSlug && projectId && issueId ? ISSUE_DETAILS(issueId as string) : null,
|
workspaceSlug && projectId && issueId ? ISSUE_DETAILS(issueId as string) : null,
|
||||||
workspaceSlug && projectId && issueId
|
workspaceSlug && projectId && issueId
|
||||||
@ -78,18 +77,18 @@ export const CommandPalette: FC = observer(() => {
|
|||||||
const url = new URL(window.location.href);
|
const url = new URL(window.location.href);
|
||||||
copyTextToClipboard(url.href)
|
copyTextToClipboard(url.href)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Copied to clipboard",
|
title: "Copied to clipboard",
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Some error occurred",
|
title: "Some error occurred",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, [setToastAlert, issueId]);
|
}, [issueId]);
|
||||||
|
|
||||||
const handleKeyDown = useCallback(
|
const handleKeyDown = useCallback(
|
||||||
(e: KeyboardEvent) => {
|
(e: KeyboardEvent) => {
|
||||||
|
@ -6,10 +6,8 @@ import { SubmitHandler, useForm } from "react-hook-form";
|
|||||||
import { Combobox, Dialog, Transition } from "@headlessui/react";
|
import { Combobox, Dialog, Transition } from "@headlessui/react";
|
||||||
// services
|
// services
|
||||||
import { IssueService } from "services/issue";
|
import { IssueService } from "services/issue";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { Button, LayersIcon } from "@plane/ui";
|
import { Button, LayersIcon, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// icons
|
// icons
|
||||||
import { Search } from "lucide-react";
|
import { Search } from "lucide-react";
|
||||||
// types
|
// types
|
||||||
@ -55,8 +53,6 @@ export const BulkDeleteIssuesModal: React.FC<Props> = observer((props) => {
|
|||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
watch,
|
watch,
|
||||||
@ -79,8 +75,8 @@ export const BulkDeleteIssuesModal: React.FC<Props> = observer((props) => {
|
|||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
if (!data.delete_issue_ids || data.delete_issue_ids.length === 0) {
|
if (!data.delete_issue_ids || data.delete_issue_ids.length === 0) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Please select at least one issue.",
|
message: "Please select at least one issue.",
|
||||||
});
|
});
|
||||||
@ -91,16 +87,16 @@ export const BulkDeleteIssuesModal: React.FC<Props> = observer((props) => {
|
|||||||
|
|
||||||
await removeBulkIssues(workspaceSlug as string, projectId as string, data.delete_issue_ids)
|
await removeBulkIssues(workspaceSlug as string, projectId as string, data.delete_issue_ids)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Issues deleted successfully!",
|
message: "Issues deleted successfully!",
|
||||||
});
|
});
|
||||||
handleClose();
|
handleClose();
|
||||||
})
|
})
|
||||||
.catch(() =>
|
.catch(() =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Something went wrong. Please try again.",
|
message: "Something went wrong. Please try again.",
|
||||||
})
|
})
|
||||||
|
@ -3,11 +3,9 @@ import { Combobox, Dialog, Transition } from "@headlessui/react";
|
|||||||
import { Rocket, Search, X } from "lucide-react";
|
import { Rocket, Search, X } from "lucide-react";
|
||||||
// services
|
// services
|
||||||
import { ProjectService } from "services/project";
|
import { ProjectService } from "services/project";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import useDebounce from "hooks/use-debounce";
|
import useDebounce from "hooks/use-debounce";
|
||||||
// ui
|
// ui
|
||||||
import { Button, LayersIcon, Loader, ToggleSwitch, Tooltip } from "@plane/ui";
|
import { Button, LayersIcon, Loader, ToggleSwitch, Tooltip, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { ISearchIssueResponse, TProjectIssuesSearchParams } from "@plane/types";
|
import { ISearchIssueResponse, TProjectIssuesSearchParams } from "@plane/types";
|
||||||
|
|
||||||
@ -43,8 +41,6 @@ export const ExistingIssuesListModal: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
const debouncedSearchTerm: string = useDebounce(searchTerm, 500);
|
const debouncedSearchTerm: string = useDebounce(searchTerm, 500);
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
onClose();
|
onClose();
|
||||||
setSearchTerm("");
|
setSearchTerm("");
|
||||||
@ -54,8 +50,8 @@ export const ExistingIssuesListModal: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
const onSubmit = async () => {
|
const onSubmit = async () => {
|
||||||
if (selectedIssues.length === 0) {
|
if (selectedIssues.length === 0) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Please select at least one issue.",
|
message: "Please select at least one issue.",
|
||||||
});
|
});
|
||||||
@ -69,9 +65,9 @@ export const ExistingIssuesListModal: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
handleClose();
|
handleClose();
|
||||||
|
|
||||||
setToastAlert({
|
setToast({
|
||||||
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success",
|
title: "Success",
|
||||||
type: "success",
|
|
||||||
message: `Issue${selectedIssues.length > 1 ? "s" : ""} added successfully`,
|
message: `Issue${selectedIssues.length > 1 ? "s" : ""} added successfully`,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -3,10 +3,9 @@ import { useRouter } from "next/router";
|
|||||||
import { Controller, useForm } from "react-hook-form"; // services
|
import { Controller, useForm } from "react-hook-form"; // services
|
||||||
import { AIService } from "services/ai.service";
|
import { AIService } from "services/ai.service";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import { usePopper } from "react-popper";
|
import { usePopper } from "react-popper";
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { RichReadOnlyEditorWithRef } from "@plane/rich-text-editor";
|
import { RichReadOnlyEditorWithRef } from "@plane/rich-text-editor";
|
||||||
import { Popover, Transition } from "@headlessui/react";
|
import { Popover, Transition } from "@headlessui/react";
|
||||||
@ -44,8 +43,6 @@ export const GptAssistantPopover: React.FC<Props> = (props) => {
|
|||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// popper
|
// popper
|
||||||
const { styles, attributes } = usePopper(referenceElement, popperElement, {
|
const { styles, attributes } = usePopper(referenceElement, popperElement, {
|
||||||
placement: placement ?? "auto",
|
placement: placement ?? "auto",
|
||||||
@ -78,8 +75,8 @@ export const GptAssistantPopover: React.FC<Props> = (props) => {
|
|||||||
? error || "You have reached the maximum number of requests of 50 requests per month per user."
|
? error || "You have reached the maximum number of requests of 50 requests per month per user."
|
||||||
: error || "Some error occurred. Please try again.";
|
: error || "Some error occurred. Please try again.";
|
||||||
|
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: errorMessage,
|
message: errorMessage,
|
||||||
});
|
});
|
||||||
@ -104,8 +101,8 @@ export const GptAssistantPopover: React.FC<Props> = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleInvalidTask = () => {
|
const handleInvalidTask = () => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Please enter some task to get AI assistance.",
|
message: "Please enter some task to get AI assistance.",
|
||||||
});
|
});
|
||||||
|
@ -6,10 +6,8 @@ import { Transition, Dialog } from "@headlessui/react";
|
|||||||
import { useApplication } from "hooks/store";
|
import { useApplication } from "hooks/store";
|
||||||
// services
|
// services
|
||||||
import { FileService } from "services/file.service";
|
import { FileService } from "services/file.service";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { Button } from "@plane/ui";
|
import { Button, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// icons
|
// icons
|
||||||
import { UserCircle2 } from "lucide-react";
|
import { UserCircle2 } from "lucide-react";
|
||||||
// constants
|
// constants
|
||||||
@ -32,8 +30,6 @@ export const UserImageUploadModal: React.FC<Props> = observer((props) => {
|
|||||||
// states
|
// states
|
||||||
const [image, setImage] = useState<File | null>(null);
|
const [image, setImage] = useState<File | null>(null);
|
||||||
const [isImageUploading, setIsImageUploading] = useState(false);
|
const [isImageUploading, setIsImageUploading] = useState(false);
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// store hooks
|
// store hooks
|
||||||
const {
|
const {
|
||||||
config: { envConfig },
|
config: { envConfig },
|
||||||
@ -76,8 +72,8 @@ export const UserImageUploadModal: React.FC<Props> = observer((props) => {
|
|||||||
if (value) fileService.deleteUserFile(value);
|
if (value) fileService.deleteUserFile(value);
|
||||||
})
|
})
|
||||||
.catch((err) =>
|
.catch((err) =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err?.error ?? "Something went wrong. Please try again.",
|
message: err?.error ?? "Something went wrong. Please try again.",
|
||||||
})
|
})
|
||||||
|
@ -7,10 +7,8 @@ import { Transition, Dialog } from "@headlessui/react";
|
|||||||
import { useApplication, useWorkspace } from "hooks/store";
|
import { useApplication, useWorkspace } from "hooks/store";
|
||||||
// services
|
// services
|
||||||
import { FileService } from "services/file.service";
|
import { FileService } from "services/file.service";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { Button } from "@plane/ui";
|
import { Button, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// icons
|
// icons
|
||||||
import { UserCircle2 } from "lucide-react";
|
import { UserCircle2 } from "lucide-react";
|
||||||
// constants
|
// constants
|
||||||
@ -37,8 +35,6 @@ export const WorkspaceImageUploadModal: React.FC<Props> = observer((props) => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
config: { envConfig },
|
config: { envConfig },
|
||||||
} = useApplication();
|
} = useApplication();
|
||||||
@ -83,8 +79,8 @@ export const WorkspaceImageUploadModal: React.FC<Props> = observer((props) => {
|
|||||||
if (value && currentWorkspace) fileService.deleteFile(currentWorkspace.id, value);
|
if (value && currentWorkspace) fileService.deleteFile(currentWorkspace.id, value);
|
||||||
})
|
})
|
||||||
.catch((err) =>
|
.catch((err) =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err?.error ?? "Something went wrong. Please try again.",
|
message: err?.error ?? "Something went wrong. Please try again.",
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// ui
|
// ui
|
||||||
import { ExternalLinkIcon, Tooltip } from "@plane/ui";
|
import { ExternalLinkIcon, Tooltip, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// icons
|
// icons
|
||||||
import { Pencil, Trash2, LinkIcon } from "lucide-react";
|
import { Pencil, Trash2, LinkIcon } from "lucide-react";
|
||||||
// helpers
|
// helpers
|
||||||
@ -7,7 +7,6 @@ import { calculateTimeAgo } from "helpers/date-time.helper";
|
|||||||
// types
|
// types
|
||||||
import { ILinkDetails, UserAuth } from "@plane/types";
|
import { ILinkDetails, UserAuth } from "@plane/types";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useMeasure } from "@nivo/core";
|
import { useMeasure } from "@nivo/core";
|
||||||
import { useMember } from "hooks/store";
|
import { useMember } from "hooks/store";
|
||||||
@ -20,18 +19,16 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const LinksList: React.FC<Props> = observer(({ links, handleDeleteLink, handleEditLink, userAuth }) => {
|
export const LinksList: React.FC<Props> = observer(({ links, handleDeleteLink, handleEditLink, userAuth }) => {
|
||||||
// toast
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
const { getUserDetails } = useMember();
|
const { getUserDetails } = useMember();
|
||||||
|
|
||||||
const isNotAllowed = userAuth.isGuest || userAuth.isViewer;
|
const isNotAllowed = userAuth.isGuest || userAuth.isViewer;
|
||||||
|
|
||||||
const copyToClipboard = (text: string) => {
|
const copyToClipboard = (text: string) => {
|
||||||
navigator.clipboard.writeText(text);
|
navigator.clipboard.writeText(text);
|
||||||
setToastAlert({
|
setToast({
|
||||||
message: "The URL has been successfully copied to your clipboard",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
type: "success",
|
|
||||||
title: "Copied to clipboard",
|
title: "Copied to clipboard",
|
||||||
|
message: "The URL has been successfully copied to your clipboard",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ import useSWR from "swr";
|
|||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
// hooks
|
// hooks
|
||||||
import { useCycle, useIssues, useMember, useProject, useUser } from "hooks/store";
|
import { useCycle, useIssues, useMember, useProject, useUser } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { SingleProgressStats } from "components/core";
|
import { SingleProgressStats } from "components/core";
|
||||||
import {
|
import {
|
||||||
@ -18,6 +17,7 @@ import {
|
|||||||
PriorityIcon,
|
PriorityIcon,
|
||||||
Avatar,
|
Avatar,
|
||||||
CycleGroupIcon,
|
CycleGroupIcon,
|
||||||
|
setPromiseToast,
|
||||||
} from "@plane/ui";
|
} from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import ProgressChart from "components/core/sidebar/progress-chart";
|
import ProgressChart from "components/core/sidebar/progress-chart";
|
||||||
@ -60,8 +60,6 @@ export const ActiveCycleDetails: React.FC<IActiveCycleDetails> = observer((props
|
|||||||
} = useCycle();
|
} = useCycle();
|
||||||
const { currentProjectDetails } = useProject();
|
const { currentProjectDetails } = useProject();
|
||||||
const { getUserDetails } = useMember();
|
const { getUserDetails } = useMember();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const { isLoading } = useSWR(
|
const { isLoading } = useSWR(
|
||||||
workspaceSlug && projectId ? `PROJECT_ACTIVE_CYCLE_${projectId}` : null,
|
workspaceSlug && projectId ? `PROJECT_ACTIVE_CYCLE_${projectId}` : null,
|
||||||
@ -119,12 +117,18 @@ export const ActiveCycleDetails: React.FC<IActiveCycleDetails> = observer((props
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
addCycleToFavorites(workspaceSlug?.toString(), projectId.toString(), activeCycle.id).catch(() => {
|
const addToFavoritePromise = addCycleToFavorites(workspaceSlug?.toString(), projectId.toString(), activeCycle.id);
|
||||||
setToastAlert({
|
|
||||||
type: "error",
|
setPromiseToast(addToFavoritePromise, {
|
||||||
|
loading: "Adding cycle to favorites...",
|
||||||
|
success: {
|
||||||
|
title: "Success!",
|
||||||
|
message: () => "Cycle added to favorites.",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Couldn't add the cycle to favorites. Please try again.",
|
message: () => "Couldn't add the cycle to favorites. Please try again.",
|
||||||
});
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -132,12 +136,22 @@ export const ActiveCycleDetails: React.FC<IActiveCycleDetails> = observer((props
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
removeCycleFromFavorites(workspaceSlug?.toString(), projectId.toString(), activeCycle.id).catch(() => {
|
const removeFromFavoritePromise = removeCycleFromFavorites(
|
||||||
setToastAlert({
|
workspaceSlug?.toString(),
|
||||||
type: "error",
|
projectId.toString(),
|
||||||
|
activeCycle.id
|
||||||
|
);
|
||||||
|
|
||||||
|
setPromiseToast(removeFromFavoritePromise, {
|
||||||
|
loading: "Removing cycle from favorites...",
|
||||||
|
success: {
|
||||||
|
title: "Success!",
|
||||||
|
message: () => "Cycle removed from favorites.",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Couldn't add the cycle to favorites. Please try again.",
|
message: () => "Couldn't remove the cycle from favorites. Please try again.",
|
||||||
});
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4,11 +4,20 @@ import Link from "next/link";
|
|||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEventTracker, useCycle, useUser, useMember } from "hooks/store";
|
import { useEventTracker, useCycle, useUser, useMember } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// components
|
// components
|
||||||
import { CycleCreateUpdateModal, CycleDeleteModal } from "components/cycles";
|
import { CycleCreateUpdateModal, CycleDeleteModal } from "components/cycles";
|
||||||
// ui
|
// ui
|
||||||
import { Avatar, AvatarGroup, CustomMenu, Tooltip, LayersIcon, CycleGroupIcon } from "@plane/ui";
|
import {
|
||||||
|
Avatar,
|
||||||
|
AvatarGroup,
|
||||||
|
CustomMenu,
|
||||||
|
Tooltip,
|
||||||
|
LayersIcon,
|
||||||
|
CycleGroupIcon,
|
||||||
|
TOAST_TYPE,
|
||||||
|
setToast,
|
||||||
|
setPromiseToast,
|
||||||
|
} from "@plane/ui";
|
||||||
// icons
|
// icons
|
||||||
import { Info, LinkIcon, Pencil, Star, Trash2 } from "lucide-react";
|
import { Info, LinkIcon, Pencil, Star, Trash2 } from "lucide-react";
|
||||||
// helpers
|
// helpers
|
||||||
@ -41,8 +50,6 @@ export const CyclesBoardCard: FC<ICyclesBoardCard> = observer((props) => {
|
|||||||
} = useUser();
|
} = useUser();
|
||||||
const { addCycleToFavorites, removeCycleFromFavorites, getCycleById } = useCycle();
|
const { addCycleToFavorites, removeCycleFromFavorites, getCycleById } = useCycle();
|
||||||
const { getUserDetails } = useMember();
|
const { getUserDetails } = useMember();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// computed
|
// computed
|
||||||
const cycleDetails = getCycleById(cycleId);
|
const cycleDetails = getCycleById(cycleId);
|
||||||
|
|
||||||
@ -81,8 +88,8 @@ export const CyclesBoardCard: FC<ICyclesBoardCard> = observer((props) => {
|
|||||||
const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
|
const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
|
||||||
|
|
||||||
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}`).then(() => {
|
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}`).then(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Link Copied!",
|
title: "Link Copied!",
|
||||||
message: "Cycle link copied to clipboard.",
|
message: "Cycle link copied to clipboard.",
|
||||||
});
|
});
|
||||||
@ -93,42 +100,56 @@ export const CyclesBoardCard: FC<ICyclesBoardCard> = observer((props) => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
addCycleToFavorites(workspaceSlug?.toString(), projectId.toString(), cycleId)
|
const addToFavoritePromise = addCycleToFavorites(workspaceSlug?.toString(), projectId.toString(), cycleId).then(
|
||||||
.then(() => {
|
() => {
|
||||||
captureEvent(CYCLE_FAVORITED, {
|
captureEvent(CYCLE_FAVORITED, {
|
||||||
cycle_id: cycleId,
|
cycle_id: cycleId,
|
||||||
element: "Grid layout",
|
element: "Grid layout",
|
||||||
state: "SUCCESS",
|
state: "SUCCESS",
|
||||||
});
|
});
|
||||||
})
|
}
|
||||||
.catch(() => {
|
);
|
||||||
setToastAlert({
|
|
||||||
type: "error",
|
setPromiseToast(addToFavoritePromise, {
|
||||||
title: "Error!",
|
loading: "Adding cycle to favorites...",
|
||||||
message: "Couldn't add the cycle to favorites. Please try again.",
|
success: {
|
||||||
});
|
title: "Success!",
|
||||||
});
|
message: () => "Cycle added to favorites.",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
title: "Error!",
|
||||||
|
message: () => "Couldn't add the cycle to favorites. Please try again.",
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveFromFavorites = (e: MouseEvent<HTMLButtonElement>) => {
|
const handleRemoveFromFavorites = (e: MouseEvent<HTMLButtonElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
removeCycleFromFavorites(workspaceSlug?.toString(), projectId.toString(), cycleId)
|
const removeFromFavoritePromise = removeCycleFromFavorites(
|
||||||
.then(() => {
|
workspaceSlug?.toString(),
|
||||||
captureEvent(CYCLE_UNFAVORITED, {
|
projectId.toString(),
|
||||||
cycle_id: cycleId,
|
cycleId
|
||||||
element: "Grid layout",
|
).then(() => {
|
||||||
state: "SUCCESS",
|
captureEvent(CYCLE_UNFAVORITED, {
|
||||||
});
|
cycle_id: cycleId,
|
||||||
})
|
element: "Grid layout",
|
||||||
.catch(() => {
|
state: "SUCCESS",
|
||||||
setToastAlert({
|
|
||||||
type: "error",
|
|
||||||
title: "Error!",
|
|
||||||
message: "Couldn't add the cycle to favorites. Please try again.",
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
setPromiseToast(removeFromFavoritePromise, {
|
||||||
|
loading: "Removing cycle from favorites...",
|
||||||
|
success: {
|
||||||
|
title: "Success!",
|
||||||
|
message: () => "Cycle removed from favorites.",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
title: "Error!",
|
||||||
|
message: () => "Couldn't remove the cycle from favorites. Please try again.",
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEditCycle = (e: MouseEvent<HTMLButtonElement>) => {
|
const handleEditCycle = (e: MouseEvent<HTMLButtonElement>) => {
|
||||||
|
@ -4,11 +4,20 @@ import { useRouter } from "next/router";
|
|||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEventTracker, useCycle, useUser, useMember } from "hooks/store";
|
import { useEventTracker, useCycle, useUser, useMember } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// components
|
// components
|
||||||
import { CycleCreateUpdateModal, CycleDeleteModal } from "components/cycles";
|
import { CycleCreateUpdateModal, CycleDeleteModal } from "components/cycles";
|
||||||
// ui
|
// ui
|
||||||
import { CustomMenu, Tooltip, CircularProgressIndicator, CycleGroupIcon, AvatarGroup, Avatar } from "@plane/ui";
|
import {
|
||||||
|
CustomMenu,
|
||||||
|
Tooltip,
|
||||||
|
CircularProgressIndicator,
|
||||||
|
CycleGroupIcon,
|
||||||
|
AvatarGroup,
|
||||||
|
Avatar,
|
||||||
|
TOAST_TYPE,
|
||||||
|
setToast,
|
||||||
|
setPromiseToast,
|
||||||
|
} from "@plane/ui";
|
||||||
// icons
|
// icons
|
||||||
import { Check, Info, LinkIcon, Pencil, Star, Trash2, User2 } from "lucide-react";
|
import { Check, Info, LinkIcon, Pencil, Star, Trash2, User2 } from "lucide-react";
|
||||||
// helpers
|
// helpers
|
||||||
@ -45,8 +54,6 @@ export const CyclesListItem: FC<TCyclesListItem> = observer((props) => {
|
|||||||
} = useUser();
|
} = useUser();
|
||||||
const { getCycleById, addCycleToFavorites, removeCycleFromFavorites } = useCycle();
|
const { getCycleById, addCycleToFavorites, removeCycleFromFavorites } = useCycle();
|
||||||
const { getUserDetails } = useMember();
|
const { getUserDetails } = useMember();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const handleCopyText = (e: MouseEvent<HTMLButtonElement>) => {
|
const handleCopyText = (e: MouseEvent<HTMLButtonElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -54,8 +61,8 @@ export const CyclesListItem: FC<TCyclesListItem> = observer((props) => {
|
|||||||
const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
|
const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
|
||||||
|
|
||||||
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}`).then(() => {
|
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}`).then(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Link Copied!",
|
title: "Link Copied!",
|
||||||
message: "Cycle link copied to clipboard.",
|
message: "Cycle link copied to clipboard.",
|
||||||
});
|
});
|
||||||
@ -66,42 +73,56 @@ export const CyclesListItem: FC<TCyclesListItem> = observer((props) => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
addCycleToFavorites(workspaceSlug?.toString(), projectId.toString(), cycleId)
|
const addToFavoritePromise = addCycleToFavorites(workspaceSlug?.toString(), projectId.toString(), cycleId).then(
|
||||||
.then(() => {
|
() => {
|
||||||
captureEvent(CYCLE_FAVORITED, {
|
captureEvent(CYCLE_FAVORITED, {
|
||||||
cycle_id: cycleId,
|
cycle_id: cycleId,
|
||||||
element: "List layout",
|
element: "List layout",
|
||||||
state: "SUCCESS",
|
state: "SUCCESS",
|
||||||
});
|
});
|
||||||
})
|
}
|
||||||
.catch(() => {
|
);
|
||||||
setToastAlert({
|
|
||||||
type: "error",
|
setPromiseToast(addToFavoritePromise, {
|
||||||
title: "Error!",
|
loading: "Adding cycle to favorites...",
|
||||||
message: "Couldn't add the cycle to favorites. Please try again.",
|
success: {
|
||||||
});
|
title: "Success!",
|
||||||
});
|
message: () => "Cycle added to favorites.",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
title: "Error!",
|
||||||
|
message: () => "Couldn't add the cycle to favorites. Please try again.",
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveFromFavorites = (e: MouseEvent<HTMLButtonElement>) => {
|
const handleRemoveFromFavorites = (e: MouseEvent<HTMLButtonElement>) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
|
||||||
removeCycleFromFavorites(workspaceSlug?.toString(), projectId.toString(), cycleId)
|
const removeFromFavoritePromise = removeCycleFromFavorites(
|
||||||
.then(() => {
|
workspaceSlug?.toString(),
|
||||||
captureEvent(CYCLE_UNFAVORITED, {
|
projectId.toString(),
|
||||||
cycle_id: cycleId,
|
cycleId
|
||||||
element: "List layout",
|
).then(() => {
|
||||||
state: "SUCCESS",
|
captureEvent(CYCLE_UNFAVORITED, {
|
||||||
});
|
cycle_id: cycleId,
|
||||||
})
|
element: "List layout",
|
||||||
.catch(() => {
|
state: "SUCCESS",
|
||||||
setToastAlert({
|
|
||||||
type: "error",
|
|
||||||
title: "Error!",
|
|
||||||
message: "Couldn't add the cycle to favorites. Please try again.",
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
setPromiseToast(removeFromFavoritePromise, {
|
||||||
|
loading: "Removing cycle from favorites...",
|
||||||
|
success: {
|
||||||
|
title: "Success!",
|
||||||
|
message: () => "Cycle removed from favorites.",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
title: "Error!",
|
||||||
|
message: () => "Couldn't remove the cycle from favorites. Please try again.",
|
||||||
|
},
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEditCycle = (e: MouseEvent<HTMLButtonElement>) => {
|
const handleEditCycle = (e: MouseEvent<HTMLButtonElement>) => {
|
||||||
|
@ -5,9 +5,8 @@ import { observer } from "mobx-react-lite";
|
|||||||
import { AlertTriangle } from "lucide-react";
|
import { AlertTriangle } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEventTracker, useCycle } from "hooks/store";
|
import { useEventTracker, useCycle } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// components
|
// components
|
||||||
import { Button } from "@plane/ui";
|
import { Button, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { ICycle } from "@plane/types";
|
import { ICycle } from "@plane/types";
|
||||||
// constants
|
// constants
|
||||||
@ -31,8 +30,6 @@ export const CycleDeleteModal: React.FC<ICycleDelete> = observer((props) => {
|
|||||||
// store hooks
|
// store hooks
|
||||||
const { captureCycleEvent } = useEventTracker();
|
const { captureCycleEvent } = useEventTracker();
|
||||||
const { deleteCycle } = useCycle();
|
const { deleteCycle } = useCycle();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const formSubmit = async () => {
|
const formSubmit = async () => {
|
||||||
if (!cycle) return;
|
if (!cycle) return;
|
||||||
@ -41,8 +38,8 @@ export const CycleDeleteModal: React.FC<ICycleDelete> = observer((props) => {
|
|||||||
try {
|
try {
|
||||||
await deleteCycle(workspaceSlug, projectId, cycle.id)
|
await deleteCycle(workspaceSlug, projectId, cycle.id)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Cycle deleted successfully.",
|
message: "Cycle deleted successfully.",
|
||||||
});
|
});
|
||||||
@ -62,8 +59,8 @@ export const CycleDeleteModal: React.FC<ICycleDelete> = observer((props) => {
|
|||||||
|
|
||||||
handleClose();
|
handleClose();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Warning!",
|
title: "Warning!",
|
||||||
message: "Something went wrong please try again later.",
|
message: "Something went wrong please try again later.",
|
||||||
});
|
});
|
||||||
|
@ -4,10 +4,11 @@ import { Dialog, Transition } from "@headlessui/react";
|
|||||||
import { CycleService } from "services/cycle.service";
|
import { CycleService } from "services/cycle.service";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEventTracker, useCycle, useProject } from "hooks/store";
|
import { useEventTracker, useCycle, useProject } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import useLocalStorage from "hooks/use-local-storage";
|
import useLocalStorage from "hooks/use-local-storage";
|
||||||
// components
|
// components
|
||||||
import { CycleForm } from "components/cycles";
|
import { CycleForm } from "components/cycles";
|
||||||
|
// ui
|
||||||
|
import { TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import type { CycleDateCheckData, ICycle, TCycleView } from "@plane/types";
|
import type { CycleDateCheckData, ICycle, TCycleView } from "@plane/types";
|
||||||
// constants
|
// constants
|
||||||
@ -32,8 +33,6 @@ export const CycleCreateUpdateModal: React.FC<CycleModalProps> = (props) => {
|
|||||||
const { captureCycleEvent } = useEventTracker();
|
const { captureCycleEvent } = useEventTracker();
|
||||||
const { workspaceProjectIds } = useProject();
|
const { workspaceProjectIds } = useProject();
|
||||||
const { createCycle, updateCycleDetails } = useCycle();
|
const { createCycle, updateCycleDetails } = useCycle();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const { setValue: setCycleTab } = useLocalStorage<TCycleView>("cycle_tab", "active");
|
const { setValue: setCycleTab } = useLocalStorage<TCycleView>("cycle_tab", "active");
|
||||||
|
|
||||||
@ -43,8 +42,8 @@ export const CycleCreateUpdateModal: React.FC<CycleModalProps> = (props) => {
|
|||||||
const selectedProjectId = payload.project_id ?? projectId.toString();
|
const selectedProjectId = payload.project_id ?? projectId.toString();
|
||||||
await createCycle(workspaceSlug, selectedProjectId, payload)
|
await createCycle(workspaceSlug, selectedProjectId, payload)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Cycle created successfully.",
|
message: "Cycle created successfully.",
|
||||||
});
|
});
|
||||||
@ -54,8 +53,8 @@ export const CycleCreateUpdateModal: React.FC<CycleModalProps> = (props) => {
|
|||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err.detail ?? "Error in creating cycle. Please try again.",
|
message: err.detail ?? "Error in creating cycle. Please try again.",
|
||||||
});
|
});
|
||||||
@ -77,8 +76,8 @@ export const CycleCreateUpdateModal: React.FC<CycleModalProps> = (props) => {
|
|||||||
eventName: CYCLE_UPDATED,
|
eventName: CYCLE_UPDATED,
|
||||||
payload: { ...res, changed_properties: changed_properties, state: "SUCCESS" },
|
payload: { ...res, changed_properties: changed_properties, state: "SUCCESS" },
|
||||||
});
|
});
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Cycle updated successfully.",
|
message: "Cycle updated successfully.",
|
||||||
});
|
});
|
||||||
@ -88,8 +87,8 @@ export const CycleCreateUpdateModal: React.FC<CycleModalProps> = (props) => {
|
|||||||
eventName: CYCLE_UPDATED,
|
eventName: CYCLE_UPDATED,
|
||||||
payload: { ...payload, state: "FAILED" },
|
payload: { ...payload, state: "FAILED" },
|
||||||
});
|
});
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err.detail ?? "Error in updating cycle. Please try again.",
|
message: err.detail ?? "Error in updating cycle. Please try again.",
|
||||||
});
|
});
|
||||||
@ -138,8 +137,8 @@ export const CycleCreateUpdateModal: React.FC<CycleModalProps> = (props) => {
|
|||||||
}
|
}
|
||||||
handleClose();
|
handleClose();
|
||||||
} else
|
} else
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "You already have a cycle on the given dates, if you want to create a draft cycle, remove the dates.",
|
message: "You already have a cycle on the given dates, if you want to create a draft cycle, remove the dates.",
|
||||||
});
|
});
|
||||||
|
@ -8,13 +8,12 @@ import isEmpty from "lodash/isEmpty";
|
|||||||
import { CycleService } from "services/cycle.service";
|
import { CycleService } from "services/cycle.service";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEventTracker, useCycle, useUser, useMember } from "hooks/store";
|
import { useEventTracker, useCycle, useUser, useMember } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// components
|
// components
|
||||||
import { SidebarProgressStats } from "components/core";
|
import { SidebarProgressStats } from "components/core";
|
||||||
import ProgressChart from "components/core/sidebar/progress-chart";
|
import ProgressChart from "components/core/sidebar/progress-chart";
|
||||||
import { CycleDeleteModal } from "components/cycles/delete-modal";
|
import { CycleDeleteModal } from "components/cycles/delete-modal";
|
||||||
// ui
|
// ui
|
||||||
import { Avatar, CustomMenu, Loader, LayersIcon } from "@plane/ui";
|
import { Avatar, CustomMenu, Loader, LayersIcon, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// icons
|
// icons
|
||||||
import { ChevronDown, LinkIcon, Trash2, UserCircle2, AlertCircle, ChevronRight, CalendarClock } from "lucide-react";
|
import { ChevronDown, LinkIcon, Trash2, UserCircle2, AlertCircle, ChevronRight, CalendarClock } from "lucide-react";
|
||||||
// helpers
|
// helpers
|
||||||
@ -60,8 +59,6 @@ export const CycleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
// derived values
|
// derived values
|
||||||
const cycleDetails = getCycleById(cycleId);
|
const cycleDetails = getCycleById(cycleId);
|
||||||
const cycleOwnerDetails = cycleDetails ? getUserDetails(cycleDetails.owned_by_id) : undefined;
|
const cycleOwnerDetails = cycleDetails ? getUserDetails(cycleDetails.owned_by_id) : undefined;
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// form info
|
// form info
|
||||||
const { control, reset } = useForm({
|
const { control, reset } = useForm({
|
||||||
defaultValues,
|
defaultValues,
|
||||||
@ -98,15 +95,15 @@ export const CycleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
const handleCopyText = () => {
|
const handleCopyText = () => {
|
||||||
copyUrlToClipboard(`${workspaceSlug}/projects/${projectId}/cycles/${cycleId}`)
|
copyUrlToClipboard(`${workspaceSlug}/projects/${projectId}/cycles/${cycleId}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Link Copied!",
|
title: "Link Copied!",
|
||||||
message: "Cycle link copied to clipboard.",
|
message: "Cycle link copied to clipboard.",
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Some error occurred",
|
title: "Some error occurred",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -147,14 +144,14 @@ export const CycleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
|
|
||||||
if (isDateValid) {
|
if (isDateValid) {
|
||||||
submitChanges(payload, "date_range");
|
submitChanges(payload, "date_range");
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Cycle updated successfully.",
|
message: "Cycle updated successfully.",
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message:
|
message:
|
||||||
"You already have a cycle on the given dates, if you want to create a draft cycle, you can do that by removing both the dates.",
|
"You already have a cycle on the given dates, if you want to create a draft cycle, you can do that by removing both the dates.",
|
||||||
|
@ -3,10 +3,10 @@ import { useRouter } from "next/router";
|
|||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import { useCycle, useIssues } from "hooks/store";
|
import { useCycle, useIssues } from "hooks/store";
|
||||||
|
// ui
|
||||||
|
import { ContrastIcon, TransferIcon, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
//icons
|
//icons
|
||||||
import { ContrastIcon, TransferIcon } from "@plane/ui";
|
|
||||||
import { AlertCircle, Search, X } from "lucide-react";
|
import { AlertCircle, Search, X } from "lucide-react";
|
||||||
// constants
|
// constants
|
||||||
import { EIssuesStoreType } from "constants/issue";
|
import { EIssuesStoreType } from "constants/issue";
|
||||||
@ -30,23 +30,21 @@ export const TransferIssuesModal: React.FC<Props> = observer((props) => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, cycleId } = router.query;
|
const { workspaceSlug, projectId, cycleId } = router.query;
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const transferIssue = async (payload: any) => {
|
const transferIssue = async (payload: any) => {
|
||||||
if (!workspaceSlug || !projectId || !cycleId) return;
|
if (!workspaceSlug || !projectId || !cycleId) return;
|
||||||
|
|
||||||
// TODO: import transferIssuesFromCycle from store
|
// TODO: import transferIssuesFromCycle from store
|
||||||
await transferIssuesFromCycle(workspaceSlug.toString(), projectId.toString(), cycleId.toString(), payload)
|
await transferIssuesFromCycle(workspaceSlug.toString(), projectId.toString(), cycleId.toString(), payload)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Issues transferred successfully",
|
title: "Issues transferred successfully",
|
||||||
message: "Issues have been transferred successfully",
|
message: "Issues have been transferred successfully",
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Issues cannot be transfer. Please try again.",
|
message: "Issues cannot be transfer. Please try again.",
|
||||||
});
|
});
|
||||||
|
@ -5,9 +5,8 @@ import { Dialog, Transition } from "@headlessui/react";
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// store hooks
|
// store hooks
|
||||||
import { useEstimate } from "hooks/store";
|
import { useEstimate } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input, TextArea } from "@plane/ui";
|
import { Button, Input, TextArea, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { checkDuplicates } from "helpers/array.helper";
|
import { checkDuplicates } from "helpers/array.helper";
|
||||||
// types
|
// types
|
||||||
@ -40,8 +39,6 @@ export const CreateUpdateEstimateModal: React.FC<Props> = observer((props) => {
|
|||||||
// store hooks
|
// store hooks
|
||||||
const { createEstimate, updateEstimate } = useEstimate();
|
const { createEstimate, updateEstimate } = useEstimate();
|
||||||
// form info
|
// form info
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
const {
|
const {
|
||||||
formState: { errors, isSubmitting },
|
formState: { errors, isSubmitting },
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@ -67,8 +64,8 @@ export const CreateUpdateEstimateModal: React.FC<Props> = observer((props) => {
|
|||||||
const error = err?.error;
|
const error = err?.error;
|
||||||
const errorString = Array.isArray(error) ? error[0] : error;
|
const errorString = Array.isArray(error) ? error[0] : error;
|
||||||
|
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message:
|
message:
|
||||||
errorString ?? err.status === 400
|
errorString ?? err.status === 400
|
||||||
@ -89,8 +86,8 @@ export const CreateUpdateEstimateModal: React.FC<Props> = observer((props) => {
|
|||||||
const error = err?.error;
|
const error = err?.error;
|
||||||
const errorString = Array.isArray(error) ? error[0] : error;
|
const errorString = Array.isArray(error) ? error[0] : error;
|
||||||
|
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: errorString ?? "Estimate could not be updated. Please try again.",
|
message: errorString ?? "Estimate could not be updated. Please try again.",
|
||||||
});
|
});
|
||||||
@ -99,8 +96,8 @@ export const CreateUpdateEstimateModal: React.FC<Props> = observer((props) => {
|
|||||||
|
|
||||||
const onSubmit = async (formData: FormValues) => {
|
const onSubmit = async (formData: FormValues) => {
|
||||||
if (!formData.name || formData.name === "") {
|
if (!formData.name || formData.name === "") {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Estimate title cannot be empty.",
|
message: "Estimate title cannot be empty.",
|
||||||
});
|
});
|
||||||
@ -115,8 +112,8 @@ export const CreateUpdateEstimateModal: React.FC<Props> = observer((props) => {
|
|||||||
formData.value5 === "" ||
|
formData.value5 === "" ||
|
||||||
formData.value6 === ""
|
formData.value6 === ""
|
||||||
) {
|
) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Estimate point cannot be empty.",
|
message: "Estimate point cannot be empty.",
|
||||||
});
|
});
|
||||||
@ -131,8 +128,8 @@ export const CreateUpdateEstimateModal: React.FC<Props> = observer((props) => {
|
|||||||
formData.value5.length > 20 ||
|
formData.value5.length > 20 ||
|
||||||
formData.value6.length > 20
|
formData.value6.length > 20
|
||||||
) {
|
) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Estimate point cannot have more than 20 characters.",
|
message: "Estimate point cannot have more than 20 characters.",
|
||||||
});
|
});
|
||||||
@ -149,8 +146,8 @@ export const CreateUpdateEstimateModal: React.FC<Props> = observer((props) => {
|
|||||||
formData.value6,
|
formData.value6,
|
||||||
])
|
])
|
||||||
) {
|
) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Estimate points cannot have duplicate values.",
|
message: "Estimate points cannot have duplicate values.",
|
||||||
});
|
});
|
||||||
|
@ -5,11 +5,10 @@ import { observer } from "mobx-react-lite";
|
|||||||
import { AlertTriangle } from "lucide-react";
|
import { AlertTriangle } from "lucide-react";
|
||||||
// store hooks
|
// store hooks
|
||||||
import { useEstimate } from "hooks/store";
|
import { useEstimate } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// types
|
// types
|
||||||
import { IEstimate } from "@plane/types";
|
import { IEstimate } from "@plane/types";
|
||||||
// ui
|
// ui
|
||||||
import { Button } from "@plane/ui";
|
import { Button, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@ -26,8 +25,6 @@ export const DeleteEstimateModal: React.FC<Props> = observer((props) => {
|
|||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
// store hooks
|
// store hooks
|
||||||
const { deleteEstimate } = useEstimate();
|
const { deleteEstimate } = useEstimate();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const handleEstimateDelete = () => {
|
const handleEstimateDelete = () => {
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
@ -43,8 +40,8 @@ export const DeleteEstimateModal: React.FC<Props> = observer((props) => {
|
|||||||
const error = err?.error;
|
const error = err?.error;
|
||||||
const errorString = Array.isArray(error) ? error[0] : error;
|
const errorString = Array.isArray(error) ? error[0] : error;
|
||||||
|
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: errorString ?? "Estimate could not be deleted. Please try again",
|
message: errorString ?? "Estimate could not be deleted. Please try again",
|
||||||
});
|
});
|
||||||
|
@ -3,9 +3,8 @@ import { useRouter } from "next/router";
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// hooks
|
// hooks
|
||||||
import { useProject } from "hooks/store";
|
import { useProject } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { Button, CustomMenu } from "@plane/ui";
|
import { Button, CustomMenu, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
//icons
|
//icons
|
||||||
import { Pencil, Trash2 } from "lucide-react";
|
import { Pencil, Trash2 } from "lucide-react";
|
||||||
// helpers
|
// helpers
|
||||||
@ -26,8 +25,6 @@ export const EstimateListItem: React.FC<Props> = observer((props) => {
|
|||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
// store hooks
|
// store hooks
|
||||||
const { currentProjectDetails, updateProject } = useProject();
|
const { currentProjectDetails, updateProject } = useProject();
|
||||||
// hooks
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const handleUseEstimate = async () => {
|
const handleUseEstimate = async () => {
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
@ -38,8 +35,8 @@ export const EstimateListItem: React.FC<Props> = observer((props) => {
|
|||||||
const error = err?.error;
|
const error = err?.error;
|
||||||
const errorString = Array.isArray(error) ? error[0] : error;
|
const errorString = Array.isArray(error) ? error[0] : error;
|
||||||
|
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: errorString ?? "Estimate points could not be used. Please try again.",
|
message: errorString ?? "Estimate points could not be used. Please try again.",
|
||||||
});
|
});
|
||||||
|
@ -4,12 +4,11 @@ import { observer } from "mobx-react-lite";
|
|||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
// store hooks
|
// store hooks
|
||||||
import { useEstimate, useProject, useUser } from "hooks/store";
|
import { useEstimate, useProject, useUser } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// components
|
// components
|
||||||
import { CreateUpdateEstimateModal, DeleteEstimateModal, EstimateListItem } from "components/estimates";
|
import { CreateUpdateEstimateModal, DeleteEstimateModal, EstimateListItem } from "components/estimates";
|
||||||
import { EmptyState, getEmptyStateImagePath } from "components/empty-state";
|
import { EmptyState, getEmptyStateImagePath } from "components/empty-state";
|
||||||
// ui
|
// ui
|
||||||
import { Button, Loader } from "@plane/ui";
|
import { Button, Loader, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { IEstimate } from "@plane/types";
|
import { IEstimate } from "@plane/types";
|
||||||
// helpers
|
// helpers
|
||||||
@ -31,8 +30,6 @@ export const EstimatesList: React.FC = observer(() => {
|
|||||||
const { updateProject, currentProjectDetails } = useProject();
|
const { updateProject, currentProjectDetails } = useProject();
|
||||||
const { projectEstimates, getProjectEstimateById } = useEstimate();
|
const { projectEstimates, getProjectEstimateById } = useEstimate();
|
||||||
const { currentUser } = useUser();
|
const { currentUser } = useUser();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const editEstimate = (estimate: IEstimate) => {
|
const editEstimate = (estimate: IEstimate) => {
|
||||||
setEstimateFormOpen(true);
|
setEstimateFormOpen(true);
|
||||||
@ -50,8 +47,8 @@ export const EstimatesList: React.FC = observer(() => {
|
|||||||
const error = err?.error;
|
const error = err?.error;
|
||||||
const errorString = Array.isArray(error) ? error[0] : error;
|
const errorString = Array.isArray(error) ? error[0] : error;
|
||||||
|
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: errorString ?? "Estimate could not be disabled. Please try again",
|
message: errorString ?? "Estimate could not be disabled. Please try again",
|
||||||
});
|
});
|
||||||
|
@ -6,10 +6,8 @@ import { Dialog, Transition } from "@headlessui/react";
|
|||||||
import { useProject } from "hooks/store";
|
import { useProject } from "hooks/store";
|
||||||
// services
|
// services
|
||||||
import { ProjectExportService } from "services/project";
|
import { ProjectExportService } from "services/project";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { Button, CustomSearchSelect } from "@plane/ui";
|
import { Button, CustomSearchSelect, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { IUser, IImporterService } from "@plane/types";
|
import { IUser, IImporterService } from "@plane/types";
|
||||||
|
|
||||||
@ -34,8 +32,6 @@ export const Exporter: React.FC<Props> = observer((props) => {
|
|||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
// store hooks
|
// store hooks
|
||||||
const { workspaceProjectIds, getProjectById } = useProject();
|
const { workspaceProjectIds, getProjectById } = useProject();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const options = workspaceProjectIds?.map((projectId) => {
|
const options = workspaceProjectIds?.map((projectId) => {
|
||||||
const projectDetails = getProjectById(projectId);
|
const projectDetails = getProjectById(projectId);
|
||||||
@ -71,8 +67,8 @@ export const Exporter: React.FC<Props> = observer((props) => {
|
|||||||
mutateServices();
|
mutateServices();
|
||||||
router.push(`/${workspaceSlug}/settings/exports`);
|
router.push(`/${workspaceSlug}/settings/exports`);
|
||||||
setExportLoading(false);
|
setExportLoading(false);
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Export Successful",
|
title: "Export Successful",
|
||||||
message: `You will be able to download the exported ${
|
message: `You will be able to download the exported ${
|
||||||
provider === "csv" ? "CSV" : provider === "xlsx" ? "Excel" : provider === "json" ? "JSON" : ""
|
provider === "csv" ? "CSV" : provider === "xlsx" ? "Excel" : provider === "json" ? "JSON" : ""
|
||||||
@ -81,8 +77,8 @@ export const Exporter: React.FC<Props> = observer((props) => {
|
|||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
setExportLoading(false);
|
setExportLoading(false);
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Export was unsuccessful. Please try again.",
|
message: "Export was unsuccessful. Please try again.",
|
||||||
});
|
});
|
||||||
|
@ -5,7 +5,6 @@ import { DayPicker } from "react-day-picker";
|
|||||||
import { Popover } from "@headlessui/react";
|
import { Popover } from "@headlessui/react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useUser, useInboxIssues, useIssueDetail, useWorkspace, useEventTracker } from "hooks/store";
|
import { useUser, useInboxIssues, useIssueDetail, useWorkspace, useEventTracker } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// components
|
// components
|
||||||
import {
|
import {
|
||||||
AcceptIssueModal,
|
AcceptIssueModal,
|
||||||
@ -14,7 +13,7 @@ import {
|
|||||||
SelectDuplicateInboxIssueModal,
|
SelectDuplicateInboxIssueModal,
|
||||||
} from "components/inbox";
|
} from "components/inbox";
|
||||||
// ui
|
// ui
|
||||||
import { Button } from "@plane/ui";
|
import { Button, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// icons
|
// icons
|
||||||
import { CheckCircle2, ChevronDown, ChevronUp, Clock, FileStack, Trash2, XCircle } from "lucide-react";
|
import { CheckCircle2, ChevronDown, ChevronUp, Clock, FileStack, Trash2, XCircle } from "lucide-react";
|
||||||
// types
|
// types
|
||||||
@ -51,7 +50,6 @@ export const InboxIssueActionsHeader: FC<TInboxIssueActionsHeader> = observer((p
|
|||||||
currentUser,
|
currentUser,
|
||||||
membership: { currentProjectRole },
|
membership: { currentProjectRole },
|
||||||
} = useUser();
|
} = useUser();
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
// states
|
// states
|
||||||
const [date, setDate] = useState(new Date());
|
const [date, setDate] = useState(new Date());
|
||||||
@ -74,8 +72,8 @@ export const InboxIssueActionsHeader: FC<TInboxIssueActionsHeader> = observer((p
|
|||||||
if (!workspaceSlug || !projectId || !inboxId || !inboxIssueId) throw new Error("Missing required parameters");
|
if (!workspaceSlug || !projectId || !inboxId || !inboxIssueId) throw new Error("Missing required parameters");
|
||||||
await updateInboxIssueStatus(workspaceSlug, projectId, inboxId, inboxIssueId, data);
|
await updateInboxIssueStatus(workspaceSlug, projectId, inboxId, inboxIssueId, data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Something went wrong while updating inbox status. Please try again.",
|
message: "Something went wrong while updating inbox status. Please try again.",
|
||||||
});
|
});
|
||||||
@ -98,8 +96,8 @@ export const InboxIssueActionsHeader: FC<TInboxIssueActionsHeader> = observer((p
|
|||||||
pathname: `/${workspaceSlug}/projects/${projectId}/inbox/${inboxId}`,
|
pathname: `/${workspaceSlug}/projects/${projectId}/inbox/${inboxId}`,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Something went wrong while deleting inbox issue. Please try again.",
|
message: "Something went wrong while deleting inbox issue. Please try again.",
|
||||||
});
|
});
|
||||||
@ -122,7 +120,6 @@ export const InboxIssueActionsHeader: FC<TInboxIssueActionsHeader> = observer((p
|
|||||||
inboxIssueId,
|
inboxIssueId,
|
||||||
updateInboxIssueStatus,
|
updateInboxIssueStatus,
|
||||||
removeInboxIssue,
|
removeInboxIssue,
|
||||||
setToastAlert,
|
|
||||||
captureIssueEvent,
|
captureIssueEvent,
|
||||||
router,
|
router,
|
||||||
]
|
]
|
||||||
|
@ -7,7 +7,6 @@ import { RichTextEditorWithRef } from "@plane/rich-text-editor";
|
|||||||
import { Sparkle } from "lucide-react";
|
import { Sparkle } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useApplication, useEventTracker, useWorkspace, useInboxIssues, useMention } from "hooks/store";
|
import { useApplication, useEventTracker, useWorkspace, useInboxIssues, useMention } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// services
|
// services
|
||||||
import { FileService } from "services/file.service";
|
import { FileService } from "services/file.service";
|
||||||
import { AIService } from "services/ai.service";
|
import { AIService } from "services/ai.service";
|
||||||
@ -15,7 +14,7 @@ import { AIService } from "services/ai.service";
|
|||||||
import { PriorityDropdown } from "components/dropdowns";
|
import { PriorityDropdown } from "components/dropdowns";
|
||||||
import { GptAssistantPopover } from "components/core";
|
import { GptAssistantPopover } from "components/core";
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input, ToggleSwitch } from "@plane/ui";
|
import { Button, Input, ToggleSwitch, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { TIssue } from "@plane/types";
|
import { TIssue } from "@plane/types";
|
||||||
// constants
|
// constants
|
||||||
@ -46,9 +45,6 @@ export const CreateInboxIssueModal: React.FC<Props> = observer((props) => {
|
|||||||
const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false);
|
const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false);
|
||||||
// refs
|
// refs
|
||||||
const editorRef = useRef<any>(null);
|
const editorRef = useRef<any>(null);
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
const { mentionHighlights, mentionSuggestions } = useMention();
|
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, inboxId } = router.query as {
|
const { workspaceSlug, projectId, inboxId } = router.query as {
|
||||||
@ -56,6 +52,8 @@ export const CreateInboxIssueModal: React.FC<Props> = observer((props) => {
|
|||||||
projectId: string;
|
projectId: string;
|
||||||
inboxId: string;
|
inboxId: string;
|
||||||
};
|
};
|
||||||
|
// hooks
|
||||||
|
const { mentionHighlights, mentionSuggestions } = useMention();
|
||||||
const workspaceStore = useWorkspace();
|
const workspaceStore = useWorkspace();
|
||||||
const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug as string)?.id as string;
|
const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug as string)?.id as string;
|
||||||
|
|
||||||
@ -138,8 +136,8 @@ export const CreateInboxIssueModal: React.FC<Props> = observer((props) => {
|
|||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.response === "")
|
if (res.response === "")
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message:
|
message:
|
||||||
"Issue title isn't informative enough to generate the description. Please try with a different title.",
|
"Issue title isn't informative enough to generate the description. Please try with a different title.",
|
||||||
@ -150,14 +148,14 @@ export const CreateInboxIssueModal: React.FC<Props> = observer((props) => {
|
|||||||
const error = err?.data?.error;
|
const error = err?.data?.error;
|
||||||
|
|
||||||
if (err.status === 429)
|
if (err.status === 429)
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: error || "You have reached the maximum number of requests of 50 requests per month per user.",
|
message: error || "You have reached the maximum number of requests of 50 requests per month per user.",
|
||||||
});
|
});
|
||||||
else
|
else
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: error || "Some error occurred. Please try again.",
|
message: error || "Some error occurred. Please try again.",
|
||||||
});
|
});
|
||||||
|
@ -2,13 +2,10 @@ import React, { useEffect, useState } from "react";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { Combobox, Dialog, Transition } from "@headlessui/react";
|
import { Combobox, Dialog, Transition } from "@headlessui/react";
|
||||||
|
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// services
|
// services
|
||||||
import { IssueService } from "services/issue";
|
import { IssueService } from "services/issue";
|
||||||
// ui
|
// ui
|
||||||
import { Button, LayersIcon } from "@plane/ui";
|
import { Button, LayersIcon, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// icons
|
// icons
|
||||||
import { Search } from "lucide-react";
|
import { Search } from "lucide-react";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
@ -30,8 +27,6 @@ export const SelectDuplicateInboxIssueModal: React.FC<Props> = (props) => {
|
|||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
const [selectedItem, setSelectedItem] = useState<string>("");
|
const [selectedItem, setSelectedItem] = useState<string>("");
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, issueId } = router.query;
|
const { workspaceSlug, projectId, issueId } = router.query;
|
||||||
|
|
||||||
@ -62,9 +57,9 @@ export const SelectDuplicateInboxIssueModal: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
if (!selectedItem || selectedItem.length === 0)
|
if (!selectedItem || selectedItem.length === 0)
|
||||||
return setToastAlert({
|
return setToast({
|
||||||
title: "Error",
|
title: "Error",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
});
|
});
|
||||||
onSubmit(selectedItem);
|
onSubmit(selectedItem);
|
||||||
handleClose();
|
handleClose();
|
||||||
|
@ -2,12 +2,11 @@ import { FC, useState } from "react";
|
|||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { Eye, EyeOff } from "lucide-react";
|
import { Eye, EyeOff } from "lucide-react";
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { IFormattedInstanceConfiguration } from "@plane/types";
|
import { IFormattedInstanceConfiguration } from "@plane/types";
|
||||||
// hooks
|
// hooks
|
||||||
import { useApplication } from "hooks/store";
|
import { useApplication } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
|
|
||||||
export interface IInstanceAIForm {
|
export interface IInstanceAIForm {
|
||||||
config: IFormattedInstanceConfiguration;
|
config: IFormattedInstanceConfiguration;
|
||||||
@ -24,8 +23,6 @@ export const InstanceAIForm: FC<IInstanceAIForm> = (props) => {
|
|||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
// store
|
// store
|
||||||
const { instance: instanceStore } = useApplication();
|
const { instance: instanceStore } = useApplication();
|
||||||
// toast
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// form data
|
// form data
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@ -44,9 +41,9 @@ export const InstanceAIForm: FC<IInstanceAIForm> = (props) => {
|
|||||||
await instanceStore
|
await instanceStore
|
||||||
.updateInstanceConfigurations(payload)
|
.updateInstanceConfigurations(payload)
|
||||||
.then(() =>
|
.then(() =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Success",
|
title: "Success",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: "AI Settings updated successfully",
|
message: "AI Settings updated successfully",
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import { FC, useState } from "react";
|
import { FC, useState } from "react";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input, ToggleSwitch } from "@plane/ui";
|
import { Button, Input, ToggleSwitch, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
import { Eye, EyeOff } from "lucide-react";
|
import { Eye, EyeOff } from "lucide-react";
|
||||||
// types
|
// types
|
||||||
import { IFormattedInstanceConfiguration } from "@plane/types";
|
import { IFormattedInstanceConfiguration } from "@plane/types";
|
||||||
// hooks
|
// hooks
|
||||||
import { useApplication } from "hooks/store";
|
import { useApplication } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
|
|
||||||
export interface IInstanceEmailForm {
|
export interface IInstanceEmailForm {
|
||||||
config: IFormattedInstanceConfiguration;
|
config: IFormattedInstanceConfiguration;
|
||||||
@ -29,8 +28,6 @@ export const InstanceEmailForm: FC<IInstanceEmailForm> = (props) => {
|
|||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
// store hooks
|
// store hooks
|
||||||
const { instance: instanceStore } = useApplication();
|
const { instance: instanceStore } = useApplication();
|
||||||
// toast
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// form data
|
// form data
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@ -55,9 +52,9 @@ export const InstanceEmailForm: FC<IInstanceEmailForm> = (props) => {
|
|||||||
await instanceStore
|
await instanceStore
|
||||||
.updateInstanceConfigurations(payload)
|
.updateInstanceConfigurations(payload)
|
||||||
.then(() =>
|
.then(() =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Success",
|
title: "Success",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: "Email Settings updated successfully",
|
message: "Email Settings updated successfully",
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
import { FC } from "react";
|
import { FC } from "react";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { IInstance, IInstanceAdmin } from "@plane/types";
|
import { IInstance, IInstanceAdmin } from "@plane/types";
|
||||||
// hooks
|
// hooks
|
||||||
import { useApplication } from "hooks/store";
|
import { useApplication } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
|
|
||||||
export interface IInstanceGeneralForm {
|
export interface IInstanceGeneralForm {
|
||||||
instance: IInstance;
|
instance: IInstance;
|
||||||
@ -22,8 +21,6 @@ export const InstanceGeneralForm: FC<IInstanceGeneralForm> = (props) => {
|
|||||||
const { instance, instanceAdmins } = props;
|
const { instance, instanceAdmins } = props;
|
||||||
// store hooks
|
// store hooks
|
||||||
const { instance: instanceStore } = useApplication();
|
const { instance: instanceStore } = useApplication();
|
||||||
// toast
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// form data
|
// form data
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@ -42,9 +39,9 @@ export const InstanceGeneralForm: FC<IInstanceGeneralForm> = (props) => {
|
|||||||
await instanceStore
|
await instanceStore
|
||||||
.updateInstanceInfo(payload)
|
.updateInstanceInfo(payload)
|
||||||
.then(() =>
|
.then(() =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Success",
|
title: "Success",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: "Settings updated successfully",
|
message: "Settings updated successfully",
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -2,12 +2,11 @@ import { FC, useState } from "react";
|
|||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { Copy, Eye, EyeOff } from "lucide-react";
|
import { Copy, Eye, EyeOff } from "lucide-react";
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { IFormattedInstanceConfiguration } from "@plane/types";
|
import { IFormattedInstanceConfiguration } from "@plane/types";
|
||||||
// hooks
|
// hooks
|
||||||
import { useApplication } from "hooks/store";
|
import { useApplication } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
|
|
||||||
export interface IInstanceGithubConfigForm {
|
export interface IInstanceGithubConfigForm {
|
||||||
config: IFormattedInstanceConfiguration;
|
config: IFormattedInstanceConfiguration;
|
||||||
@ -24,8 +23,6 @@ export const InstanceGithubConfigForm: FC<IInstanceGithubConfigForm> = (props) =
|
|||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
// store hooks
|
// store hooks
|
||||||
const { instance: instanceStore } = useApplication();
|
const { instance: instanceStore } = useApplication();
|
||||||
// toast
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// form data
|
// form data
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@ -44,9 +41,9 @@ export const InstanceGithubConfigForm: FC<IInstanceGithubConfigForm> = (props) =
|
|||||||
await instanceStore
|
await instanceStore
|
||||||
.updateInstanceConfigurations(payload)
|
.updateInstanceConfigurations(payload)
|
||||||
.then(() =>
|
.then(() =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Success",
|
title: "Success",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: "Github Configuration Settings updated successfully",
|
message: "Github Configuration Settings updated successfully",
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@ -145,9 +142,9 @@ export const InstanceGithubConfigForm: FC<IInstanceGithubConfigForm> = (props) =
|
|||||||
className="flex items-center justify-between py-2"
|
className="flex items-center justify-between py-2"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigator.clipboard.writeText(originURL);
|
navigator.clipboard.writeText(originURL);
|
||||||
setToastAlert({
|
setToast({
|
||||||
message: "The Origin URL has been successfully copied to your clipboard",
|
message: "The Origin URL has been successfully copied to your clipboard",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Copied to clipboard",
|
title: "Copied to clipboard",
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
@ -2,12 +2,11 @@ import { FC } from "react";
|
|||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { Copy } from "lucide-react";
|
import { Copy } from "lucide-react";
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { IFormattedInstanceConfiguration } from "@plane/types";
|
import { IFormattedInstanceConfiguration } from "@plane/types";
|
||||||
// hooks
|
// hooks
|
||||||
import { useApplication } from "hooks/store";
|
import { useApplication } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
|
|
||||||
export interface IInstanceGoogleConfigForm {
|
export interface IInstanceGoogleConfigForm {
|
||||||
config: IFormattedInstanceConfiguration;
|
config: IFormattedInstanceConfiguration;
|
||||||
@ -22,8 +21,6 @@ export const InstanceGoogleConfigForm: FC<IInstanceGoogleConfigForm> = (props) =
|
|||||||
const { config } = props;
|
const { config } = props;
|
||||||
// store hooks
|
// store hooks
|
||||||
const { instance: instanceStore } = useApplication();
|
const { instance: instanceStore } = useApplication();
|
||||||
// toast
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// form data
|
// form data
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@ -42,9 +39,9 @@ export const InstanceGoogleConfigForm: FC<IInstanceGoogleConfigForm> = (props) =
|
|||||||
await instanceStore
|
await instanceStore
|
||||||
.updateInstanceConfigurations(payload)
|
.updateInstanceConfigurations(payload)
|
||||||
.then(() =>
|
.then(() =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Success",
|
title: "Success",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: "Google Configuration Settings updated successfully",
|
message: "Google Configuration Settings updated successfully",
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@ -94,9 +91,9 @@ export const InstanceGoogleConfigForm: FC<IInstanceGoogleConfigForm> = (props) =
|
|||||||
className="flex items-center justify-between py-2"
|
className="flex items-center justify-between py-2"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigator.clipboard.writeText(originURL);
|
navigator.clipboard.writeText(originURL);
|
||||||
setToastAlert({
|
setToast({
|
||||||
message: "The Origin URL has been successfully copied to your clipboard",
|
message: "The Origin URL has been successfully copied to your clipboard",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Copied to clipboard",
|
title: "Copied to clipboard",
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
@ -2,12 +2,11 @@ import { FC, useState } from "react";
|
|||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { Eye, EyeOff } from "lucide-react";
|
import { Eye, EyeOff } from "lucide-react";
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { IFormattedInstanceConfiguration } from "@plane/types";
|
import { IFormattedInstanceConfiguration } from "@plane/types";
|
||||||
// hooks
|
// hooks
|
||||||
import { useApplication } from "hooks/store";
|
import { useApplication } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
|
|
||||||
export interface IInstanceImageConfigForm {
|
export interface IInstanceImageConfigForm {
|
||||||
config: IFormattedInstanceConfiguration;
|
config: IFormattedInstanceConfiguration;
|
||||||
@ -23,8 +22,6 @@ export const InstanceImageConfigForm: FC<IInstanceImageConfigForm> = (props) =>
|
|||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
// store hooks
|
// store hooks
|
||||||
const { instance: instanceStore } = useApplication();
|
const { instance: instanceStore } = useApplication();
|
||||||
// toast
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// form data
|
// form data
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@ -42,9 +39,9 @@ export const InstanceImageConfigForm: FC<IInstanceImageConfigForm> = (props) =>
|
|||||||
await instanceStore
|
await instanceStore
|
||||||
.updateInstanceConfigurations(payload)
|
.updateInstanceConfigurations(payload)
|
||||||
.then(() =>
|
.then(() =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Success",
|
title: "Success",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: "Image Configuration Settings updated successfully",
|
message: "Image Configuration Settings updated successfully",
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -4,12 +4,10 @@ import { Eye, EyeOff, XCircle } from "lucide-react";
|
|||||||
// hooks
|
// hooks
|
||||||
import { useUser } from "hooks/store";
|
import { useUser } from "hooks/store";
|
||||||
// ui
|
// ui
|
||||||
import { Input, Button } from "@plane/ui";
|
import { Input, Button, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// services
|
// services
|
||||||
import { AuthService } from "services/auth.service";
|
import { AuthService } from "services/auth.service";
|
||||||
const authService = new AuthService();
|
const authService = new AuthService();
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// helpers
|
// helpers
|
||||||
import { checkEmailValidity } from "helpers/string.helper";
|
import { checkEmailValidity } from "helpers/string.helper";
|
||||||
|
|
||||||
@ -40,8 +38,6 @@ export const InstanceSetupSignInForm: FC<IInstanceSetupEmailForm> = (props) => {
|
|||||||
password: "",
|
password: "",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
// hooks
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const handleFormSubmit = async (formValues: InstanceSetupEmailFormValues) => {
|
const handleFormSubmit = async (formValues: InstanceSetupEmailFormValues) => {
|
||||||
const payload = {
|
const payload = {
|
||||||
@ -56,8 +52,8 @@ export const InstanceSetupSignInForm: FC<IInstanceSetupEmailForm> = (props) => {
|
|||||||
handleNextStep(formValues.email);
|
handleNextStep(formValues.email);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: err?.error ?? "Something went wrong. Please try again.",
|
message: err?.error ?? "Something went wrong. Please try again.",
|
||||||
});
|
});
|
||||||
|
@ -10,10 +10,8 @@ import { Menu, Transition } from "@headlessui/react";
|
|||||||
import { LogIn, LogOut, Settings, UserCog2 } from "lucide-react";
|
import { LogIn, LogOut, Settings, UserCog2 } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useApplication, useUser } from "hooks/store";
|
import { useApplication, useUser } from "hooks/store";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { Avatar, Tooltip } from "@plane/ui";
|
import { Avatar, Tooltip, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
|
|
||||||
// Static Data
|
// Static Data
|
||||||
const PROFILE_LINKS = [
|
const PROFILE_LINKS = [
|
||||||
@ -35,7 +33,6 @@ export const InstanceSidebarDropdown = observer(() => {
|
|||||||
} = useApplication();
|
} = useApplication();
|
||||||
const { signOut, currentUser, currentUserSettings } = useUser();
|
const { signOut, currentUser, currentUserSettings } = useUser();
|
||||||
// hooks
|
// hooks
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
const { setTheme } = useTheme();
|
const { setTheme } = useTheme();
|
||||||
|
|
||||||
// redirect url for normal mode
|
// redirect url for normal mode
|
||||||
@ -53,8 +50,8 @@ export const InstanceSidebarDropdown = observer(() => {
|
|||||||
router.push("/");
|
router.push("/");
|
||||||
})
|
})
|
||||||
.catch(() =>
|
.catch(() =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Failed to sign out. Please try again.",
|
message: "Failed to sign out. Please try again.",
|
||||||
})
|
})
|
||||||
|
@ -8,10 +8,8 @@ import { mutate } from "swr";
|
|||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
// services
|
// services
|
||||||
import { IntegrationService } from "services/integrations/integration.service";
|
import { IntegrationService } from "services/integrations/integration.service";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// icons
|
// icons
|
||||||
import { AlertTriangle } from "lucide-react";
|
import { AlertTriangle } from "lucide-react";
|
||||||
// types
|
// types
|
||||||
@ -36,8 +34,6 @@ export const DeleteImportModal: React.FC<Props> = ({ isOpen, handleClose, data }
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const handleDeletion = () => {
|
const handleDeletion = () => {
|
||||||
if (!workspaceSlug || !data) return;
|
if (!workspaceSlug || !data) return;
|
||||||
|
|
||||||
@ -52,8 +48,8 @@ export const DeleteImportModal: React.FC<Props> = ({ isOpen, handleClose, data }
|
|||||||
integrationService
|
integrationService
|
||||||
.deleteImporterService(workspaceSlug as string, data.service, data.id)
|
.deleteImporterService(workspaceSlug as string, data.service, data.id)
|
||||||
.catch(() =>
|
.catch(() =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Something went wrong. Please try again.",
|
message: "Something went wrong. Please try again.",
|
||||||
})
|
})
|
||||||
|
@ -10,8 +10,6 @@ import useSWR, { mutate } from "swr";
|
|||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
// services
|
// services
|
||||||
import { IntegrationService, GithubIntegrationService } from "services/integrations";
|
import { IntegrationService, GithubIntegrationService } from "services/integrations";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// components
|
// components
|
||||||
import {
|
import {
|
||||||
GithubImportConfigure,
|
GithubImportConfigure,
|
||||||
@ -21,7 +19,7 @@ import {
|
|||||||
GithubImportConfirm,
|
GithubImportConfirm,
|
||||||
} from "components/integration";
|
} from "components/integration";
|
||||||
// icons
|
// icons
|
||||||
import { UserGroupIcon } from "@plane/ui";
|
import { UserGroupIcon, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
import { ArrowLeft, Check, List, Settings, UploadCloud } from "lucide-react";
|
import { ArrowLeft, Check, List, Settings, UploadCloud } from "lucide-react";
|
||||||
// images
|
// images
|
||||||
import GithubLogo from "public/services/github.png";
|
import GithubLogo from "public/services/github.png";
|
||||||
@ -92,8 +90,6 @@ export const GithubImporterRoot: React.FC = () => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, provider } = router.query;
|
const { workspaceSlug, provider } = router.query;
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const { handleSubmit, control, setValue, watch } = useForm<TFormValues>({
|
const { handleSubmit, control, setValue, watch } = useForm<TFormValues>({
|
||||||
defaultValues: defaultFormValues,
|
defaultValues: defaultFormValues,
|
||||||
});
|
});
|
||||||
@ -149,8 +145,8 @@ export const GithubImporterRoot: React.FC = () => {
|
|||||||
mutate(IMPORTER_SERVICES_LIST(workspaceSlug as string));
|
mutate(IMPORTER_SERVICES_LIST(workspaceSlug as string));
|
||||||
})
|
})
|
||||||
.catch(() =>
|
.catch(() =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Import was unsuccessful. Please try again.",
|
message: "Import was unsuccessful. Please try again.",
|
||||||
})
|
})
|
||||||
|
@ -8,10 +8,9 @@ import useSWR, { mutate } from "swr";
|
|||||||
import { IntegrationService } from "services/integrations";
|
import { IntegrationService } from "services/integrations";
|
||||||
// hooks
|
// hooks
|
||||||
import { useApplication, useUser } from "hooks/store";
|
import { useApplication, useUser } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import useIntegrationPopup from "hooks/use-integration-popup";
|
import useIntegrationPopup from "hooks/use-integration-popup";
|
||||||
// ui
|
// ui
|
||||||
import { Button, Loader, Tooltip } from "@plane/ui";
|
import { Button, Loader, Tooltip, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// icons
|
// icons
|
||||||
import GithubLogo from "public/services/github.png";
|
import GithubLogo from "public/services/github.png";
|
||||||
import SlackLogo from "public/services/slack.png";
|
import SlackLogo from "public/services/slack.png";
|
||||||
@ -54,8 +53,6 @@ export const SingleIntegrationCard: React.FC<Props> = observer(({ integration })
|
|||||||
const {
|
const {
|
||||||
membership: { currentWorkspaceRole },
|
membership: { currentWorkspaceRole },
|
||||||
} = useUser();
|
} = useUser();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const isUserAdmin = currentWorkspaceRole === 20;
|
const isUserAdmin = currentWorkspaceRole === 20;
|
||||||
|
|
||||||
@ -87,8 +84,8 @@ export const SingleIntegrationCard: React.FC<Props> = observer(({ integration })
|
|||||||
);
|
);
|
||||||
setDeletingIntegration(false);
|
setDeletingIntegration(false);
|
||||||
|
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Deleted successfully!",
|
title: "Deleted successfully!",
|
||||||
message: `${integration.title} integration deleted successfully.`,
|
message: `${integration.title} integration deleted successfully.`,
|
||||||
});
|
});
|
||||||
@ -96,8 +93,8 @@ export const SingleIntegrationCard: React.FC<Props> = observer(({ integration })
|
|||||||
.catch(() => {
|
.catch(() => {
|
||||||
setDeletingIntegration(false);
|
setDeletingIntegration(false);
|
||||||
|
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: `${integration.title} integration could not be deleted. Please try again.`,
|
message: `${integration.title} integration could not be deleted. Please try again.`,
|
||||||
});
|
});
|
||||||
|
@ -3,9 +3,8 @@ import { Dialog, Transition } from "@headlessui/react";
|
|||||||
// hooks
|
// hooks
|
||||||
import { useProject } from "hooks/store";
|
import { useProject } from "hooks/store";
|
||||||
import { useIssues } from "hooks/store/use-issues";
|
import { useIssues } from "hooks/store/use-issues";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { Button } from "@plane/ui";
|
import { Button, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { TIssue } from "@plane/types";
|
import { TIssue } from "@plane/types";
|
||||||
|
|
||||||
@ -24,8 +23,6 @@ export const ArchiveIssueModal: React.FC<Props> = (props) => {
|
|||||||
// store hooks
|
// store hooks
|
||||||
const { getProjectById } = useProject();
|
const { getProjectById } = useProject();
|
||||||
const { issueMap } = useIssues();
|
const { issueMap } = useIssues();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
if (!dataId && !data) return null;
|
if (!dataId && !data) return null;
|
||||||
|
|
||||||
@ -44,8 +41,8 @@ export const ArchiveIssueModal: React.FC<Props> = (props) => {
|
|||||||
await onSubmit()
|
await onSubmit()
|
||||||
.then(() => onClose())
|
.then(() => onClose())
|
||||||
.catch(() =>
|
.catch(() =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Issue could not be archived. Please try again.",
|
message: "Issue could not be archived. Please try again.",
|
||||||
})
|
})
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { FC, useMemo } from "react";
|
import { FC, useMemo } from "react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEventTracker, useIssueDetail } from "hooks/store";
|
import { useEventTracker, useIssueDetail } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
// ui
|
||||||
|
import { TOAST_TYPE, setPromiseToast, setToast } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { IssueAttachmentUpload } from "./attachment-upload";
|
import { IssueAttachmentUpload } from "./attachment-upload";
|
||||||
import { IssueAttachmentsList } from "./attachments-list";
|
import { IssueAttachmentsList } from "./attachments-list";
|
||||||
@ -24,19 +25,27 @@ export const IssueAttachmentRoot: FC<TIssueAttachmentRoot> = (props) => {
|
|||||||
// hooks
|
// hooks
|
||||||
const { createAttachment, removeAttachment } = useIssueDetail();
|
const { createAttachment, removeAttachment } = useIssueDetail();
|
||||||
const { captureIssueEvent } = useEventTracker();
|
const { captureIssueEvent } = useEventTracker();
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const handleAttachmentOperations: TAttachmentOperations = useMemo(
|
const handleAttachmentOperations: TAttachmentOperations = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
create: async (data: FormData) => {
|
create: async (data: FormData) => {
|
||||||
try {
|
try {
|
||||||
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing required fields");
|
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing required fields");
|
||||||
const res = await createAttachment(workspaceSlug, projectId, issueId, data);
|
|
||||||
setToastAlert({
|
const attachmentUploadPromise = createAttachment(workspaceSlug, projectId, issueId, data);
|
||||||
message: "The attachment has been successfully uploaded",
|
setPromiseToast(attachmentUploadPromise, {
|
||||||
type: "success",
|
loading: "Uploading attachment...",
|
||||||
title: "Attachment uploaded",
|
success: {
|
||||||
|
title: "Attachment uploaded",
|
||||||
|
message: () => "The attachment has been successfully uploaded",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
title: "Attachment not uploaded",
|
||||||
|
message: () => "The attachment could not be uploaded",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const res = await attachmentUploadPromise;
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
eventName: "Issue attachment added",
|
eventName: "Issue attachment added",
|
||||||
payload: { id: issueId, state: "SUCCESS", element: "Issue detail page" },
|
payload: { id: issueId, state: "SUCCESS", element: "Issue detail page" },
|
||||||
@ -50,20 +59,15 @@ export const IssueAttachmentRoot: FC<TIssueAttachmentRoot> = (props) => {
|
|||||||
eventName: "Issue attachment added",
|
eventName: "Issue attachment added",
|
||||||
payload: { id: issueId, state: "FAILED", element: "Issue detail page" },
|
payload: { id: issueId, state: "FAILED", element: "Issue detail page" },
|
||||||
});
|
});
|
||||||
setToastAlert({
|
|
||||||
message: "The attachment could not be uploaded",
|
|
||||||
type: "error",
|
|
||||||
title: "Attachment not uploaded",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
remove: async (attachmentId: string) => {
|
remove: async (attachmentId: string) => {
|
||||||
try {
|
try {
|
||||||
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing required fields");
|
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing required fields");
|
||||||
await removeAttachment(workspaceSlug, projectId, issueId, attachmentId);
|
await removeAttachment(workspaceSlug, projectId, issueId, attachmentId);
|
||||||
setToastAlert({
|
setToast({
|
||||||
message: "The attachment has been successfully removed",
|
message: "The attachment has been successfully removed",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Attachment removed",
|
title: "Attachment removed",
|
||||||
});
|
});
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
@ -83,15 +87,15 @@ export const IssueAttachmentRoot: FC<TIssueAttachmentRoot> = (props) => {
|
|||||||
change_details: "",
|
change_details: "",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
setToastAlert({
|
setToast({
|
||||||
message: "The Attachment could not be removed",
|
message: "The Attachment could not be removed",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Attachment not removed",
|
title: "Attachment not removed",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[workspaceSlug, projectId, issueId, createAttachment, removeAttachment, setToastAlert]
|
[workspaceSlug, projectId, issueId, createAttachment, removeAttachment]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -2,9 +2,7 @@ import { useEffect, useState, Fragment } from "react";
|
|||||||
import { Dialog, Transition } from "@headlessui/react";
|
import { Dialog, Transition } from "@headlessui/react";
|
||||||
import { AlertTriangle } from "lucide-react";
|
import { AlertTriangle } from "lucide-react";
|
||||||
// ui
|
// ui
|
||||||
import { Button } from "@plane/ui";
|
import { Button, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// types
|
// types
|
||||||
import { useIssues } from "hooks/store/use-issues";
|
import { useIssues } from "hooks/store/use-issues";
|
||||||
import { TIssue } from "@plane/types";
|
import { TIssue } from "@plane/types";
|
||||||
@ -25,7 +23,6 @@ export const DeleteIssueModal: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
const [isDeleting, setIsDeleting] = useState(false);
|
const [isDeleting, setIsDeleting] = useState(false);
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// hooks
|
// hooks
|
||||||
const { getProjectById } = useProject();
|
const { getProjectById } = useProject();
|
||||||
|
|
||||||
@ -50,9 +47,9 @@ export const DeleteIssueModal: React.FC<Props> = (props) => {
|
|||||||
onClose();
|
onClose();
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Error",
|
title: "Error",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
message: "Failed to delete issue",
|
message: "Failed to delete issue",
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
@ -71,16 +71,10 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = observer((props) => {
|
|||||||
async (formData: Partial<TIssue>) => {
|
async (formData: Partial<TIssue>) => {
|
||||||
if (!formData?.name || formData?.name.length === 0 || formData?.name.length > 255) return;
|
if (!formData?.name || formData?.name.length === 0 || formData?.name.length > 255) return;
|
||||||
|
|
||||||
await issueOperations.update(
|
await issueOperations.update(workspaceSlug, projectId, issueId, {
|
||||||
workspaceSlug,
|
name: formData.name ?? "",
|
||||||
projectId,
|
description_html: formData.description_html ?? "<p></p>",
|
||||||
issueId,
|
});
|
||||||
{
|
|
||||||
name: formData.name ?? "",
|
|
||||||
description_html: formData.description_html ?? "<p></p>",
|
|
||||||
},
|
|
||||||
false
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
[workspaceSlug, projectId, issueId, issueOperations]
|
[workspaceSlug, projectId, issueId, issueOperations]
|
||||||
);
|
);
|
||||||
|
@ -41,11 +41,9 @@ export const IssueDescriptionInput: FC<IssueDescriptionInputProps> = (props) =>
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (debouncedValue && debouncedValue !== value) {
|
if (debouncedValue && debouncedValue !== value) {
|
||||||
issueOperations
|
issueOperations.update(workspaceSlug, projectId, issueId, { description_html: debouncedValue }).finally(() => {
|
||||||
.update(workspaceSlug, projectId, issueId, { description_html: debouncedValue }, false)
|
setIsSubmitting("submitted");
|
||||||
.finally(() => {
|
});
|
||||||
setIsSubmitting("submitted");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
// DO NOT Add more dependencies here. It will cause multiple requests to be sent.
|
// DO NOT Add more dependencies here. It will cause multiple requests to be sent.
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
@ -56,7 +56,6 @@ export const IssueCycleSelect: React.FC<TIssueCycleSelect> = observer((props) =>
|
|||||||
dropdownArrow
|
dropdownArrow
|
||||||
dropdownArrowClassName="h-3.5 w-3.5 hidden group-hover:inline"
|
dropdownArrowClassName="h-3.5 w-3.5 hidden group-hover:inline"
|
||||||
/>
|
/>
|
||||||
{isUpdating && <Spinner className="h-4 w-4" />}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -6,7 +6,8 @@ import { InboxIssueMainContent } from "./main-content";
|
|||||||
import { InboxIssueDetailsSidebar } from "./sidebar";
|
import { InboxIssueDetailsSidebar } from "./sidebar";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEventTracker, useInboxIssues, useIssueDetail, useUser } from "hooks/store";
|
import { useEventTracker, useInboxIssues, useIssueDetail, useUser } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
// ui
|
||||||
|
import { TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { TIssue } from "@plane/types";
|
import { TIssue } from "@plane/types";
|
||||||
import { TIssueOperations } from "../root";
|
import { TIssueOperations } from "../root";
|
||||||
@ -34,7 +35,6 @@ export const InboxIssueDetailRoot: FC<TInboxIssueDetailRoot> = (props) => {
|
|||||||
fetchComments,
|
fetchComments,
|
||||||
} = useIssueDetail();
|
} = useIssueDetail();
|
||||||
const { captureIssueEvent } = useEventTracker();
|
const { captureIssueEvent } = useEventTracker();
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
const {
|
const {
|
||||||
membership: { currentProjectRole },
|
membership: { currentProjectRole },
|
||||||
} = useUser();
|
} = useUser();
|
||||||
@ -53,17 +53,9 @@ export const InboxIssueDetailRoot: FC<TInboxIssueDetailRoot> = (props) => {
|
|||||||
projectId: string,
|
projectId: string,
|
||||||
issueId: string,
|
issueId: string,
|
||||||
data: Partial<TIssue>,
|
data: Partial<TIssue>,
|
||||||
showToast: boolean = true
|
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
await updateInboxIssue(workspaceSlug, projectId, inboxId, issueId, data);
|
await updateInboxIssue(workspaceSlug, projectId, inboxId, issueId, data);
|
||||||
if (showToast) {
|
|
||||||
setToastAlert({
|
|
||||||
title: "Issue updated successfully",
|
|
||||||
type: "success",
|
|
||||||
message: "Issue updated successfully",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
eventName: "Inbox issue updated",
|
eventName: "Inbox issue updated",
|
||||||
payload: { ...data, state: "SUCCESS", element: "Inbox" },
|
payload: { ...data, state: "SUCCESS", element: "Inbox" },
|
||||||
@ -74,9 +66,9 @@ export const InboxIssueDetailRoot: FC<TInboxIssueDetailRoot> = (props) => {
|
|||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Issue update failed",
|
title: "Issue update failed",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
message: "Issue update failed",
|
message: "Issue update failed",
|
||||||
});
|
});
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
@ -93,9 +85,9 @@ export const InboxIssueDetailRoot: FC<TInboxIssueDetailRoot> = (props) => {
|
|||||||
remove: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
remove: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
||||||
try {
|
try {
|
||||||
await removeInboxIssue(workspaceSlug, projectId, inboxId, issueId);
|
await removeInboxIssue(workspaceSlug, projectId, inboxId, issueId);
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Issue deleted successfully",
|
title: "Issue deleted successfully",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: "Issue deleted successfully",
|
message: "Issue deleted successfully",
|
||||||
});
|
});
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
@ -109,15 +101,15 @@ export const InboxIssueDetailRoot: FC<TInboxIssueDetailRoot> = (props) => {
|
|||||||
payload: { id: issueId, state: "FAILED", element: "Inbox" },
|
payload: { id: issueId, state: "FAILED", element: "Inbox" },
|
||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Issue delete failed",
|
title: "Issue delete failed",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
message: "Issue delete failed",
|
message: "Issue delete failed",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[inboxId, fetchInboxIssueById, updateInboxIssue, removeInboxIssue, setToastAlert]
|
[inboxId, fetchInboxIssueById, updateInboxIssue, removeInboxIssue]
|
||||||
);
|
);
|
||||||
|
|
||||||
useSWR(
|
useSWR(
|
||||||
|
@ -3,7 +3,8 @@ import { observer } from "mobx-react-lite";
|
|||||||
import { History, LucideIcon, MessageCircle, ListRestart } from "lucide-react";
|
import { History, LucideIcon, MessageCircle, ListRestart } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useIssueDetail, useProject } from "hooks/store";
|
import { useIssueDetail, useProject } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
// ui
|
||||||
|
import { TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { IssueActivityCommentRoot, IssueActivityRoot, IssueCommentRoot, IssueCommentCreate } from "./";
|
import { IssueActivityCommentRoot, IssueActivityRoot, IssueCommentRoot, IssueCommentCreate } from "./";
|
||||||
// types
|
// types
|
||||||
@ -45,7 +46,6 @@ export const IssueActivity: FC<TIssueActivity> = observer((props) => {
|
|||||||
const { workspaceSlug, projectId, issueId } = props;
|
const { workspaceSlug, projectId, issueId } = props;
|
||||||
// hooks
|
// hooks
|
||||||
const { createComment, updateComment, removeComment } = useIssueDetail();
|
const { createComment, updateComment, removeComment } = useIssueDetail();
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
const { getProjectById } = useProject();
|
const { getProjectById } = useProject();
|
||||||
// state
|
// state
|
||||||
const [activityTab, setActivityTab] = useState<TActivityTabs>("all");
|
const [activityTab, setActivityTab] = useState<TActivityTabs>("all");
|
||||||
@ -56,15 +56,15 @@ export const IssueActivity: FC<TIssueActivity> = observer((props) => {
|
|||||||
try {
|
try {
|
||||||
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing fields");
|
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing fields");
|
||||||
await createComment(workspaceSlug, projectId, issueId, data);
|
await createComment(workspaceSlug, projectId, issueId, data);
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Comment created successfully.",
|
title: "Comment created successfully.",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: "Comment created successfully.",
|
message: "Comment created successfully.",
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Comment creation failed.",
|
title: "Comment creation failed.",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
message: "Comment creation failed. Please try again later.",
|
message: "Comment creation failed. Please try again later.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -73,15 +73,15 @@ export const IssueActivity: FC<TIssueActivity> = observer((props) => {
|
|||||||
try {
|
try {
|
||||||
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing fields");
|
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing fields");
|
||||||
await updateComment(workspaceSlug, projectId, issueId, commentId, data);
|
await updateComment(workspaceSlug, projectId, issueId, commentId, data);
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Comment updated successfully.",
|
title: "Comment updated successfully.",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: "Comment updated successfully.",
|
message: "Comment updated successfully.",
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Comment update failed.",
|
title: "Comment update failed.",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
message: "Comment update failed. Please try again later.",
|
message: "Comment update failed. Please try again later.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -90,21 +90,21 @@ export const IssueActivity: FC<TIssueActivity> = observer((props) => {
|
|||||||
try {
|
try {
|
||||||
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing fields");
|
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing fields");
|
||||||
await removeComment(workspaceSlug, projectId, issueId, commentId);
|
await removeComment(workspaceSlug, projectId, issueId, commentId);
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Comment removed successfully.",
|
title: "Comment removed successfully.",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: "Comment removed successfully.",
|
message: "Comment removed successfully.",
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Comment remove failed.",
|
title: "Comment remove failed.",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
message: "Comment remove failed. Please try again later.",
|
message: "Comment remove failed. Please try again later.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[workspaceSlug, projectId, issueId, createComment, updateComment, removeComment, setToastAlert]
|
[workspaceSlug, projectId, issueId, createComment, updateComment, removeComment]
|
||||||
);
|
);
|
||||||
|
|
||||||
const project = getProjectById(projectId);
|
const project = getProjectById(projectId);
|
||||||
|
@ -5,9 +5,8 @@ import { TwitterPicker } from "react-color";
|
|||||||
import { Popover, Transition } from "@headlessui/react";
|
import { Popover, Transition } from "@headlessui/react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useIssueDetail } from "hooks/store";
|
import { useIssueDetail } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { Input } from "@plane/ui";
|
import { Input, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { TLabelOperations } from "./root";
|
import { TLabelOperations } from "./root";
|
||||||
import { IIssueLabel } from "@plane/types";
|
import { IIssueLabel } from "@plane/types";
|
||||||
@ -28,7 +27,6 @@ const defaultValues: Partial<IIssueLabel> = {
|
|||||||
export const LabelCreate: FC<ILabelCreate> = (props) => {
|
export const LabelCreate: FC<ILabelCreate> = (props) => {
|
||||||
const { workspaceSlug, projectId, issueId, labelOperations, disabled = false } = props;
|
const { workspaceSlug, projectId, issueId, labelOperations, disabled = false } = props;
|
||||||
// hooks
|
// hooks
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
const {
|
const {
|
||||||
issue: { getIssueById },
|
issue: { getIssueById },
|
||||||
} = useIssueDetail();
|
} = useIssueDetail();
|
||||||
@ -63,9 +61,9 @@ export const LabelCreate: FC<ILabelCreate> = (props) => {
|
|||||||
await labelOperations.updateIssue(workspaceSlug, projectId, issueId, { label_ids: currentLabels });
|
await labelOperations.updateIssue(workspaceSlug, projectId, issueId, { label_ids: currentLabels });
|
||||||
reset(defaultValues);
|
reset(defaultValues);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Label creation failed",
|
title: "Label creation failed",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
message: "Label creation failed. Please try again sometime later.",
|
message: "Label creation failed. Please try again sometime later.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,10 @@ import { observer } from "mobx-react-lite";
|
|||||||
import { LabelList, LabelCreate, IssueLabelSelectRoot } from "./";
|
import { LabelList, LabelCreate, IssueLabelSelectRoot } from "./";
|
||||||
// hooks
|
// hooks
|
||||||
import { useIssueDetail, useLabel } from "hooks/store";
|
import { useIssueDetail, useLabel } from "hooks/store";
|
||||||
|
// ui
|
||||||
|
import { TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { IIssueLabel, TIssue } from "@plane/types";
|
import { IIssueLabel, TIssue } from "@plane/types";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
|
|
||||||
export type TIssueLabel = {
|
export type TIssueLabel = {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
@ -27,7 +28,6 @@ export const IssueLabel: FC<TIssueLabel> = observer((props) => {
|
|||||||
// hooks
|
// hooks
|
||||||
const { updateIssue } = useIssueDetail();
|
const { updateIssue } = useIssueDetail();
|
||||||
const { createLabel } = useLabel();
|
const { createLabel } = useLabel();
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const labelOperations: TLabelOperations = useMemo(
|
const labelOperations: TLabelOperations = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
@ -35,16 +35,10 @@ export const IssueLabel: FC<TIssueLabel> = observer((props) => {
|
|||||||
try {
|
try {
|
||||||
if (onLabelUpdate) onLabelUpdate(data.label_ids || []);
|
if (onLabelUpdate) onLabelUpdate(data.label_ids || []);
|
||||||
else await updateIssue(workspaceSlug, projectId, issueId, data);
|
else await updateIssue(workspaceSlug, projectId, issueId, data);
|
||||||
if (!isInboxIssue)
|
|
||||||
setToastAlert({
|
|
||||||
title: "Issue updated successfully",
|
|
||||||
type: "success",
|
|
||||||
message: "Issue updated successfully",
|
|
||||||
});
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Issue update failed",
|
title: "Issue update failed",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
message: "Issue update failed",
|
message: "Issue update failed",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -53,23 +47,23 @@ export const IssueLabel: FC<TIssueLabel> = observer((props) => {
|
|||||||
try {
|
try {
|
||||||
const labelResponse = await createLabel(workspaceSlug, projectId, data);
|
const labelResponse = await createLabel(workspaceSlug, projectId, data);
|
||||||
if (!isInboxIssue)
|
if (!isInboxIssue)
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Label created successfully",
|
title: "Label created successfully",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: "Label created successfully",
|
message: "Label created successfully",
|
||||||
});
|
});
|
||||||
return labelResponse;
|
return labelResponse;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Label creation failed",
|
title: "Label creation failed",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
message: "Label creation failed",
|
message: "Label creation failed",
|
||||||
});
|
});
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[updateIssue, createLabel, setToastAlert, onLabelUpdate]
|
[updateIssue, createLabel, onLabelUpdate]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import { FC, useState } from "react";
|
import { FC, useState } from "react";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import { useIssueDetail, useMember } from "hooks/store";
|
import { useIssueDetail, useMember } from "hooks/store";
|
||||||
// ui
|
// ui
|
||||||
import { ExternalLinkIcon, Tooltip } from "@plane/ui";
|
import { ExternalLinkIcon, Tooltip, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// icons
|
// icons
|
||||||
import { Pencil, Trash2, LinkIcon } from "lucide-react";
|
import { Pencil, Trash2, LinkIcon } from "lucide-react";
|
||||||
// types
|
// types
|
||||||
@ -27,7 +26,6 @@ export const IssueLinkDetail: FC<TIssueLinkDetail> = (props) => {
|
|||||||
link: { getLinkById },
|
link: { getLinkById },
|
||||||
} = useIssueDetail();
|
} = useIssueDetail();
|
||||||
const { getUserDetails } = useMember();
|
const { getUserDetails } = useMember();
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
// state
|
// state
|
||||||
const [isIssueLinkModalOpen, setIsIssueLinkModalOpen] = useState(false);
|
const [isIssueLinkModalOpen, setIsIssueLinkModalOpen] = useState(false);
|
||||||
@ -55,8 +53,8 @@ export const IssueLinkDetail: FC<TIssueLinkDetail> = (props) => {
|
|||||||
className="flex w-full items-start justify-between gap-2 cursor-pointer"
|
className="flex w-full items-start justify-between gap-2 cursor-pointer"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
copyTextToClipboard(linkDetail.url);
|
copyTextToClipboard(linkDetail.url);
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Link copied!",
|
title: "Link copied!",
|
||||||
message: "Link copied to clipboard",
|
message: "Link copied to clipboard",
|
||||||
});
|
});
|
||||||
|
@ -2,7 +2,8 @@ import { FC, useCallback, useMemo, useState } from "react";
|
|||||||
import { Plus } from "lucide-react";
|
import { Plus } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useIssueDetail } from "hooks/store";
|
import { useIssueDetail } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
// ui
|
||||||
|
import { TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { IssueLinkCreateUpdateModal } from "./create-update-link-modal";
|
import { IssueLinkCreateUpdateModal } from "./create-update-link-modal";
|
||||||
import { IssueLinkList } from "./links";
|
import { IssueLinkList } from "./links";
|
||||||
@ -37,24 +38,22 @@ export const IssueLinkRoot: FC<TIssueLinkRoot> = (props) => {
|
|||||||
[toggleIssueLinkModalStore]
|
[toggleIssueLinkModalStore]
|
||||||
);
|
);
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const handleLinkOperations: TLinkOperations = useMemo(
|
const handleLinkOperations: TLinkOperations = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
create: async (data: Partial<TIssueLink>) => {
|
create: async (data: Partial<TIssueLink>) => {
|
||||||
try {
|
try {
|
||||||
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing required fields");
|
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing required fields");
|
||||||
await createLink(workspaceSlug, projectId, issueId, data);
|
await createLink(workspaceSlug, projectId, issueId, data);
|
||||||
setToastAlert({
|
setToast({
|
||||||
message: "The link has been successfully created",
|
message: "The link has been successfully created",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Link created",
|
title: "Link created",
|
||||||
});
|
});
|
||||||
toggleIssueLinkModal(false);
|
toggleIssueLinkModal(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
message: "The link could not be created",
|
message: "The link could not be created",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Link not created",
|
title: "Link not created",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -63,16 +62,16 @@ export const IssueLinkRoot: FC<TIssueLinkRoot> = (props) => {
|
|||||||
try {
|
try {
|
||||||
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing required fields");
|
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing required fields");
|
||||||
await updateLink(workspaceSlug, projectId, issueId, linkId, data);
|
await updateLink(workspaceSlug, projectId, issueId, linkId, data);
|
||||||
setToastAlert({
|
setToast({
|
||||||
message: "The link has been successfully updated",
|
message: "The link has been successfully updated",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Link updated",
|
title: "Link updated",
|
||||||
});
|
});
|
||||||
toggleIssueLinkModal(false);
|
toggleIssueLinkModal(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
message: "The link could not be updated",
|
message: "The link could not be updated",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Link not updated",
|
title: "Link not updated",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -81,22 +80,22 @@ export const IssueLinkRoot: FC<TIssueLinkRoot> = (props) => {
|
|||||||
try {
|
try {
|
||||||
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing required fields");
|
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing required fields");
|
||||||
await removeLink(workspaceSlug, projectId, issueId, linkId);
|
await removeLink(workspaceSlug, projectId, issueId, linkId);
|
||||||
setToastAlert({
|
setToast({
|
||||||
message: "The link has been successfully removed",
|
message: "The link has been successfully removed",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Link removed",
|
title: "Link removed",
|
||||||
});
|
});
|
||||||
toggleIssueLinkModal(false);
|
toggleIssueLinkModal(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
message: "The link could not be removed",
|
message: "The link could not be removed",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Link not removed",
|
title: "Link not removed",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[workspaceSlug, projectId, issueId, createLink, updateLink, removeLink, setToastAlert, toggleIssueLinkModal]
|
[workspaceSlug, projectId, issueId, createLink, updateLink, removeLink, toggleIssueLinkModal]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -75,7 +75,6 @@ export const IssueModuleSelect: React.FC<TIssueModuleSelect> = observer((props)
|
|||||||
showTooltip
|
showTooltip
|
||||||
multiple
|
multiple
|
||||||
/>
|
/>
|
||||||
{isUpdating && <Spinner className="h-4 w-4" />}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -4,7 +4,8 @@ import { observer } from "mobx-react-lite";
|
|||||||
import { ReactionSelector } from "./reaction-selector";
|
import { ReactionSelector } from "./reaction-selector";
|
||||||
// hooks
|
// hooks
|
||||||
import { useIssueDetail } from "hooks/store";
|
import { useIssueDetail } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
// ui
|
||||||
|
import { TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { IUser } from "@plane/types";
|
import { IUser } from "@plane/types";
|
||||||
import { renderEmoji } from "helpers/emoji.helper";
|
import { renderEmoji } from "helpers/emoji.helper";
|
||||||
@ -25,7 +26,6 @@ export const IssueCommentReaction: FC<TIssueCommentReaction> = observer((props)
|
|||||||
createCommentReaction,
|
createCommentReaction,
|
||||||
removeCommentReaction,
|
removeCommentReaction,
|
||||||
} = useIssueDetail();
|
} = useIssueDetail();
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const reactionIds = getCommentReactionsByCommentId(commentId);
|
const reactionIds = getCommentReactionsByCommentId(commentId);
|
||||||
const userReactions = commentReactionsByUser(commentId, currentUser.id).map((r) => r.reaction);
|
const userReactions = commentReactionsByUser(commentId, currentUser.id).map((r) => r.reaction);
|
||||||
@ -36,15 +36,15 @@ export const IssueCommentReaction: FC<TIssueCommentReaction> = observer((props)
|
|||||||
try {
|
try {
|
||||||
if (!workspaceSlug || !projectId || !commentId) throw new Error("Missing fields");
|
if (!workspaceSlug || !projectId || !commentId) throw new Error("Missing fields");
|
||||||
await createCommentReaction(workspaceSlug, projectId, commentId, reaction);
|
await createCommentReaction(workspaceSlug, projectId, commentId, reaction);
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Reaction created successfully",
|
title: "Reaction created successfully",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: "Reaction created successfully",
|
message: "Reaction created successfully",
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Reaction creation failed",
|
title: "Reaction creation failed",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
message: "Reaction creation failed",
|
message: "Reaction creation failed",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -53,15 +53,15 @@ export const IssueCommentReaction: FC<TIssueCommentReaction> = observer((props)
|
|||||||
try {
|
try {
|
||||||
if (!workspaceSlug || !projectId || !commentId || !currentUser?.id) throw new Error("Missing fields");
|
if (!workspaceSlug || !projectId || !commentId || !currentUser?.id) throw new Error("Missing fields");
|
||||||
removeCommentReaction(workspaceSlug, projectId, commentId, reaction, currentUser.id);
|
removeCommentReaction(workspaceSlug, projectId, commentId, reaction, currentUser.id);
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Reaction removed successfully",
|
title: "Reaction removed successfully",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: "Reaction removed successfully",
|
message: "Reaction removed successfully",
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Reaction remove failed",
|
title: "Reaction remove failed",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
message: "Reaction remove failed",
|
message: "Reaction remove failed",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -78,7 +78,6 @@ export const IssueCommentReaction: FC<TIssueCommentReaction> = observer((props)
|
|||||||
currentUser,
|
currentUser,
|
||||||
createCommentReaction,
|
createCommentReaction,
|
||||||
removeCommentReaction,
|
removeCommentReaction,
|
||||||
setToastAlert,
|
|
||||||
userReactions,
|
userReactions,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
@ -4,7 +4,8 @@ import { observer } from "mobx-react-lite";
|
|||||||
import { ReactionSelector } from "./reaction-selector";
|
import { ReactionSelector } from "./reaction-selector";
|
||||||
// hooks
|
// hooks
|
||||||
import { useIssueDetail } from "hooks/store";
|
import { useIssueDetail } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
// ui
|
||||||
|
import { TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { IUser } from "@plane/types";
|
import { IUser } from "@plane/types";
|
||||||
import { renderEmoji } from "helpers/emoji.helper";
|
import { renderEmoji } from "helpers/emoji.helper";
|
||||||
@ -24,7 +25,6 @@ export const IssueReaction: FC<TIssueReaction> = observer((props) => {
|
|||||||
createReaction,
|
createReaction,
|
||||||
removeReaction,
|
removeReaction,
|
||||||
} = useIssueDetail();
|
} = useIssueDetail();
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const reactionIds = getReactionsByIssueId(issueId);
|
const reactionIds = getReactionsByIssueId(issueId);
|
||||||
const userReactions = reactionsByUser(issueId, currentUser.id).map((r) => r.reaction);
|
const userReactions = reactionsByUser(issueId, currentUser.id).map((r) => r.reaction);
|
||||||
@ -35,15 +35,15 @@ export const IssueReaction: FC<TIssueReaction> = observer((props) => {
|
|||||||
try {
|
try {
|
||||||
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing fields");
|
if (!workspaceSlug || !projectId || !issueId) throw new Error("Missing fields");
|
||||||
await createReaction(workspaceSlug, projectId, issueId, reaction);
|
await createReaction(workspaceSlug, projectId, issueId, reaction);
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Reaction created successfully",
|
title: "Reaction created successfully",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: "Reaction created successfully",
|
message: "Reaction created successfully",
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Reaction creation failed",
|
title: "Reaction creation failed",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
message: "Reaction creation failed",
|
message: "Reaction creation failed",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -52,15 +52,15 @@ export const IssueReaction: FC<TIssueReaction> = observer((props) => {
|
|||||||
try {
|
try {
|
||||||
if (!workspaceSlug || !projectId || !issueId || !currentUser?.id) throw new Error("Missing fields");
|
if (!workspaceSlug || !projectId || !issueId || !currentUser?.id) throw new Error("Missing fields");
|
||||||
await removeReaction(workspaceSlug, projectId, issueId, reaction, currentUser.id);
|
await removeReaction(workspaceSlug, projectId, issueId, reaction, currentUser.id);
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Reaction removed successfully",
|
title: "Reaction removed successfully",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: "Reaction removed successfully",
|
message: "Reaction removed successfully",
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Reaction remove failed",
|
title: "Reaction remove failed",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
message: "Reaction remove failed",
|
message: "Reaction remove failed",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -70,7 +70,7 @@ export const IssueReaction: FC<TIssueReaction> = observer((props) => {
|
|||||||
else await issueReactionOperations.create(reaction);
|
else await issueReactionOperations.create(reaction);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[workspaceSlug, projectId, issueId, currentUser, createReaction, removeReaction, setToastAlert, userReactions]
|
[workspaceSlug, projectId, issueId, currentUser, createReaction, removeReaction, userReactions]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -4,11 +4,10 @@ import { observer } from "mobx-react-lite";
|
|||||||
import { CircleDot, CopyPlus, Pencil, X, XCircle } from "lucide-react";
|
import { CircleDot, CopyPlus, Pencil, X, XCircle } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useIssueDetail, useIssues, useProject } from "hooks/store";
|
import { useIssueDetail, useIssues, useProject } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// components
|
// components
|
||||||
import { ExistingIssuesListModal } from "components/core";
|
import { ExistingIssuesListModal } from "components/core";
|
||||||
// ui
|
// ui
|
||||||
import { RelatedIcon, Tooltip } from "@plane/ui";
|
import { RelatedIcon, Tooltip, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { cn } from "helpers/common.helper";
|
import { cn } from "helpers/common.helper";
|
||||||
// types
|
// types
|
||||||
@ -60,15 +59,13 @@ export const IssueRelationSelect: React.FC<TIssueRelationSelect> = observer((pro
|
|||||||
toggleRelationModal,
|
toggleRelationModal,
|
||||||
} = useIssueDetail();
|
} = useIssueDetail();
|
||||||
const { issueMap } = useIssues();
|
const { issueMap } = useIssues();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const relationIssueIds = getRelationByIssueIdRelationType(issueId, relationKey);
|
const relationIssueIds = getRelationByIssueIdRelationType(issueId, relationKey);
|
||||||
|
|
||||||
const onSubmit = async (data: ISearchIssueResponse[]) => {
|
const onSubmit = async (data: ISearchIssueResponse[]) => {
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Please select at least one issue.",
|
message: "Please select at least one issue.",
|
||||||
});
|
});
|
||||||
|
@ -10,9 +10,10 @@ import { EmptyState } from "components/common";
|
|||||||
import emptyIssue from "public/empty-state/issue.svg";
|
import emptyIssue from "public/empty-state/issue.svg";
|
||||||
// hooks
|
// hooks
|
||||||
import { useApplication, useEventTracker, useIssueDetail, useIssues, useUser } from "hooks/store";
|
import { useApplication, useEventTracker, useIssueDetail, useIssues, useUser } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// types
|
// types
|
||||||
import { TIssue } from "@plane/types";
|
import { TIssue } from "@plane/types";
|
||||||
|
// ui
|
||||||
|
import { TOAST_TYPE, setPromiseToast, setToast } from "@plane/ui";
|
||||||
// constants
|
// constants
|
||||||
import { EUserProjectRoles } from "constants/project";
|
import { EUserProjectRoles } from "constants/project";
|
||||||
import { EIssuesStoreType } from "constants/issue";
|
import { EIssuesStoreType } from "constants/issue";
|
||||||
@ -21,13 +22,7 @@ import { observer } from "mobx-react";
|
|||||||
|
|
||||||
export type TIssueOperations = {
|
export type TIssueOperations = {
|
||||||
fetch: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
fetch: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
||||||
update: (
|
update: (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => Promise<void>;
|
||||||
workspaceSlug: string,
|
|
||||||
projectId: string,
|
|
||||||
issueId: string,
|
|
||||||
data: Partial<TIssue>,
|
|
||||||
showToast?: boolean
|
|
||||||
) => Promise<void>;
|
|
||||||
remove: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
remove: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
||||||
archive?: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
archive?: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
||||||
restore?: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
restore?: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
||||||
@ -76,7 +71,6 @@ export const IssueDetailRoot: FC<TIssueDetailRoot> = observer((props) => {
|
|||||||
issues: { removeIssue: removeArchivedIssue },
|
issues: { removeIssue: removeArchivedIssue },
|
||||||
} = useIssues(EIssuesStoreType.ARCHIVED);
|
} = useIssues(EIssuesStoreType.ARCHIVED);
|
||||||
const { captureIssueEvent } = useEventTracker();
|
const { captureIssueEvent } = useEventTracker();
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
const {
|
const {
|
||||||
membership: { currentProjectRole },
|
membership: { currentProjectRole },
|
||||||
} = useUser();
|
} = useUser();
|
||||||
@ -91,22 +85,9 @@ export const IssueDetailRoot: FC<TIssueDetailRoot> = observer((props) => {
|
|||||||
console.error("Error fetching the parent issue");
|
console.error("Error fetching the parent issue");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
update: async (
|
update: async (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => {
|
||||||
workspaceSlug: string,
|
|
||||||
projectId: string,
|
|
||||||
issueId: string,
|
|
||||||
data: Partial<TIssue>,
|
|
||||||
showToast: boolean = true
|
|
||||||
) => {
|
|
||||||
try {
|
try {
|
||||||
await updateIssue(workspaceSlug, projectId, issueId, data);
|
await updateIssue(workspaceSlug, projectId, issueId, data);
|
||||||
if (showToast) {
|
|
||||||
setToastAlert({
|
|
||||||
title: "Issue updated successfully",
|
|
||||||
type: "success",
|
|
||||||
message: "Issue updated successfully",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
eventName: ISSUE_UPDATED,
|
eventName: ISSUE_UPDATED,
|
||||||
payload: { ...data, issueId, state: "SUCCESS", element: "Issue detail page" },
|
payload: { ...data, issueId, state: "SUCCESS", element: "Issue detail page" },
|
||||||
@ -126,9 +107,9 @@ export const IssueDetailRoot: FC<TIssueDetailRoot> = observer((props) => {
|
|||||||
},
|
},
|
||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Issue update failed",
|
title: "Issue update failed",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
message: "Issue update failed",
|
message: "Issue update failed",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -138,9 +119,9 @@ export const IssueDetailRoot: FC<TIssueDetailRoot> = observer((props) => {
|
|||||||
let response;
|
let response;
|
||||||
if (is_archived) response = await removeArchivedIssue(workspaceSlug, projectId, issueId);
|
if (is_archived) response = await removeArchivedIssue(workspaceSlug, projectId, issueId);
|
||||||
else response = await removeIssue(workspaceSlug, projectId, issueId);
|
else response = await removeIssue(workspaceSlug, projectId, issueId);
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Issue deleted successfully",
|
title: "Issue deleted successfully",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: "Issue deleted successfully",
|
message: "Issue deleted successfully",
|
||||||
});
|
});
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
@ -149,9 +130,9 @@ export const IssueDetailRoot: FC<TIssueDetailRoot> = observer((props) => {
|
|||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Issue delete failed",
|
title: "Issue delete failed",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
message: "Issue delete failed",
|
message: "Issue delete failed",
|
||||||
});
|
});
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
@ -164,8 +145,8 @@ export const IssueDetailRoot: FC<TIssueDetailRoot> = observer((props) => {
|
|||||||
archive: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
archive: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
||||||
try {
|
try {
|
||||||
await archiveIssue(workspaceSlug, projectId, issueId);
|
await archiveIssue(workspaceSlug, projectId, issueId);
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Issue archived successfully.",
|
message: "Issue archived successfully.",
|
||||||
});
|
});
|
||||||
@ -175,8 +156,8 @@ export const IssueDetailRoot: FC<TIssueDetailRoot> = observer((props) => {
|
|||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Issue could not be archived. Please try again.",
|
message: "Issue could not be archived. Please try again.",
|
||||||
});
|
});
|
||||||
@ -189,12 +170,19 @@ export const IssueDetailRoot: FC<TIssueDetailRoot> = observer((props) => {
|
|||||||
},
|
},
|
||||||
addIssueToCycle: async (workspaceSlug: string, projectId: string, cycleId: string, issueIds: string[]) => {
|
addIssueToCycle: async (workspaceSlug: string, projectId: string, cycleId: string, issueIds: string[]) => {
|
||||||
try {
|
try {
|
||||||
await addIssueToCycle(workspaceSlug, projectId, cycleId, issueIds);
|
const addToCyclePromise = addIssueToCycle(workspaceSlug, projectId, cycleId, issueIds);
|
||||||
setToastAlert({
|
setPromiseToast(addToCyclePromise, {
|
||||||
title: "Cycle added to issue successfully",
|
loading: "Adding cycle to issue...",
|
||||||
type: "success",
|
success: {
|
||||||
message: "Issue added to issue successfully",
|
title: "Success!",
|
||||||
|
message: () => "Cycle added to issue successfully",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
title: "Error!",
|
||||||
|
message: () => "Cycle add to issue failed",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
await addToCyclePromise;
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
eventName: ISSUE_UPDATED,
|
eventName: ISSUE_UPDATED,
|
||||||
payload: { ...issueIds, state: "SUCCESS", element: "Issue detail page" },
|
payload: { ...issueIds, state: "SUCCESS", element: "Issue detail page" },
|
||||||
@ -214,21 +202,23 @@ export const IssueDetailRoot: FC<TIssueDetailRoot> = observer((props) => {
|
|||||||
},
|
},
|
||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
setToastAlert({
|
|
||||||
title: "Cycle add to issue failed",
|
|
||||||
type: "error",
|
|
||||||
message: "Cycle add to issue failed",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeIssueFromCycle: async (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => {
|
removeIssueFromCycle: async (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => {
|
||||||
try {
|
try {
|
||||||
const response = await removeIssueFromCycle(workspaceSlug, projectId, cycleId, issueId);
|
const removeFromCyclePromise = removeIssueFromCycle(workspaceSlug, projectId, cycleId, issueId);
|
||||||
setToastAlert({
|
setPromiseToast(removeFromCyclePromise, {
|
||||||
title: "Cycle removed from issue successfully",
|
loading: "Removing cycle from issue...",
|
||||||
type: "success",
|
success: {
|
||||||
message: "Cycle removed from issue successfully",
|
title: "Success!",
|
||||||
|
message: () => "Cycle removed from issue successfully",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
title: "Error!",
|
||||||
|
message: () => "Cycle remove from issue failed",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
const response = await removeFromCyclePromise;
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
eventName: ISSUE_UPDATED,
|
eventName: ISSUE_UPDATED,
|
||||||
payload: { ...response, state: "SUCCESS", element: "Issue detail page" },
|
payload: { ...response, state: "SUCCESS", element: "Issue detail page" },
|
||||||
@ -248,21 +238,23 @@ export const IssueDetailRoot: FC<TIssueDetailRoot> = observer((props) => {
|
|||||||
},
|
},
|
||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
setToastAlert({
|
|
||||||
title: "Cycle remove from issue failed",
|
|
||||||
type: "error",
|
|
||||||
message: "Cycle remove from issue failed",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addModulesToIssue: async (workspaceSlug: string, projectId: string, issueId: string, moduleIds: string[]) => {
|
addModulesToIssue: async (workspaceSlug: string, projectId: string, issueId: string, moduleIds: string[]) => {
|
||||||
try {
|
try {
|
||||||
const response = await addModulesToIssue(workspaceSlug, projectId, issueId, moduleIds);
|
const addToModulePromise = addModulesToIssue(workspaceSlug, projectId, issueId, moduleIds);
|
||||||
setToastAlert({
|
setPromiseToast(addToModulePromise, {
|
||||||
title: "Module added to issue successfully",
|
loading: "Adding module to issue...",
|
||||||
type: "success",
|
success: {
|
||||||
message: "Module added to issue successfully",
|
title: "Success!",
|
||||||
|
message: () => "Module added to issue successfully",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
title: "Error!",
|
||||||
|
message: () => "Module add to issue failed",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
const response = await addToModulePromise;
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
eventName: ISSUE_UPDATED,
|
eventName: ISSUE_UPDATED,
|
||||||
payload: { ...response, state: "SUCCESS", element: "Issue detail page" },
|
payload: { ...response, state: "SUCCESS", element: "Issue detail page" },
|
||||||
@ -282,21 +274,23 @@ export const IssueDetailRoot: FC<TIssueDetailRoot> = observer((props) => {
|
|||||||
},
|
},
|
||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
setToastAlert({
|
|
||||||
title: "Module add to issue failed",
|
|
||||||
type: "error",
|
|
||||||
message: "Module add to issue failed",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeIssueFromModule: async (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) => {
|
removeIssueFromModule: async (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) => {
|
||||||
try {
|
try {
|
||||||
await removeIssueFromModule(workspaceSlug, projectId, moduleId, issueId);
|
const removeFromModulePromise = removeIssueFromModule(workspaceSlug, projectId, moduleId, issueId);
|
||||||
setToastAlert({
|
setPromiseToast(removeFromModulePromise, {
|
||||||
title: "Module removed from issue successfully",
|
loading: "Removing module from issue...",
|
||||||
type: "success",
|
success: {
|
||||||
message: "Module removed from issue successfully",
|
title: "Success!",
|
||||||
|
message: () => "Module removed from issue successfully",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
title: "Error!",
|
||||||
|
message: () => "Module remove from issue failed",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
await removeFromModulePromise;
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
eventName: ISSUE_UPDATED,
|
eventName: ISSUE_UPDATED,
|
||||||
payload: { id: issueId, state: "SUCCESS", element: "Issue detail page" },
|
payload: { id: issueId, state: "SUCCESS", element: "Issue detail page" },
|
||||||
@ -316,11 +310,6 @@ export const IssueDetailRoot: FC<TIssueDetailRoot> = observer((props) => {
|
|||||||
},
|
},
|
||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
setToastAlert({
|
|
||||||
title: "Module remove from issue failed",
|
|
||||||
type: "error",
|
|
||||||
message: "Module remove from issue failed",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeModulesFromIssue: async (
|
removeModulesFromIssue: async (
|
||||||
@ -329,20 +318,19 @@ export const IssueDetailRoot: FC<TIssueDetailRoot> = observer((props) => {
|
|||||||
issueId: string,
|
issueId: string,
|
||||||
moduleIds: string[]
|
moduleIds: string[]
|
||||||
) => {
|
) => {
|
||||||
try {
|
const removeModulesFromIssuePromise = removeModulesFromIssue(workspaceSlug, projectId, issueId, moduleIds);
|
||||||
await removeModulesFromIssue(workspaceSlug, projectId, issueId, moduleIds);
|
setPromiseToast(removeModulesFromIssuePromise, {
|
||||||
setToastAlert({
|
loading: "Removing module from issue...",
|
||||||
type: "success",
|
success: {
|
||||||
title: "Successful!",
|
title: "Success!",
|
||||||
message: "Issue removed from module successfully.",
|
message: () => "Module removed from issue successfully",
|
||||||
});
|
},
|
||||||
} catch (error) {
|
error: {
|
||||||
setToastAlert({
|
|
||||||
type: "error",
|
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Issue could not be removed from module. Please try again.",
|
message: () => "Module remove from issue failed",
|
||||||
});
|
},
|
||||||
}
|
});
|
||||||
|
await removeModulesFromIssuePromise;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
@ -357,7 +345,6 @@ export const IssueDetailRoot: FC<TIssueDetailRoot> = observer((props) => {
|
|||||||
addModulesToIssue,
|
addModulesToIssue,
|
||||||
removeIssueFromModule,
|
removeIssueFromModule,
|
||||||
removeModulesFromIssue,
|
removeModulesFromIssue,
|
||||||
setToastAlert,
|
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@ import {
|
|||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEstimate, useIssueDetail, useProject, useProjectState, useUser } from "hooks/store";
|
import { useEstimate, useIssueDetail, useProject, useProjectState, useUser } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// components
|
// components
|
||||||
import {
|
import {
|
||||||
DeleteIssueModal,
|
DeleteIssueModal,
|
||||||
@ -30,8 +29,18 @@ import {
|
|||||||
} from "components/issues";
|
} from "components/issues";
|
||||||
import { IssueSubscription } from "./subscription";
|
import { IssueSubscription } from "./subscription";
|
||||||
import { DateDropdown, EstimateDropdown, PriorityDropdown, MemberDropdown, StateDropdown } from "components/dropdowns";
|
import { DateDropdown, EstimateDropdown, PriorityDropdown, MemberDropdown, StateDropdown } from "components/dropdowns";
|
||||||
// icons
|
// ui
|
||||||
import { ArchiveIcon, ContrastIcon, DiceIcon, DoubleCircleIcon, RelatedIcon, Tooltip, UserGroupIcon } from "@plane/ui";
|
import {
|
||||||
|
ArchiveIcon,
|
||||||
|
ContrastIcon,
|
||||||
|
DiceIcon,
|
||||||
|
DoubleCircleIcon,
|
||||||
|
RelatedIcon,
|
||||||
|
Tooltip,
|
||||||
|
UserGroupIcon,
|
||||||
|
TOAST_TYPE,
|
||||||
|
setToast,
|
||||||
|
} from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
||||||
import { copyTextToClipboard } from "helpers/string.helper";
|
import { copyTextToClipboard } from "helpers/string.helper";
|
||||||
@ -61,7 +70,6 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
const { getProjectById } = useProject();
|
const { getProjectById } = useProject();
|
||||||
const { currentUser } = useUser();
|
const { currentUser } = useUser();
|
||||||
const { areEstimatesEnabledForCurrentProject } = useEstimate();
|
const { areEstimatesEnabledForCurrentProject } = useEstimate();
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
const {
|
const {
|
||||||
issue: { getIssueById },
|
issue: { getIssueById },
|
||||||
} = useIssueDetail();
|
} = useIssueDetail();
|
||||||
@ -73,8 +81,8 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
const handleCopyText = () => {
|
const handleCopyText = () => {
|
||||||
const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
|
const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
|
||||||
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`).then(() => {
|
copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`).then(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Link Copied!",
|
title: "Link Copied!",
|
||||||
message: "Issue link copied to clipboard.",
|
message: "Issue link copied to clipboard.",
|
||||||
});
|
});
|
||||||
|
@ -2,10 +2,9 @@ import { Bell, BellOff } from "lucide-react";
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { FC, useState } from "react";
|
import { FC, useState } from "react";
|
||||||
// UI
|
// UI
|
||||||
import { Button, Loader } from "@plane/ui";
|
import { Button, Loader, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// hooks
|
// hooks
|
||||||
import { useIssueDetail } from "hooks/store";
|
import { useIssueDetail } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import isNil from "lodash/isNil";
|
import isNil from "lodash/isNil";
|
||||||
|
|
||||||
export type TIssueSubscription = {
|
export type TIssueSubscription = {
|
||||||
@ -22,7 +21,6 @@ export const IssueSubscription: FC<TIssueSubscription> = observer((props) => {
|
|||||||
createSubscription,
|
createSubscription,
|
||||||
removeSubscription,
|
removeSubscription,
|
||||||
} = useIssueDetail();
|
} = useIssueDetail();
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// state
|
// state
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
@ -33,16 +31,16 @@ export const IssueSubscription: FC<TIssueSubscription> = observer((props) => {
|
|||||||
try {
|
try {
|
||||||
if (isSubscribed) await removeSubscription(workspaceSlug, projectId, issueId);
|
if (isSubscribed) await removeSubscription(workspaceSlug, projectId, issueId);
|
||||||
else await createSubscription(workspaceSlug, projectId, issueId);
|
else await createSubscription(workspaceSlug, projectId, issueId);
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: `Issue ${isSubscribed ? `unsubscribed` : `subscribed`} successfully.!`,
|
title: `Issue ${isSubscribed ? `unsubscribed` : `subscribed`} successfully.!`,
|
||||||
message: `Issue ${isSubscribed ? `unsubscribed` : `subscribed`} successfully.!`,
|
message: `Issue ${isSubscribed ? `unsubscribed` : `subscribed`} successfully.!`,
|
||||||
});
|
});
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error",
|
title: "Error",
|
||||||
message: "Something went wrong. Please try again later.",
|
message: "Something went wrong. Please try again later.",
|
||||||
});
|
});
|
||||||
|
@ -4,8 +4,8 @@ import { observer } from "mobx-react-lite";
|
|||||||
import { DragDropContext, DropResult } from "@hello-pangea/dnd";
|
import { DragDropContext, DropResult } from "@hello-pangea/dnd";
|
||||||
// components
|
// components
|
||||||
import { CalendarChart } from "components/issues";
|
import { CalendarChart } from "components/issues";
|
||||||
// hooks
|
// ui
|
||||||
import useToast from "hooks/use-toast";
|
import { TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { TGroupedIssues, TIssue } from "@plane/types";
|
import { TGroupedIssues, TIssue } from "@plane/types";
|
||||||
import { IQuickActionProps } from "../list/list-view-types";
|
import { IQuickActionProps } from "../list/list-view-types";
|
||||||
@ -41,7 +41,6 @@ export const BaseCalendarRoot = observer((props: IBaseCalendarRoot) => {
|
|||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
// hooks
|
// hooks
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
const { issueMap } = useIssues();
|
const { issueMap } = useIssues();
|
||||||
const {
|
const {
|
||||||
membership: { currentProjectRole },
|
membership: { currentProjectRole },
|
||||||
@ -73,9 +72,9 @@ export const BaseCalendarRoot = observer((props: IBaseCalendarRoot) => {
|
|||||||
groupedIssueIds,
|
groupedIssueIds,
|
||||||
viewId
|
viewId
|
||||||
).catch((err) => {
|
).catch((err) => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Error",
|
title: "Error",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
message: err.detail ?? "Failed to perform this action",
|
message: err.detail ?? "Failed to perform this action",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -4,13 +4,14 @@ import { useForm } from "react-hook-form";
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEventTracker, useProject } from "hooks/store";
|
import { useEventTracker, useProject } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import useKeypress from "hooks/use-keypress";
|
import useKeypress from "hooks/use-keypress";
|
||||||
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
||||||
// helpers
|
// helpers
|
||||||
import { createIssuePayload } from "helpers/issue.helper";
|
import { createIssuePayload } from "helpers/issue.helper";
|
||||||
// icons
|
// icons
|
||||||
import { PlusIcon } from "lucide-react";
|
import { PlusIcon } from "lucide-react";
|
||||||
|
// ui
|
||||||
|
import { TOAST_TYPE, setPromiseToast, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { TIssue } from "@plane/types";
|
import { TIssue } from "@plane/types";
|
||||||
// constants
|
// constants
|
||||||
@ -71,8 +72,6 @@ export const CalendarQuickAddIssueForm: React.FC<Props> = observer((props) => {
|
|||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
// states
|
// states
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
// derived values
|
// derived values
|
||||||
const projectDetail = projectId ? getProjectById(projectId.toString()) : null;
|
const projectDetail = projectId ? getProjectById(projectId.toString()) : null;
|
||||||
@ -102,13 +101,13 @@ export const CalendarQuickAddIssueForm: React.FC<Props> = observer((props) => {
|
|||||||
Object.keys(errors).forEach((key) => {
|
Object.keys(errors).forEach((key) => {
|
||||||
const error = errors[key as keyof TIssue];
|
const error = errors[key as keyof TIssue];
|
||||||
|
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: error?.message?.toString() || "Some error occurred. Please try again.",
|
message: error?.message?.toString() || "Some error occurred. Please try again.",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, [errors, setToastAlert]);
|
}, [errors]);
|
||||||
|
|
||||||
const onSubmitHandler = async (formData: TIssue) => {
|
const onSubmitHandler = async (formData: TIssue) => {
|
||||||
if (isSubmitting || !workspaceSlug || !projectId) return;
|
if (isSubmitting || !workspaceSlug || !projectId) return;
|
||||||
@ -120,39 +119,42 @@ export const CalendarQuickAddIssueForm: React.FC<Props> = observer((props) => {
|
|||||||
...formData,
|
...formData,
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
if (quickAddCallback) {
|
||||||
quickAddCallback &&
|
const quickAddPromise = quickAddCallback(
|
||||||
(await quickAddCallback(
|
workspaceSlug.toString(),
|
||||||
workspaceSlug.toString(),
|
projectId.toString(),
|
||||||
projectId.toString(),
|
{
|
||||||
{
|
...payload,
|
||||||
...payload,
|
},
|
||||||
},
|
viewId
|
||||||
viewId
|
);
|
||||||
).then((res) => {
|
setPromiseToast<any>(quickAddPromise, {
|
||||||
|
loading: "Adding issue...",
|
||||||
|
success: {
|
||||||
|
title: "Success!",
|
||||||
|
message: () => "Issue created successfully.",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
title: "Error!",
|
||||||
|
message: (err) => err?.message || "Some error occurred. Please try again.",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await quickAddPromise
|
||||||
|
.then((res) => {
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
eventName: ISSUE_CREATED,
|
eventName: ISSUE_CREATED,
|
||||||
payload: { ...res, state: "SUCCESS", element: "Calendar quick add" },
|
payload: { ...res, state: "SUCCESS", element: "Calendar quick add" },
|
||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
}));
|
})
|
||||||
setToastAlert({
|
.catch(() => {
|
||||||
type: "success",
|
captureIssueEvent({
|
||||||
title: "Success!",
|
eventName: ISSUE_CREATED,
|
||||||
message: "Issue created successfully.",
|
payload: { ...payload, state: "FAILED", element: "Calendar quick add" },
|
||||||
});
|
path: router.asPath,
|
||||||
} catch (err: any) {
|
});
|
||||||
console.error(err);
|
});
|
||||||
captureIssueEvent({
|
|
||||||
eventName: ISSUE_CREATED,
|
|
||||||
payload: { ...payload, state: "FAILED", element: "Calendar quick add" },
|
|
||||||
path: router.asPath,
|
|
||||||
});
|
|
||||||
setToastAlert({
|
|
||||||
type: "error",
|
|
||||||
title: "Error!",
|
|
||||||
message: err?.message || "Some error occurred. Please try again.",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4,7 +4,8 @@ import { PlusIcon } from "lucide-react";
|
|||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
// hooks
|
// hooks
|
||||||
import { useApplication, useEventTracker, useIssueDetail, useIssues, useUser } from "hooks/store";
|
import { useApplication, useEventTracker, useIssueDetail, useIssues, useUser } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
// ui
|
||||||
|
import { TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { ExistingIssuesListModal } from "components/core";
|
import { ExistingIssuesListModal } from "components/core";
|
||||||
import { EmptyState, getEmptyStateImagePath } from "components/empty-state";
|
import { EmptyState, getEmptyStateImagePath } from "components/empty-state";
|
||||||
@ -53,16 +54,14 @@ export const CycleEmptyState: React.FC<Props> = observer((props) => {
|
|||||||
currentUser,
|
currentUser,
|
||||||
} = useUser();
|
} = useUser();
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const handleAddIssuesToCycle = async (data: ISearchIssueResponse[]) => {
|
const handleAddIssuesToCycle = async (data: ISearchIssueResponse[]) => {
|
||||||
if (!workspaceSlug || !projectId || !cycleId) return;
|
if (!workspaceSlug || !projectId || !cycleId) return;
|
||||||
|
|
||||||
const issueIds = data.map((i) => i.id);
|
const issueIds = data.map((i) => i.id);
|
||||||
|
|
||||||
await issues.addIssueToCycle(workspaceSlug.toString(), projectId, cycleId.toString(), issueIds).catch(() => {
|
await issues.addIssueToCycle(workspaceSlug.toString(), projectId, cycleId.toString(), issueIds).catch(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Selected issues could not be added to the cycle. Please try again.",
|
message: "Selected issues could not be added to the cycle. Please try again.",
|
||||||
});
|
});
|
||||||
|
@ -4,7 +4,8 @@ import { PlusIcon } from "lucide-react";
|
|||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
// hooks
|
// hooks
|
||||||
import { useApplication, useEventTracker, useIssues, useUser } from "hooks/store";
|
import { useApplication, useEventTracker, useIssues, useUser } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
// ui
|
||||||
|
import { TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { ExistingIssuesListModal } from "components/core";
|
import { ExistingIssuesListModal } from "components/core";
|
||||||
import { EmptyState, getEmptyStateImagePath } from "components/empty-state";
|
import { EmptyState, getEmptyStateImagePath } from "components/empty-state";
|
||||||
@ -51,8 +52,6 @@ export const ModuleEmptyState: React.FC<Props> = observer((props) => {
|
|||||||
membership: { currentProjectRole: userRole },
|
membership: { currentProjectRole: userRole },
|
||||||
currentUser,
|
currentUser,
|
||||||
} = useUser();
|
} = useUser();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const handleAddIssuesToModule = async (data: ISearchIssueResponse[]) => {
|
const handleAddIssuesToModule = async (data: ISearchIssueResponse[]) => {
|
||||||
if (!workspaceSlug || !projectId || !moduleId) return;
|
if (!workspaceSlug || !projectId || !moduleId) return;
|
||||||
@ -61,8 +60,8 @@ export const ModuleEmptyState: React.FC<Props> = observer((props) => {
|
|||||||
await issues
|
await issues
|
||||||
.addIssuesToModule(workspaceSlug.toString(), projectId?.toString(), moduleId.toString(), issueIds)
|
.addIssuesToModule(workspaceSlug.toString(), projectId?.toString(), moduleId.toString(), issueIds)
|
||||||
.catch(() =>
|
.catch(() =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Selected issues could not be added to the module. Please try again.",
|
message: "Selected issues could not be added to the module. Please try again.",
|
||||||
})
|
})
|
||||||
|
@ -5,13 +5,14 @@ import { observer } from "mobx-react-lite";
|
|||||||
import { PlusIcon } from "lucide-react";
|
import { PlusIcon } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEventTracker, useProject } from "hooks/store";
|
import { useEventTracker, useProject } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import useKeypress from "hooks/use-keypress";
|
import useKeypress from "hooks/use-keypress";
|
||||||
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
||||||
// helpers
|
// helpers
|
||||||
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
||||||
import { createIssuePayload } from "helpers/issue.helper";
|
import { createIssuePayload } from "helpers/issue.helper";
|
||||||
import { cn } from "helpers/common.helper";
|
import { cn } from "helpers/common.helper";
|
||||||
|
// ui
|
||||||
|
import { setPromiseToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { IProject, TIssue } from "@plane/types";
|
import { IProject, TIssue } from "@plane/types";
|
||||||
// constants
|
// constants
|
||||||
@ -70,7 +71,6 @@ export const GanttQuickAddIssueForm: React.FC<IGanttQuickAddIssueForm> = observe
|
|||||||
// hooks
|
// hooks
|
||||||
const { getProjectById } = useProject();
|
const { getProjectById } = useProject();
|
||||||
const { captureIssueEvent } = useEventTracker();
|
const { captureIssueEvent } = useEventTracker();
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const projectDetail = (projectId && getProjectById(projectId.toString())) || undefined;
|
const projectDetail = (projectId && getProjectById(projectId.toString())) || undefined;
|
||||||
|
|
||||||
@ -110,31 +110,35 @@ export const GanttQuickAddIssueForm: React.FC<IGanttQuickAddIssueForm> = observe
|
|||||||
target_date: renderFormattedPayloadDate(targetDate),
|
target_date: renderFormattedPayloadDate(targetDate),
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
if (quickAddCallback) {
|
||||||
quickAddCallback &&
|
const quickAddPromise = quickAddCallback(workspaceSlug.toString(), projectId.toString(), { ...payload }, viewId);
|
||||||
(await quickAddCallback(workspaceSlug.toString(), projectId.toString(), { ...payload }, viewId).then((res) => {
|
setPromiseToast<any>(quickAddPromise, {
|
||||||
|
loading: "Adding issue...",
|
||||||
|
success: {
|
||||||
|
title: "Success!",
|
||||||
|
message: () => "Issue created successfully.",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
title: "Error!",
|
||||||
|
message: (err) => err?.message || "Some error occurred. Please try again.",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await quickAddPromise
|
||||||
|
.then((res) => {
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
eventName: ISSUE_CREATED,
|
eventName: ISSUE_CREATED,
|
||||||
payload: { ...res, state: "SUCCESS", element: "Gantt quick add" },
|
payload: { ...res, state: "SUCCESS", element: "Gantt quick add" },
|
||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
}));
|
})
|
||||||
setToastAlert({
|
.catch(() => {
|
||||||
type: "success",
|
captureIssueEvent({
|
||||||
title: "Success!",
|
eventName: ISSUE_CREATED,
|
||||||
message: "Issue created successfully.",
|
payload: { ...payload, state: "FAILED", element: "Gantt quick add" },
|
||||||
});
|
path: router.asPath,
|
||||||
} catch (err: any) {
|
});
|
||||||
captureIssueEvent({
|
});
|
||||||
eventName: ISSUE_CREATED,
|
|
||||||
payload: { ...payload, state: "FAILED", element: "Gantt quick add" },
|
|
||||||
path: router.asPath,
|
|
||||||
});
|
|
||||||
setToastAlert({
|
|
||||||
type: "error",
|
|
||||||
title: "Error!",
|
|
||||||
message: err?.message || "Some error occurred. Please try again.",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
|
@ -4,9 +4,8 @@ import { useRouter } from "next/router";
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEventTracker, useUser } from "hooks/store";
|
import { useEventTracker, useUser } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { Spinner } from "@plane/ui";
|
import { Spinner, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { TIssue } from "@plane/types";
|
import { TIssue } from "@plane/types";
|
||||||
import { EIssueActions } from "../types";
|
import { EIssueActions } from "../types";
|
||||||
@ -80,8 +79,6 @@ export const BaseKanBanRoot: React.FC<IBaseKanBanLayout> = observer((props: IBas
|
|||||||
} = useUser();
|
} = useUser();
|
||||||
const { captureIssueEvent } = useEventTracker();
|
const { captureIssueEvent } = useEventTracker();
|
||||||
const { issueMap } = useIssues();
|
const { issueMap } = useIssues();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const issueIds = issues?.groupedIssueIds || [];
|
const issueIds = issues?.groupedIssueIds || [];
|
||||||
|
|
||||||
@ -159,9 +156,9 @@ export const BaseKanBanRoot: React.FC<IBaseKanBanLayout> = observer((props: IBas
|
|||||||
issueIds,
|
issueIds,
|
||||||
viewId
|
viewId
|
||||||
).catch((err) => {
|
).catch((err) => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Error",
|
title: "Error",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
message: err.detail ?? "Failed to perform this action",
|
message: err.detail ?? "Failed to perform this action",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
// ui
|
||||||
|
import { CustomMenu, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { CustomMenu } from "@plane/ui";
|
|
||||||
import { ExistingIssuesListModal } from "components/core";
|
import { ExistingIssuesListModal } from "components/core";
|
||||||
import { CreateUpdateIssueModal } from "components/issues";
|
import { CreateUpdateIssueModal } from "components/issues";
|
||||||
// lucide icons
|
// lucide icons
|
||||||
import { Minimize2, Maximize2, Circle, Plus } from "lucide-react";
|
import { Minimize2, Maximize2, Circle, Plus } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import { useEventTracker } from "hooks/store";
|
import { useEventTracker } from "hooks/store";
|
||||||
// mobx
|
// mobx
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
@ -56,8 +56,6 @@ export const HeaderGroupByCard: FC<IHeaderGroupByCard> = observer((props) => {
|
|||||||
|
|
||||||
const isDraftIssue = router.pathname.includes("draft-issue");
|
const isDraftIssue = router.pathname.includes("draft-issue");
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const renderExistingIssueModal = moduleId || cycleId;
|
const renderExistingIssueModal = moduleId || cycleId;
|
||||||
const ExistingIssuesListModalPayload = moduleId ? { module: moduleId.toString() } : { cycle: true };
|
const ExistingIssuesListModalPayload = moduleId ? { module: moduleId.toString() } : { cycle: true };
|
||||||
|
|
||||||
@ -69,8 +67,8 @@ export const HeaderGroupByCard: FC<IHeaderGroupByCard> = observer((props) => {
|
|||||||
try {
|
try {
|
||||||
addIssuesToView && addIssuesToView(issues);
|
addIssuesToView && addIssuesToView(issues);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Selected issues could not be added to the cycle. Please try again.",
|
message: "Selected issues could not be added to the cycle. Please try again.",
|
||||||
});
|
});
|
||||||
|
@ -5,11 +5,12 @@ import { observer } from "mobx-react-lite";
|
|||||||
import { PlusIcon } from "lucide-react";
|
import { PlusIcon } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEventTracker, useProject } from "hooks/store";
|
import { useEventTracker, useProject } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import useKeypress from "hooks/use-keypress";
|
import useKeypress from "hooks/use-keypress";
|
||||||
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
||||||
// helpers
|
// helpers
|
||||||
import { createIssuePayload } from "helpers/issue.helper";
|
import { createIssuePayload } from "helpers/issue.helper";
|
||||||
|
// ui
|
||||||
|
import { setPromiseToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { TIssue } from "@plane/types";
|
import { TIssue } from "@plane/types";
|
||||||
// constants
|
// constants
|
||||||
@ -73,7 +74,6 @@ export const KanBanQuickAddIssueForm: React.FC<IKanBanQuickAddIssueForm> = obser
|
|||||||
|
|
||||||
useKeypress("Escape", handleClose);
|
useKeypress("Escape", handleClose);
|
||||||
useOutsideClickDetector(ref, handleClose);
|
useOutsideClickDetector(ref, handleClose);
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
reset,
|
reset,
|
||||||
@ -97,39 +97,42 @@ export const KanBanQuickAddIssueForm: React.FC<IKanBanQuickAddIssueForm> = obser
|
|||||||
...formData,
|
...formData,
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
if (quickAddCallback) {
|
||||||
quickAddCallback &&
|
const quickAddPromise = quickAddCallback(
|
||||||
(await quickAddCallback(
|
workspaceSlug.toString(),
|
||||||
workspaceSlug.toString(),
|
projectId.toString(),
|
||||||
projectId.toString(),
|
{
|
||||||
{
|
...payload,
|
||||||
...payload,
|
},
|
||||||
},
|
viewId
|
||||||
viewId
|
);
|
||||||
).then((res) => {
|
setPromiseToast<any>(quickAddPromise, {
|
||||||
|
loading: "Adding issue...",
|
||||||
|
success: {
|
||||||
|
title: "Success!",
|
||||||
|
message: () => "Issue created successfully.",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
title: "Error!",
|
||||||
|
message: (err) => err?.message || "Some error occurred. Please try again.",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await quickAddPromise
|
||||||
|
.then((res) => {
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
eventName: ISSUE_CREATED,
|
eventName: ISSUE_CREATED,
|
||||||
payload: { ...res, state: "SUCCESS", element: "Kanban quick add" },
|
payload: { ...res, state: "SUCCESS", element: "Kanban quick add" },
|
||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
}));
|
})
|
||||||
setToastAlert({
|
.catch(() => {
|
||||||
type: "success",
|
captureIssueEvent({
|
||||||
title: "Success!",
|
eventName: ISSUE_CREATED,
|
||||||
message: "Issue created successfully.",
|
payload: { ...payload, state: "FAILED", element: "Kanban quick add" },
|
||||||
});
|
path: router.asPath,
|
||||||
} catch (err: any) {
|
});
|
||||||
captureIssueEvent({
|
});
|
||||||
eventName: ISSUE_CREATED,
|
|
||||||
payload: { ...payload, state: "FAILED", element: "Kanban quick add" },
|
|
||||||
path: router.asPath,
|
|
||||||
});
|
|
||||||
console.error(err);
|
|
||||||
setToastAlert({
|
|
||||||
type: "error",
|
|
||||||
title: "Error!",
|
|
||||||
message: err?.message || "Some error occurred. Please try again.",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4,14 +4,14 @@ import { CircleDashed, Plus } from "lucide-react";
|
|||||||
// components
|
// components
|
||||||
import { CreateUpdateIssueModal } from "components/issues";
|
import { CreateUpdateIssueModal } from "components/issues";
|
||||||
import { ExistingIssuesListModal } from "components/core";
|
import { ExistingIssuesListModal } from "components/core";
|
||||||
import { CustomMenu } from "@plane/ui";
|
// ui
|
||||||
|
import { CustomMenu, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// mobx
|
// mobx
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEventTracker } from "hooks/store";
|
import { useEventTracker } from "hooks/store";
|
||||||
// types
|
// types
|
||||||
import { TIssue, ISearchIssueResponse } from "@plane/types";
|
import { TIssue, ISearchIssueResponse } from "@plane/types";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { TCreateModalStoreTypes } from "constants/issue";
|
import { TCreateModalStoreTypes } from "constants/issue";
|
||||||
|
|
||||||
@ -38,8 +38,6 @@ export const HeaderGroupByCard = observer(
|
|||||||
|
|
||||||
const isDraftIssue = router.pathname.includes("draft-issue");
|
const isDraftIssue = router.pathname.includes("draft-issue");
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const renderExistingIssueModal = moduleId || cycleId;
|
const renderExistingIssueModal = moduleId || cycleId;
|
||||||
const ExistingIssuesListModalPayload = moduleId ? { module: moduleId.toString() } : { cycle: true };
|
const ExistingIssuesListModalPayload = moduleId ? { module: moduleId.toString() } : { cycle: true };
|
||||||
|
|
||||||
@ -51,8 +49,8 @@ export const HeaderGroupByCard = observer(
|
|||||||
try {
|
try {
|
||||||
addIssuesToView && addIssuesToView(issues);
|
addIssuesToView && addIssuesToView(issues);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Selected issues could not be added to the cycle. Please try again.",
|
message: "Selected issues could not be added to the cycle. Please try again.",
|
||||||
});
|
});
|
||||||
|
@ -5,12 +5,13 @@ import { PlusIcon } from "lucide-react";
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEventTracker, useProject } from "hooks/store";
|
import { useEventTracker, useProject } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import useKeypress from "hooks/use-keypress";
|
import useKeypress from "hooks/use-keypress";
|
||||||
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
||||||
// constants
|
// ui
|
||||||
import { TIssue, IProject } from "@plane/types";
|
import { setPromiseToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
|
import { TIssue, IProject } from "@plane/types";
|
||||||
|
// helper
|
||||||
import { createIssuePayload } from "helpers/issue.helper";
|
import { createIssuePayload } from "helpers/issue.helper";
|
||||||
// constants
|
// constants
|
||||||
import { ISSUE_CREATED } from "constants/event-tracker";
|
import { ISSUE_CREATED } from "constants/event-tracker";
|
||||||
@ -77,7 +78,6 @@ export const ListQuickAddIssueForm: FC<IListQuickAddIssueForm> = observer((props
|
|||||||
|
|
||||||
useKeypress("Escape", handleClose);
|
useKeypress("Escape", handleClose);
|
||||||
useOutsideClickDetector(ref, handleClose);
|
useOutsideClickDetector(ref, handleClose);
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
reset,
|
reset,
|
||||||
@ -101,31 +101,35 @@ export const ListQuickAddIssueForm: FC<IListQuickAddIssueForm> = observer((props
|
|||||||
...formData,
|
...formData,
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
if (quickAddCallback) {
|
||||||
quickAddCallback &&
|
const quickAddPromise = quickAddCallback(workspaceSlug.toString(), projectId.toString(), { ...payload }, viewId);
|
||||||
(await quickAddCallback(workspaceSlug.toString(), projectId.toString(), { ...payload }, viewId).then((res) => {
|
setPromiseToast<any>(quickAddPromise, {
|
||||||
|
loading: "Adding issue...",
|
||||||
|
success: {
|
||||||
|
title: "Success!",
|
||||||
|
message: () => "Issue created successfully.",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
title: "Error!",
|
||||||
|
message: (err) => err?.message || "Some error occurred. Please try again.",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await quickAddPromise
|
||||||
|
.then((res) => {
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
eventName: ISSUE_CREATED,
|
eventName: ISSUE_CREATED,
|
||||||
payload: { ...res, state: "SUCCESS", element: "List quick add" },
|
payload: { ...res, state: "SUCCESS", element: "List quick add" },
|
||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
}));
|
})
|
||||||
setToastAlert({
|
.catch(() => {
|
||||||
type: "success",
|
captureIssueEvent({
|
||||||
title: "Success!",
|
eventName: ISSUE_CREATED,
|
||||||
message: "Issue created successfully.",
|
payload: { ...payload, state: "FAILED", element: "List quick add" },
|
||||||
});
|
path: router.asPath,
|
||||||
} catch (err: any) {
|
});
|
||||||
captureIssueEvent({
|
});
|
||||||
eventName: ISSUE_CREATED,
|
|
||||||
payload: { ...payload, state: "FAILED", element: "List quick add" },
|
|
||||||
path: router.asPath,
|
|
||||||
});
|
|
||||||
setToastAlert({
|
|
||||||
type: "error",
|
|
||||||
title: "Error!",
|
|
||||||
message: err?.message || "Some error occurred. Please try again.",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { ArchiveIcon, CustomMenu } from "@plane/ui";
|
|
||||||
import { observer } from "mobx-react";
|
|
||||||
import { Copy, ExternalLink, Link, Pencil, Trash2 } from "lucide-react";
|
import { Copy, ExternalLink, Link, Pencil, Trash2 } from "lucide-react";
|
||||||
import omit from "lodash/omit";
|
import omit from "lodash/omit";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import { useEventTracker, useProjectState } from "hooks/store";
|
import { useEventTracker, useProjectState } from "hooks/store";
|
||||||
|
// ui
|
||||||
|
import { ArchiveIcon, CustomMenu, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { ArchiveIssueModal, CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
import { ArchiveIssueModal, CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
||||||
// helpers
|
// helpers
|
||||||
@ -39,8 +39,6 @@ export const AllIssueQuickActions: React.FC<IQuickActionProps> = observer((props
|
|||||||
// store hooks
|
// store hooks
|
||||||
const { setTrackElement } = useEventTracker();
|
const { setTrackElement } = useEventTracker();
|
||||||
const { getStateById } = useProjectState();
|
const { getStateById } = useProjectState();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// derived values
|
// derived values
|
||||||
const stateDetails = getStateById(issue.state_id);
|
const stateDetails = getStateById(issue.state_id);
|
||||||
const isEditingAllowed = !readOnly;
|
const isEditingAllowed = !readOnly;
|
||||||
@ -54,8 +52,8 @@ export const AllIssueQuickActions: React.FC<IQuickActionProps> = observer((props
|
|||||||
const handleOpenInNewTab = () => window.open(`/${issueLink}`, "_blank");
|
const handleOpenInNewTab = () => window.open(`/${issueLink}`, "_blank");
|
||||||
const handleCopyIssueLink = () =>
|
const handleCopyIssueLink = () =>
|
||||||
copyUrlToClipboard(issueLink).then(() =>
|
copyUrlToClipboard(issueLink).then(() =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Link copied",
|
title: "Link copied",
|
||||||
message: "Issue link copied to clipboard",
|
message: "Issue link copied to clipboard",
|
||||||
})
|
})
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { CustomMenu } from "@plane/ui";
|
|
||||||
import { ExternalLink, Link, RotateCcw, Trash2 } from "lucide-react";
|
import { ExternalLink, Link, RotateCcw, Trash2 } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import { useEventTracker, useIssues, useUser } from "hooks/store";
|
import { useEventTracker, useIssues, useUser } from "hooks/store";
|
||||||
|
// ui
|
||||||
|
import { CustomMenu, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { DeleteIssueModal } from "components/issues";
|
import { DeleteIssueModal } from "components/issues";
|
||||||
// helpers
|
// helpers
|
||||||
@ -32,16 +32,14 @@ export const ArchivedIssueQuickActions: React.FC<IQuickActionProps> = (props) =>
|
|||||||
// auth
|
// auth
|
||||||
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER && !readOnly;
|
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER && !readOnly;
|
||||||
const isRestoringAllowed = handleRestore && isEditingAllowed;
|
const isRestoringAllowed = handleRestore && isEditingAllowed;
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const issueLink = `${workspaceSlug}/projects/${issue.project_id}/archived-issues/${issue.id}`;
|
const issueLink = `${workspaceSlug}/projects/${issue.project_id}/archived-issues/${issue.id}`;
|
||||||
|
|
||||||
const handleOpenInNewTab = () => window.open(`/${issueLink}`, "_blank");
|
const handleOpenInNewTab = () => window.open(`/${issueLink}`, "_blank");
|
||||||
const handleCopyIssueLink = () =>
|
const handleCopyIssueLink = () =>
|
||||||
copyUrlToClipboard(issueLink).then(() =>
|
copyUrlToClipboard(issueLink).then(() =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Link copied",
|
title: "Link copied",
|
||||||
message: "Issue link copied to clipboard",
|
message: "Issue link copied to clipboard",
|
||||||
})
|
})
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { ArchiveIcon, CustomMenu } from "@plane/ui";
|
|
||||||
import { observer } from "mobx-react";
|
|
||||||
import { Copy, ExternalLink, Link, Pencil, Trash2, XCircle } from "lucide-react";
|
|
||||||
import omit from "lodash/omit";
|
import omit from "lodash/omit";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import { useEventTracker, useIssues, useProjectState, useUser } from "hooks/store";
|
import { useEventTracker, useIssues, useProjectState, useUser } from "hooks/store";
|
||||||
|
// ui
|
||||||
|
import { ArchiveIcon, CustomMenu, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
|
// icons
|
||||||
|
import { Copy, ExternalLink, Link, Pencil, Trash2, XCircle } from "lucide-react";
|
||||||
// components
|
// components
|
||||||
import { ArchiveIssueModal, CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
import { ArchiveIssueModal, CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
||||||
// helpers
|
// helpers
|
||||||
@ -45,8 +46,6 @@ export const CycleIssueQuickActions: React.FC<IQuickActionProps> = observer((pro
|
|||||||
membership: { currentProjectRole },
|
membership: { currentProjectRole },
|
||||||
} = useUser();
|
} = useUser();
|
||||||
const { getStateById } = useProjectState();
|
const { getStateById } = useProjectState();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// derived values
|
// derived values
|
||||||
const stateDetails = getStateById(issue.state_id);
|
const stateDetails = getStateById(issue.state_id);
|
||||||
// auth
|
// auth
|
||||||
@ -64,8 +63,8 @@ export const CycleIssueQuickActions: React.FC<IQuickActionProps> = observer((pro
|
|||||||
|
|
||||||
const handleCopyIssueLink = () =>
|
const handleCopyIssueLink = () =>
|
||||||
copyUrlToClipboard(issueLink).then(() =>
|
copyUrlToClipboard(issueLink).then(() =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Link copied",
|
title: "Link copied",
|
||||||
message: "Issue link copied to clipboard",
|
message: "Issue link copied to clipboard",
|
||||||
})
|
})
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { ArchiveIcon, CustomMenu } from "@plane/ui";
|
|
||||||
import { observer } from "mobx-react";
|
|
||||||
import { Copy, ExternalLink, Link, Pencil, Trash2, XCircle } from "lucide-react";
|
|
||||||
import omit from "lodash/omit";
|
import omit from "lodash/omit";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import { useIssues, useEventTracker, useUser, useProjectState } from "hooks/store";
|
import { useIssues, useEventTracker, useUser, useProjectState } from "hooks/store";
|
||||||
|
// ui
|
||||||
|
import { ArchiveIcon, CustomMenu, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
|
import { Copy, ExternalLink, Link, Pencil, Trash2, XCircle } from "lucide-react";
|
||||||
// components
|
// components
|
||||||
import { ArchiveIssueModal, CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
import { ArchiveIssueModal, CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
||||||
// helpers
|
// helpers
|
||||||
@ -45,8 +45,6 @@ export const ModuleIssueQuickActions: React.FC<IQuickActionProps> = observer((pr
|
|||||||
membership: { currentProjectRole },
|
membership: { currentProjectRole },
|
||||||
} = useUser();
|
} = useUser();
|
||||||
const { getStateById } = useProjectState();
|
const { getStateById } = useProjectState();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// derived values
|
// derived values
|
||||||
const stateDetails = getStateById(issue.state_id);
|
const stateDetails = getStateById(issue.state_id);
|
||||||
// auth
|
// auth
|
||||||
@ -64,8 +62,8 @@ export const ModuleIssueQuickActions: React.FC<IQuickActionProps> = observer((pr
|
|||||||
|
|
||||||
const handleCopyIssueLink = () =>
|
const handleCopyIssueLink = () =>
|
||||||
copyUrlToClipboard(issueLink).then(() =>
|
copyUrlToClipboard(issueLink).then(() =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Link copied",
|
title: "Link copied",
|
||||||
message: "Issue link copied to clipboard",
|
message: "Issue link copied to clipboard",
|
||||||
})
|
})
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { ArchiveIcon, CustomMenu } from "@plane/ui";
|
|
||||||
import { observer } from "mobx-react";
|
|
||||||
import { Copy, ExternalLink, Link, Pencil, Trash2 } from "lucide-react";
|
|
||||||
import omit from "lodash/omit";
|
import omit from "lodash/omit";
|
||||||
|
import { observer } from "mobx-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEventTracker, useIssues, useProjectState, useUser } from "hooks/store";
|
import { useEventTracker, useIssues, useProjectState, useUser } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
// ui
|
||||||
|
import { ArchiveIcon, CustomMenu, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
|
import { Copy, ExternalLink, Link, Pencil, Trash2 } from "lucide-react";
|
||||||
// components
|
// components
|
||||||
import { ArchiveIssueModal, CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
import { ArchiveIssueModal, CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
||||||
// helpers
|
// helpers
|
||||||
@ -54,16 +54,14 @@ export const ProjectIssueQuickActions: React.FC<IQuickActionProps> = observer((p
|
|||||||
!!stateDetails && [STATE_GROUPS.completed.key, STATE_GROUPS.cancelled.key].includes(stateDetails?.group);
|
!!stateDetails && [STATE_GROUPS.completed.key, STATE_GROUPS.cancelled.key].includes(stateDetails?.group);
|
||||||
const isDeletingAllowed = isEditingAllowed;
|
const isDeletingAllowed = isEditingAllowed;
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const issueLink = `${workspaceSlug}/projects/${issue.project_id}/issues/${issue.id}`;
|
const issueLink = `${workspaceSlug}/projects/${issue.project_id}/issues/${issue.id}`;
|
||||||
|
|
||||||
const handleOpenInNewTab = () => window.open(`/${issueLink}`, "_blank");
|
const handleOpenInNewTab = () => window.open(`/${issueLink}`, "_blank");
|
||||||
|
|
||||||
const handleCopyIssueLink = () =>
|
const handleCopyIssueLink = () =>
|
||||||
copyUrlToClipboard(issueLink).then(() =>
|
copyUrlToClipboard(issueLink).then(() =>
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Link copied",
|
title: "Link copied",
|
||||||
message: "Issue link copied to clipboard",
|
message: "Issue link copied to clipboard",
|
||||||
})
|
})
|
||||||
|
@ -5,11 +5,12 @@ import { observer } from "mobx-react-lite";
|
|||||||
import { PlusIcon } from "lucide-react";
|
import { PlusIcon } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEventTracker, useProject, useWorkspace } from "hooks/store";
|
import { useEventTracker, useProject, useWorkspace } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import useKeypress from "hooks/use-keypress";
|
import useKeypress from "hooks/use-keypress";
|
||||||
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
||||||
// helpers
|
// helpers
|
||||||
import { createIssuePayload } from "helpers/issue.helper";
|
import { createIssuePayload } from "helpers/issue.helper";
|
||||||
|
// ui
|
||||||
|
import { TOAST_TYPE, setPromiseToast, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { TIssue } from "@plane/types";
|
import { TIssue } from "@plane/types";
|
||||||
// constants
|
// constants
|
||||||
@ -84,7 +85,6 @@ export const SpreadsheetQuickAddIssueForm: React.FC<Props> = observer((props) =>
|
|||||||
// hooks
|
// hooks
|
||||||
useKeypress("Escape", handleClose);
|
useKeypress("Escape", handleClose);
|
||||||
useOutsideClickDetector(ref, handleClose);
|
useOutsideClickDetector(ref, handleClose);
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setFocus("name");
|
setFocus("name");
|
||||||
@ -100,13 +100,13 @@ export const SpreadsheetQuickAddIssueForm: React.FC<Props> = observer((props) =>
|
|||||||
Object.keys(errors).forEach((key) => {
|
Object.keys(errors).forEach((key) => {
|
||||||
const error = errors[key as keyof TIssue];
|
const error = errors[key as keyof TIssue];
|
||||||
|
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: error?.message?.toString() || "Some error occurred. Please try again.",
|
message: error?.message?.toString() || "Some error occurred. Please try again.",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, [errors, setToastAlert]);
|
}, [errors]);
|
||||||
|
|
||||||
// const onSubmitHandler = async (formData: TIssue) => {
|
// const onSubmitHandler = async (formData: TIssue) => {
|
||||||
// if (isSubmitting || !workspaceSlug || !projectId) return;
|
// if (isSubmitting || !workspaceSlug || !projectId) return;
|
||||||
@ -130,8 +130,8 @@ export const SpreadsheetQuickAddIssueForm: React.FC<Props> = observer((props) =>
|
|||||||
// payload
|
// payload
|
||||||
// );
|
// );
|
||||||
|
|
||||||
// setToastAlert({
|
// setToast({
|
||||||
// type: "success",
|
// type: TOAST_TYPE.SUCCESS,
|
||||||
// title: "Success!",
|
// title: "Success!",
|
||||||
// message: "Issue created successfully.",
|
// message: "Issue created successfully.",
|
||||||
// });
|
// });
|
||||||
@ -140,8 +140,8 @@ export const SpreadsheetQuickAddIssueForm: React.FC<Props> = observer((props) =>
|
|||||||
// const error = err?.[key];
|
// const error = err?.[key];
|
||||||
// const errorTitle = error ? (Array.isArray(error) ? error.join(", ") : error) : null;
|
// const errorTitle = error ? (Array.isArray(error) ? error.join(", ") : error) : null;
|
||||||
|
|
||||||
// setToastAlert({
|
// setToast({
|
||||||
// type: "error",
|
// type: TOAST_TYPE.ERROR,
|
||||||
// title: "Error!",
|
// title: "Error!",
|
||||||
// message: errorTitle || "Some error occurred. Please try again.",
|
// message: errorTitle || "Some error occurred. Please try again.",
|
||||||
// });
|
// });
|
||||||
@ -159,34 +159,41 @@ export const SpreadsheetQuickAddIssueForm: React.FC<Props> = observer((props) =>
|
|||||||
...formData,
|
...formData,
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
if (quickAddCallback) {
|
||||||
quickAddCallback &&
|
const quickAddPromise = quickAddCallback(
|
||||||
(await quickAddCallback(currentWorkspace.slug, currentProjectDetails.id, { ...payload } as TIssue, viewId).then(
|
currentWorkspace.slug,
|
||||||
(res) => {
|
currentProjectDetails.id,
|
||||||
captureIssueEvent({
|
{ ...payload } as TIssue,
|
||||||
eventName: ISSUE_CREATED,
|
viewId
|
||||||
payload: { ...res, state: "SUCCESS", element: "Spreadsheet quick add" },
|
);
|
||||||
path: router.asPath,
|
setPromiseToast<any>(quickAddPromise, {
|
||||||
});
|
loading: "Adding issue...",
|
||||||
}
|
success: {
|
||||||
));
|
title: "Success!",
|
||||||
setToastAlert({
|
message: () => "Issue created successfully.",
|
||||||
type: "success",
|
},
|
||||||
title: "Success!",
|
error: {
|
||||||
message: "Issue created successfully.",
|
title: "Error!",
|
||||||
});
|
message: (err) => err?.message || "Some error occurred. Please try again.",
|
||||||
} catch (err: any) {
|
},
|
||||||
captureIssueEvent({
|
|
||||||
eventName: ISSUE_CREATED,
|
|
||||||
payload: { ...payload, state: "FAILED", element: "Spreadsheet quick add" },
|
|
||||||
path: router.asPath,
|
|
||||||
});
|
|
||||||
console.error(err);
|
|
||||||
setToastAlert({
|
|
||||||
type: "error",
|
|
||||||
title: "Error!",
|
|
||||||
message: err?.message || "Some error occurred. Please try again.",
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await quickAddPromise
|
||||||
|
.then((res) => {
|
||||||
|
captureIssueEvent({
|
||||||
|
eventName: ISSUE_CREATED,
|
||||||
|
payload: { ...res, state: "SUCCESS", element: "Spreadsheet quick add" },
|
||||||
|
path: router.asPath,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
captureIssueEvent({
|
||||||
|
eventName: ISSUE_CREATED,
|
||||||
|
payload: { ...payload, state: "FAILED", element: "Spreadsheet quick add" },
|
||||||
|
path: router.asPath,
|
||||||
|
});
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,10 +2,11 @@ import React, { useState } from "react";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import { useEventTracker } from "hooks/store";
|
import { useEventTracker } from "hooks/store";
|
||||||
// services
|
// services
|
||||||
import { IssueDraftService } from "services/issue";
|
import { IssueDraftService } from "services/issue";
|
||||||
|
// ui
|
||||||
|
import { TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { IssueFormRoot } from "components/issues/issue-modal/form";
|
import { IssueFormRoot } from "components/issues/issue-modal/form";
|
||||||
import { ConfirmIssueDiscard } from "components/issues";
|
import { ConfirmIssueDiscard } from "components/issues";
|
||||||
@ -43,8 +44,6 @@ export const DraftIssueLayout: React.FC<DraftIssueProps> = observer((props) => {
|
|||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// store hooks
|
// store hooks
|
||||||
const { captureIssueEvent } = useEventTracker();
|
const { captureIssueEvent } = useEventTracker();
|
||||||
|
|
||||||
@ -61,8 +60,8 @@ export const DraftIssueLayout: React.FC<DraftIssueProps> = observer((props) => {
|
|||||||
await issueDraftService
|
await issueDraftService
|
||||||
.createDraftIssue(workspaceSlug.toString(), projectId.toString(), payload)
|
.createDraftIssue(workspaceSlug.toString(), projectId.toString(), payload)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Draft Issue created successfully.",
|
message: "Draft Issue created successfully.",
|
||||||
});
|
});
|
||||||
@ -76,8 +75,8 @@ export const DraftIssueLayout: React.FC<DraftIssueProps> = observer((props) => {
|
|||||||
onClose(false);
|
onClose(false);
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Issue could not be created. Please try again.",
|
message: "Issue could not be created. Please try again.",
|
||||||
});
|
});
|
||||||
|
@ -7,7 +7,6 @@ import { LayoutPanelTop, Sparkle, X } from "lucide-react";
|
|||||||
import { RichTextEditorWithRef } from "@plane/rich-text-editor";
|
import { RichTextEditorWithRef } from "@plane/rich-text-editor";
|
||||||
// hooks
|
// hooks
|
||||||
import { useApplication, useEstimate, useIssueDetail, useMention, useProject, useWorkspace } from "hooks/store";
|
import { useApplication, useEstimate, useIssueDetail, useMention, useProject, useWorkspace } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// services
|
// services
|
||||||
import { AIService } from "services/ai.service";
|
import { AIService } from "services/ai.service";
|
||||||
import { FileService } from "services/file.service";
|
import { FileService } from "services/file.service";
|
||||||
@ -27,7 +26,7 @@ import {
|
|||||||
StateDropdown,
|
StateDropdown,
|
||||||
} from "components/dropdowns";
|
} from "components/dropdowns";
|
||||||
// ui
|
// ui
|
||||||
import { Button, CustomMenu, Input, Loader, ToggleSwitch } from "@plane/ui";
|
import { Button, CustomMenu, Input, Loader, ToggleSwitch, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
|
||||||
// types
|
// types
|
||||||
@ -125,8 +124,6 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
|
|||||||
const {
|
const {
|
||||||
issue: { getIssueById },
|
issue: { getIssueById },
|
||||||
} = useIssueDetail();
|
} = useIssueDetail();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// form info
|
// form info
|
||||||
const {
|
const {
|
||||||
formState: { errors, isDirty, isSubmitting },
|
formState: { errors, isDirty, isSubmitting },
|
||||||
@ -199,8 +196,8 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
|
|||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.response === "")
|
if (res.response === "")
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message:
|
message:
|
||||||
"Issue title isn't informative enough to generate the description. Please try with a different title.",
|
"Issue title isn't informative enough to generate the description. Please try with a different title.",
|
||||||
@ -211,14 +208,14 @@ export const IssueFormRoot: FC<IssueFormProps> = observer((props) => {
|
|||||||
const error = err?.data?.error;
|
const error = err?.data?.error;
|
||||||
|
|
||||||
if (err.status === 429)
|
if (err.status === 429)
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: error || "You have reached the maximum number of requests of 50 requests per month per user.",
|
message: error || "You have reached the maximum number of requests of 50 requests per month per user.",
|
||||||
});
|
});
|
||||||
else
|
else
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: error || "Some error occurred. Please try again.",
|
message: error || "Some error occurred. Please try again.",
|
||||||
});
|
});
|
||||||
|
@ -13,11 +13,12 @@ import {
|
|||||||
useWorkspace,
|
useWorkspace,
|
||||||
useIssueDetail,
|
useIssueDetail,
|
||||||
} from "hooks/store";
|
} from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import useLocalStorage from "hooks/use-local-storage";
|
import useLocalStorage from "hooks/use-local-storage";
|
||||||
// components
|
// components
|
||||||
import { DraftIssueLayout } from "./draft-issue-layout";
|
import { DraftIssueLayout } from "./draft-issue-layout";
|
||||||
import { IssueFormRoot } from "./form";
|
import { IssueFormRoot } from "./form";
|
||||||
|
// ui
|
||||||
|
import { TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import type { TIssue } from "@plane/types";
|
import type { TIssue } from "@plane/types";
|
||||||
// constants
|
// constants
|
||||||
@ -89,8 +90,6 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
};
|
};
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
// toast alert
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// local storage
|
// local storage
|
||||||
const { storedValue: localStorageDraftIssues, setValue: setLocalStorageDraftIssue } = useLocalStorage<
|
const { storedValue: localStorageDraftIssues, setValue: setLocalStorageDraftIssue } = useLocalStorage<
|
||||||
Record<string, Partial<TIssue>>
|
Record<string, Partial<TIssue>>
|
||||||
@ -186,9 +185,8 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
await addIssueToCycle(response, payload.cycle_id);
|
await addIssueToCycle(response, payload.cycle_id);
|
||||||
if (payload.module_ids && payload.module_ids.length > 0 && storeType !== EIssuesStoreType.MODULE)
|
if (payload.module_ids && payload.module_ids.length > 0 && storeType !== EIssuesStoreType.MODULE)
|
||||||
await addIssueToModule(response, payload.module_ids);
|
await addIssueToModule(response, payload.module_ids);
|
||||||
|
setToast({
|
||||||
setToastAlert({
|
type: TOAST_TYPE.SUCCESS,
|
||||||
type: "success",
|
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Issue created successfully.",
|
message: "Issue created successfully.",
|
||||||
});
|
});
|
||||||
@ -200,8 +198,8 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
!createMore && handleClose();
|
!createMore && handleClose();
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Issue could not be created. Please try again.",
|
message: "Issue could not be created. Please try again.",
|
||||||
});
|
});
|
||||||
@ -221,8 +219,8 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
? await draftIssues.updateIssue(workspaceSlug, payload.project_id, data.id, payload)
|
? await draftIssues.updateIssue(workspaceSlug, payload.project_id, data.id, payload)
|
||||||
: await currentIssueStore.updateIssue(workspaceSlug, payload.project_id, data.id, payload, viewId);
|
: await currentIssueStore.updateIssue(workspaceSlug, payload.project_id, data.id, payload, viewId);
|
||||||
|
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Issue updated successfully.",
|
message: "Issue updated successfully.",
|
||||||
});
|
});
|
||||||
@ -233,8 +231,8 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = observer((prop
|
|||||||
});
|
});
|
||||||
handleClose();
|
handleClose();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Issue could not be created. Please try again.",
|
message: "Issue could not be created. Please try again.",
|
||||||
});
|
});
|
||||||
|
@ -3,11 +3,18 @@ import { useRouter } from "next/router";
|
|||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { MoveRight, MoveDiagonal, Link2, Trash2, RotateCcw } from "lucide-react";
|
import { MoveRight, MoveDiagonal, Link2, Trash2, RotateCcw } from "lucide-react";
|
||||||
// ui
|
// ui
|
||||||
import { ArchiveIcon, CenterPanelIcon, CustomSelect, FullScreenPanelIcon, SidePanelIcon, Tooltip } from "@plane/ui";
|
import {
|
||||||
|
ArchiveIcon,
|
||||||
|
CenterPanelIcon,
|
||||||
|
CustomSelect,
|
||||||
|
FullScreenPanelIcon,
|
||||||
|
SidePanelIcon,
|
||||||
|
Tooltip,
|
||||||
|
TOAST_TYPE,
|
||||||
|
setToast,
|
||||||
|
} from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { copyUrlToClipboard } from "helpers/string.helper";
|
import { copyUrlToClipboard } from "helpers/string.helper";
|
||||||
// hooks
|
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// store hooks
|
// store hooks
|
||||||
import { useIssueDetail, useProjectState, useUser } from "hooks/store";
|
import { useIssueDetail, useProjectState, useUser } from "hooks/store";
|
||||||
// helpers
|
// helpers
|
||||||
@ -74,8 +81,6 @@ export const IssuePeekOverviewHeader: FC<PeekOverviewHeaderProps> = observer((pr
|
|||||||
issue: { getIssueById },
|
issue: { getIssueById },
|
||||||
} = useIssueDetail();
|
} = useIssueDetail();
|
||||||
const { getStateById } = useProjectState();
|
const { getStateById } = useProjectState();
|
||||||
// hooks
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// derived values
|
// derived values
|
||||||
const issueDetails = getIssueById(issueId);
|
const issueDetails = getIssueById(issueId);
|
||||||
const stateDetails = issueDetails ? getStateById(issueDetails?.state_id) : undefined;
|
const stateDetails = issueDetails ? getStateById(issueDetails?.state_id) : undefined;
|
||||||
@ -87,8 +92,8 @@ export const IssuePeekOverviewHeader: FC<PeekOverviewHeaderProps> = observer((pr
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
copyUrlToClipboard(issueLink).then(() => {
|
copyUrlToClipboard(issueLink).then(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Link Copied!",
|
title: "Link Copied!",
|
||||||
message: "Issue link copied to clipboard.",
|
message: "Issue link copied to clipboard.",
|
||||||
});
|
});
|
||||||
|
@ -2,8 +2,9 @@ import { FC, useEffect, useState, useMemo } from "react";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
import { useEventTracker, useIssueDetail, useIssues, useUser } from "hooks/store";
|
import { useEventTracker, useIssueDetail, useIssues, useUser } from "hooks/store";
|
||||||
|
// ui
|
||||||
|
import { TOAST_TYPE, setPromiseToast, setToast } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { IssueView } from "components/issues";
|
import { IssueView } from "components/issues";
|
||||||
// types
|
// types
|
||||||
@ -20,13 +21,7 @@ interface IIssuePeekOverview {
|
|||||||
|
|
||||||
export type TIssuePeekOperations = {
|
export type TIssuePeekOperations = {
|
||||||
fetch: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
fetch: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
||||||
update: (
|
update: (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => Promise<void>;
|
||||||
workspaceSlug: string,
|
|
||||||
projectId: string,
|
|
||||||
issueId: string,
|
|
||||||
data: Partial<TIssue>,
|
|
||||||
showToast?: boolean
|
|
||||||
) => Promise<void>;
|
|
||||||
remove: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
remove: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
||||||
archive: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
archive: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
||||||
restore: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
restore: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
|
||||||
@ -49,8 +44,6 @@ export type TIssuePeekOperations = {
|
|||||||
|
|
||||||
export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
||||||
const { is_archived = false, is_draft = false } = props;
|
const { is_archived = false, is_draft = false } = props;
|
||||||
// hooks
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const {
|
const {
|
||||||
@ -86,49 +79,38 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||||||
console.error("Error fetching the parent issue");
|
console.error("Error fetching the parent issue");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
update: async (
|
update: async (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => {
|
||||||
workspaceSlug: string,
|
await updateIssue(workspaceSlug, projectId, issueId, data)
|
||||||
projectId: string,
|
.then(() => {
|
||||||
issueId: string,
|
captureIssueEvent({
|
||||||
data: Partial<TIssue>,
|
eventName: ISSUE_UPDATED,
|
||||||
showToast: boolean = true
|
payload: { ...data, issueId, state: "SUCCESS", element: "Issue peek-overview" },
|
||||||
) => {
|
updates: {
|
||||||
try {
|
changed_property: Object.keys(data).join(","),
|
||||||
await updateIssue(workspaceSlug, projectId, issueId, data);
|
change_details: Object.values(data).join(","),
|
||||||
if (showToast)
|
},
|
||||||
setToastAlert({
|
path: router.asPath,
|
||||||
title: "Issue updated successfully",
|
});
|
||||||
type: "success",
|
})
|
||||||
message: "Issue updated successfully",
|
.catch(() => {
|
||||||
|
captureIssueEvent({
|
||||||
|
eventName: ISSUE_UPDATED,
|
||||||
|
payload: { state: "FAILED", element: "Issue peek-overview" },
|
||||||
|
path: router.asPath,
|
||||||
|
});
|
||||||
|
setToast({
|
||||||
|
title: "Issue update failed",
|
||||||
|
type: TOAST_TYPE.ERROR,
|
||||||
|
message: "Issue update failed",
|
||||||
});
|
});
|
||||||
captureIssueEvent({
|
|
||||||
eventName: ISSUE_UPDATED,
|
|
||||||
payload: { ...data, issueId, state: "SUCCESS", element: "Issue peek-overview" },
|
|
||||||
updates: {
|
|
||||||
changed_property: Object.keys(data).join(","),
|
|
||||||
change_details: Object.values(data).join(","),
|
|
||||||
},
|
|
||||||
path: router.asPath,
|
|
||||||
});
|
});
|
||||||
} catch (error) {
|
|
||||||
captureIssueEvent({
|
|
||||||
eventName: ISSUE_UPDATED,
|
|
||||||
payload: { state: "FAILED", element: "Issue peek-overview" },
|
|
||||||
path: router.asPath,
|
|
||||||
});
|
|
||||||
setToastAlert({
|
|
||||||
title: "Issue update failed",
|
|
||||||
type: "error",
|
|
||||||
message: "Issue update failed",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
remove: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
remove: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
||||||
try {
|
try {
|
||||||
removeIssue(workspaceSlug, projectId, issueId);
|
removeIssue(workspaceSlug, projectId, issueId);
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Issue deleted successfully",
|
title: "Issue deleted successfully",
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
message: "Issue deleted successfully",
|
message: "Issue deleted successfully",
|
||||||
});
|
});
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
@ -137,9 +119,9 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Issue delete failed",
|
title: "Issue delete failed",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
message: "Issue delete failed",
|
message: "Issue delete failed",
|
||||||
});
|
});
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
@ -152,8 +134,8 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||||||
archive: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
archive: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
||||||
try {
|
try {
|
||||||
await archiveIssue(workspaceSlug, projectId, issueId);
|
await archiveIssue(workspaceSlug, projectId, issueId);
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Issue archived successfully.",
|
message: "Issue archived successfully.",
|
||||||
});
|
});
|
||||||
@ -163,8 +145,8 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Issue could not be archived. Please try again.",
|
message: "Issue could not be archived. Please try again.",
|
||||||
});
|
});
|
||||||
@ -178,8 +160,8 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||||||
restore: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
restore: async (workspaceSlug: string, projectId: string, issueId: string) => {
|
||||||
try {
|
try {
|
||||||
await restoreIssue(workspaceSlug, projectId, issueId);
|
await restoreIssue(workspaceSlug, projectId, issueId);
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Success!",
|
title: "Success!",
|
||||||
message: "Issue restored successfully.",
|
message: "Issue restored successfully.",
|
||||||
});
|
});
|
||||||
@ -189,8 +171,8 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Issue could not be restored. Please try again.",
|
message: "Issue could not be restored. Please try again.",
|
||||||
});
|
});
|
||||||
@ -203,12 +185,19 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||||||
},
|
},
|
||||||
addIssueToCycle: async (workspaceSlug: string, projectId: string, cycleId: string, issueIds: string[]) => {
|
addIssueToCycle: async (workspaceSlug: string, projectId: string, cycleId: string, issueIds: string[]) => {
|
||||||
try {
|
try {
|
||||||
await addIssueToCycle(workspaceSlug, projectId, cycleId, issueIds);
|
const addToCyclePromise = addIssueToCycle(workspaceSlug, projectId, cycleId, issueIds);
|
||||||
setToastAlert({
|
setPromiseToast(addToCyclePromise, {
|
||||||
title: "Cycle added to issue successfully",
|
loading: "Adding cycle to issue...",
|
||||||
type: "success",
|
success: {
|
||||||
message: "Issue added to issue successfully",
|
title: "Success!",
|
||||||
|
message: () => "Cycle added to issue successfully",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
title: "Error!",
|
||||||
|
message: () => "Cycle add to issue failed",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
await addToCyclePromise;
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
eventName: ISSUE_UPDATED,
|
eventName: ISSUE_UPDATED,
|
||||||
payload: { ...issueIds, state: "SUCCESS", element: "Issue peek-overview" },
|
payload: { ...issueIds, state: "SUCCESS", element: "Issue peek-overview" },
|
||||||
@ -228,21 +217,23 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||||||
},
|
},
|
||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
setToastAlert({
|
|
||||||
title: "Cycle add to issue failed",
|
|
||||||
type: "error",
|
|
||||||
message: "Cycle add to issue failed",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeIssueFromCycle: async (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => {
|
removeIssueFromCycle: async (workspaceSlug: string, projectId: string, cycleId: string, issueId: string) => {
|
||||||
try {
|
try {
|
||||||
const response = await removeIssueFromCycle(workspaceSlug, projectId, cycleId, issueId);
|
const removeFromCyclePromise = removeIssueFromCycle(workspaceSlug, projectId, cycleId, issueId);
|
||||||
setToastAlert({
|
setPromiseToast(removeFromCyclePromise, {
|
||||||
title: "Cycle removed from issue successfully",
|
loading: "Removing cycle from issue...",
|
||||||
type: "success",
|
success: {
|
||||||
message: "Cycle removed from issue successfully",
|
title: "Success!",
|
||||||
|
message: () => "Cycle removed from issue successfully",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
title: "Error!",
|
||||||
|
message: () => "Cycle remove from issue failed",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
const response = await removeFromCyclePromise;
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
eventName: ISSUE_UPDATED,
|
eventName: ISSUE_UPDATED,
|
||||||
payload: { ...response, state: "SUCCESS", element: "Issue peek-overview" },
|
payload: { ...response, state: "SUCCESS", element: "Issue peek-overview" },
|
||||||
@ -253,11 +244,6 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
|
||||||
title: "Cycle remove from issue failed",
|
|
||||||
type: "error",
|
|
||||||
message: "Cycle remove from issue failed",
|
|
||||||
});
|
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
eventName: ISSUE_UPDATED,
|
eventName: ISSUE_UPDATED,
|
||||||
payload: { state: "FAILED", element: "Issue peek-overview" },
|
payload: { state: "FAILED", element: "Issue peek-overview" },
|
||||||
@ -271,12 +257,19 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||||||
},
|
},
|
||||||
addModulesToIssue: async (workspaceSlug: string, projectId: string, issueId: string, moduleIds: string[]) => {
|
addModulesToIssue: async (workspaceSlug: string, projectId: string, issueId: string, moduleIds: string[]) => {
|
||||||
try {
|
try {
|
||||||
const response = await addModulesToIssue(workspaceSlug, projectId, issueId, moduleIds);
|
const addToModulePromise = addModulesToIssue(workspaceSlug, projectId, issueId, moduleIds);
|
||||||
setToastAlert({
|
setPromiseToast(addToModulePromise, {
|
||||||
title: "Module added to issue successfully",
|
loading: "Adding module to issue...",
|
||||||
type: "success",
|
success: {
|
||||||
message: "Module added to issue successfully",
|
title: "Success!",
|
||||||
|
message: () => "Module added to issue successfully",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
title: "Error!",
|
||||||
|
message: () => "Module add to issue failed",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
const response = await addToModulePromise;
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
eventName: ISSUE_UPDATED,
|
eventName: ISSUE_UPDATED,
|
||||||
payload: { ...response, state: "SUCCESS", element: "Issue peek-overview" },
|
payload: { ...response, state: "SUCCESS", element: "Issue peek-overview" },
|
||||||
@ -296,21 +289,23 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||||||
},
|
},
|
||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
setToastAlert({
|
|
||||||
title: "Module add to issue failed",
|
|
||||||
type: "error",
|
|
||||||
message: "Module add to issue failed",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeIssueFromModule: async (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) => {
|
removeIssueFromModule: async (workspaceSlug: string, projectId: string, moduleId: string, issueId: string) => {
|
||||||
try {
|
try {
|
||||||
await removeIssueFromModule(workspaceSlug, projectId, moduleId, issueId);
|
const removeFromModulePromise = removeIssueFromModule(workspaceSlug, projectId, moduleId, issueId);
|
||||||
setToastAlert({
|
setPromiseToast(removeFromModulePromise, {
|
||||||
title: "Module removed from issue successfully",
|
loading: "Removing module from issue...",
|
||||||
type: "success",
|
success: {
|
||||||
message: "Module removed from issue successfully",
|
title: "Success!",
|
||||||
|
message: () => "Module removed from issue successfully",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
title: "Error!",
|
||||||
|
message: () => "Module remove from issue failed",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
await removeFromModulePromise;
|
||||||
captureIssueEvent({
|
captureIssueEvent({
|
||||||
eventName: ISSUE_UPDATED,
|
eventName: ISSUE_UPDATED,
|
||||||
payload: { id: issueId, state: "SUCCESS", element: "Issue peek-overview" },
|
payload: { id: issueId, state: "SUCCESS", element: "Issue peek-overview" },
|
||||||
@ -330,11 +325,6 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||||||
},
|
},
|
||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
setToastAlert({
|
|
||||||
title: "Module remove from issue failed",
|
|
||||||
type: "error",
|
|
||||||
message: "Module remove from issue failed",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeModulesFromIssue: async (
|
removeModulesFromIssue: async (
|
||||||
@ -343,20 +333,19 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||||||
issueId: string,
|
issueId: string,
|
||||||
moduleIds: string[]
|
moduleIds: string[]
|
||||||
) => {
|
) => {
|
||||||
try {
|
const removeModulesFromIssuePromise = removeModulesFromIssue(workspaceSlug, projectId, issueId, moduleIds);
|
||||||
await removeModulesFromIssue(workspaceSlug, projectId, issueId, moduleIds);
|
setPromiseToast(removeModulesFromIssuePromise, {
|
||||||
setToastAlert({
|
loading: "Removing module from issue...",
|
||||||
title: "Module removed from issue successfully",
|
success: {
|
||||||
type: "success",
|
title: "Success!",
|
||||||
message: "Module removed from issue successfully",
|
message: () => "Module removed from issue successfully",
|
||||||
});
|
},
|
||||||
} catch (error) {
|
error: {
|
||||||
setToastAlert({
|
title: "Error!",
|
||||||
title: "Module remove from issue failed",
|
message: () => "Module remove from issue failed",
|
||||||
type: "error",
|
},
|
||||||
message: "Module remove from issue failed",
|
});
|
||||||
});
|
await removeModulesFromIssuePromise;
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
@ -372,7 +361,6 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
|
|||||||
addModulesToIssue,
|
addModulesToIssue,
|
||||||
removeIssueFromModule,
|
removeIssueFromModule,
|
||||||
removeModulesFromIssue,
|
removeModulesFromIssue,
|
||||||
setToastAlert,
|
|
||||||
captureIssueEvent,
|
captureIssueEvent,
|
||||||
router.asPath,
|
router.asPath,
|
||||||
]
|
]
|
||||||
|
@ -5,7 +5,6 @@ import { observer } from "mobx-react-lite";
|
|||||||
// hooks
|
// hooks
|
||||||
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
||||||
import useKeypress from "hooks/use-keypress";
|
import useKeypress from "hooks/use-keypress";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// store hooks
|
// store hooks
|
||||||
import { useIssueDetail } from "hooks/store";
|
import { useIssueDetail } from "hooks/store";
|
||||||
// components
|
// components
|
||||||
@ -50,15 +49,13 @@ export const IssueView: FC<IIssueView> = observer((props) => {
|
|||||||
issue: { getIssueById },
|
issue: { getIssueById },
|
||||||
} = useIssueDetail();
|
} = useIssueDetail();
|
||||||
const issue = getIssueById(issueId);
|
const issue = getIssueById(issueId);
|
||||||
// hooks
|
|
||||||
const { alerts } = useToast();
|
|
||||||
// remove peek id
|
// remove peek id
|
||||||
const removeRoutePeekId = () => {
|
const removeRoutePeekId = () => {
|
||||||
setPeekIssue(undefined);
|
setPeekIssue(undefined);
|
||||||
};
|
};
|
||||||
|
|
||||||
useOutsideClickDetector(issuePeekOverviewRef, () => {
|
useOutsideClickDetector(issuePeekOverviewRef, () => {
|
||||||
if (!isAnyModalOpen && (!alerts || alerts.length === 0)) {
|
if (!isAnyModalOpen) {
|
||||||
removeRoutePeekId();
|
removeRoutePeekId();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -4,14 +4,13 @@ import { observer } from "mobx-react-lite";
|
|||||||
import { Plus, ChevronRight, ChevronDown, Loader } from "lucide-react";
|
import { Plus, ChevronRight, ChevronDown, Loader } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useEventTracker, useIssueDetail } from "hooks/store";
|
import { useEventTracker, useIssueDetail } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// components
|
// components
|
||||||
import { ExistingIssuesListModal } from "components/core";
|
import { ExistingIssuesListModal } from "components/core";
|
||||||
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
||||||
import { IssueList } from "./issues-list";
|
import { IssueList } from "./issues-list";
|
||||||
import { ProgressBar } from "./progressbar";
|
import { ProgressBar } from "./progressbar";
|
||||||
// ui
|
// ui
|
||||||
import { CustomMenu } from "@plane/ui";
|
import { CustomMenu, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { copyTextToClipboard } from "helpers/string.helper";
|
import { copyTextToClipboard } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
@ -46,8 +45,6 @@ export const SubIssuesRoot: FC<ISubIssuesRoot> = observer((props) => {
|
|||||||
const { workspaceSlug, projectId, parentIssueId, disabled = false } = props;
|
const { workspaceSlug, projectId, parentIssueId, disabled = false } = props;
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
// store hooks
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
const {
|
const {
|
||||||
issue: { getIssueById },
|
issue: { getIssueById },
|
||||||
subIssues: { subIssuesByIssueId, stateDistributionByIssueId, subIssueHelpersByIssueId, setSubIssueHelpers },
|
subIssues: { subIssuesByIssueId, stateDistributionByIssueId, subIssueHelpersByIssueId, setSubIssueHelpers },
|
||||||
@ -128,8 +125,8 @@ export const SubIssuesRoot: FC<ISubIssuesRoot> = observer((props) => {
|
|||||||
copyText: (text: string) => {
|
copyText: (text: string) => {
|
||||||
const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
|
const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
|
||||||
copyTextToClipboard(`${originURL}/${text}`).then(() => {
|
copyTextToClipboard(`${originURL}/${text}`).then(() => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Link Copied!",
|
title: "Link Copied!",
|
||||||
message: "Issue link copied to clipboard.",
|
message: "Issue link copied to clipboard.",
|
||||||
});
|
});
|
||||||
@ -139,8 +136,8 @@ export const SubIssuesRoot: FC<ISubIssuesRoot> = observer((props) => {
|
|||||||
try {
|
try {
|
||||||
await fetchSubIssues(workspaceSlug, projectId, parentIssueId);
|
await fetchSubIssues(workspaceSlug, projectId, parentIssueId);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error fetching sub-issues",
|
title: "Error fetching sub-issues",
|
||||||
message: "Error fetching sub-issues",
|
message: "Error fetching sub-issues",
|
||||||
});
|
});
|
||||||
@ -149,14 +146,14 @@ export const SubIssuesRoot: FC<ISubIssuesRoot> = observer((props) => {
|
|||||||
addSubIssue: async (workspaceSlug: string, projectId: string, parentIssueId: string, issueIds: string[]) => {
|
addSubIssue: async (workspaceSlug: string, projectId: string, parentIssueId: string, issueIds: string[]) => {
|
||||||
try {
|
try {
|
||||||
await createSubIssues(workspaceSlug, projectId, parentIssueId, issueIds);
|
await createSubIssues(workspaceSlug, projectId, parentIssueId, issueIds);
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Sub-issues added successfully",
|
title: "Sub-issues added successfully",
|
||||||
message: "Sub-issues added successfully",
|
message: "Sub-issues added successfully",
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error adding sub-issue",
|
title: "Error adding sub-issue",
|
||||||
message: "Error adding sub-issue",
|
message: "Error adding sub-issue",
|
||||||
});
|
});
|
||||||
@ -183,8 +180,8 @@ export const SubIssuesRoot: FC<ISubIssuesRoot> = observer((props) => {
|
|||||||
},
|
},
|
||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Sub-issue updated successfully",
|
title: "Sub-issue updated successfully",
|
||||||
message: "Sub-issue updated successfully",
|
message: "Sub-issue updated successfully",
|
||||||
});
|
});
|
||||||
@ -199,8 +196,8 @@ export const SubIssuesRoot: FC<ISubIssuesRoot> = observer((props) => {
|
|||||||
},
|
},
|
||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error updating sub-issue",
|
title: "Error updating sub-issue",
|
||||||
message: "Error updating sub-issue",
|
message: "Error updating sub-issue",
|
||||||
});
|
});
|
||||||
@ -210,8 +207,8 @@ export const SubIssuesRoot: FC<ISubIssuesRoot> = observer((props) => {
|
|||||||
try {
|
try {
|
||||||
setSubIssueHelpers(parentIssueId, "issue_loader", issueId);
|
setSubIssueHelpers(parentIssueId, "issue_loader", issueId);
|
||||||
await removeSubIssue(workspaceSlug, projectId, parentIssueId, issueId);
|
await removeSubIssue(workspaceSlug, projectId, parentIssueId, issueId);
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Sub-issue removed successfully",
|
title: "Sub-issue removed successfully",
|
||||||
message: "Sub-issue removed successfully",
|
message: "Sub-issue removed successfully",
|
||||||
});
|
});
|
||||||
@ -235,8 +232,8 @@ export const SubIssuesRoot: FC<ISubIssuesRoot> = observer((props) => {
|
|||||||
},
|
},
|
||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error removing sub-issue",
|
title: "Error removing sub-issue",
|
||||||
message: "Error removing sub-issue",
|
message: "Error removing sub-issue",
|
||||||
});
|
});
|
||||||
@ -246,8 +243,8 @@ export const SubIssuesRoot: FC<ISubIssuesRoot> = observer((props) => {
|
|||||||
try {
|
try {
|
||||||
setSubIssueHelpers(parentIssueId, "issue_loader", issueId);
|
setSubIssueHelpers(parentIssueId, "issue_loader", issueId);
|
||||||
await deleteSubIssue(workspaceSlug, projectId, parentIssueId, issueId);
|
await deleteSubIssue(workspaceSlug, projectId, parentIssueId, issueId);
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "success",
|
type: TOAST_TYPE.SUCCESS,
|
||||||
title: "Issue deleted successfully",
|
title: "Issue deleted successfully",
|
||||||
message: "Issue deleted successfully",
|
message: "Issue deleted successfully",
|
||||||
});
|
});
|
||||||
@ -263,15 +260,15 @@ export const SubIssuesRoot: FC<ISubIssuesRoot> = observer((props) => {
|
|||||||
payload: { id: issueId, state: "FAILED", element: "Issue detail page" },
|
payload: { id: issueId, state: "FAILED", element: "Issue detail page" },
|
||||||
path: router.asPath,
|
path: router.asPath,
|
||||||
});
|
});
|
||||||
setToastAlert({
|
setToast({
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
title: "Error deleting issue",
|
title: "Error deleting issue",
|
||||||
message: "Error deleting issue",
|
message: "Error deleting issue",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
[fetchSubIssues, createSubIssues, updateSubIssue, removeSubIssue, deleteSubIssue, setToastAlert, setSubIssueHelpers]
|
[fetchSubIssues, createSubIssues, updateSubIssue, removeSubIssue, deleteSubIssue, setSubIssueHelpers]
|
||||||
);
|
);
|
||||||
|
|
||||||
const issue = getIssueById(parentIssueId);
|
const issue = getIssueById(parentIssueId);
|
||||||
|
@ -32,7 +32,7 @@ export const IssueTitleInput: FC<IssueTitleInputProps> = observer((props) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const textarea = document.querySelector("#title-input");
|
const textarea = document.querySelector("#title-input");
|
||||||
if (debouncedValue && debouncedValue !== value) {
|
if (debouncedValue && debouncedValue !== value) {
|
||||||
issueOperations.update(workspaceSlug, projectId, issueId, { name: debouncedValue }, false).finally(() => {
|
issueOperations.update(workspaceSlug, projectId, issueId, { name: debouncedValue }).finally(() => {
|
||||||
setIsSubmitting("saved");
|
setIsSubmitting("saved");
|
||||||
if (textarea && !textarea.matches(":focus")) {
|
if (textarea && !textarea.matches(":focus")) {
|
||||||
const trimmedTitle = debouncedValue.trim();
|
const trimmedTitle = debouncedValue.trim();
|
||||||
|
@ -7,9 +7,8 @@ import { Dialog, Popover, Transition } from "@headlessui/react";
|
|||||||
import { ChevronDown } from "lucide-react";
|
import { ChevronDown } from "lucide-react";
|
||||||
// hooks
|
// hooks
|
||||||
import { useLabel } from "hooks/store";
|
import { useLabel } from "hooks/store";
|
||||||
import useToast from "hooks/use-toast";
|
|
||||||
// ui
|
// ui
|
||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import type { IIssueLabel, IState } from "@plane/types";
|
import type { IIssueLabel, IState } from "@plane/types";
|
||||||
// constants
|
// constants
|
||||||
@ -64,8 +63,6 @@ export const CreateLabelModal: React.FC<Props> = observer((props) => {
|
|||||||
reset(defaultValues);
|
reset(defaultValues);
|
||||||
};
|
};
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
|
||||||
|
|
||||||
const onSubmit = async (formData: IIssueLabel) => {
|
const onSubmit = async (formData: IIssueLabel) => {
|
||||||
if (!workspaceSlug) return;
|
if (!workspaceSlug) return;
|
||||||
|
|
||||||
@ -75,9 +72,9 @@ export const CreateLabelModal: React.FC<Props> = observer((props) => {
|
|||||||
if (onSuccess) onSuccess(res);
|
if (onSuccess) onSuccess(res);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setToastAlert({
|
setToast({
|
||||||
title: "Oops!",
|
title: "Oops!",
|
||||||
type: "error",
|
type: TOAST_TYPE.ERROR,
|
||||||
message: error?.error ?? "Error while adding the label",
|
message: error?.error ?? "Error while adding the label",
|
||||||
});
|
});
|
||||||
reset(formData);
|
reset(formData);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user