mirror of
https://github.com/hex248/sprint.git
synced 2026-02-07 18:23:03 +00:00
toasts all over
This commit is contained in:
@@ -50,15 +50,19 @@ function AccountDialog({ trigger }: { trigger?: ReactNode }) {
|
||||
setUser(data);
|
||||
setPassword("");
|
||||
setOpen(false);
|
||||
},
|
||||
onError: (errorMessage) => {
|
||||
setError(errorMessage);
|
||||
},
|
||||
});
|
||||
|
||||
toast.success(`Account updated successfully`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
onError: (error) => {
|
||||
setError(error);
|
||||
|
||||
toast.error(`Error updating account: ${error}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { UserRecord } from "@issue/shared";
|
||||
import { type FormEvent, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
@@ -67,9 +68,13 @@ export function AddMemberDialog({
|
||||
userData = data;
|
||||
userId = data.id;
|
||||
},
|
||||
onError: (err) => {
|
||||
setError(err || "user not found");
|
||||
onError: (error) => {
|
||||
setError(error || "user not found");
|
||||
setSubmitting(false);
|
||||
|
||||
toast.error(`Error adding member: ${error}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -90,9 +95,13 @@ export function AddMemberDialog({
|
||||
console.error(actionErr);
|
||||
}
|
||||
},
|
||||
onError: (err) => {
|
||||
setError(err || "failed to add member");
|
||||
onError: (error) => {
|
||||
setError(error || "failed to add member");
|
||||
setSubmitting(false);
|
||||
|
||||
toast.error(`Error adding member: ${error}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
} from "@issue/shared";
|
||||
|
||||
import { type FormEvent, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { useAuthenticatedSession } from "@/components/session-provider";
|
||||
import { StatusSelect } from "@/components/status-select";
|
||||
import StatusTag from "@/components/status-tag";
|
||||
@@ -33,6 +34,7 @@ export function CreateIssue({
|
||||
statuses,
|
||||
trigger,
|
||||
completeAction,
|
||||
errorAction,
|
||||
}: {
|
||||
projectId?: number;
|
||||
sprints?: SprintRecord[];
|
||||
@@ -40,6 +42,7 @@ export function CreateIssue({
|
||||
statuses: Record<string, string>;
|
||||
trigger?: React.ReactNode;
|
||||
completeAction?: (issueNumber: number) => void | Promise<void>;
|
||||
errorAction?: (errorMessage: string) => void | Promise<void>;
|
||||
}) {
|
||||
const { user } = useAuthenticatedSession();
|
||||
|
||||
@@ -113,9 +116,13 @@ export function CreateIssue({
|
||||
console.error(actionErr);
|
||||
}
|
||||
},
|
||||
onError: (message) => {
|
||||
setError(message);
|
||||
onError: (error) => {
|
||||
setError(error);
|
||||
setSubmitting(false);
|
||||
|
||||
toast.error(`Error creating issue: ${error}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
|
||||
@@ -31,9 +31,11 @@ const slugify = (value: string) =>
|
||||
export function CreateOrganisation({
|
||||
trigger,
|
||||
completeAction,
|
||||
errorAction,
|
||||
}: {
|
||||
trigger?: React.ReactNode;
|
||||
completeAction?: (org: OrganisationRecord) => void | Promise<void>;
|
||||
errorAction?: (errorMessage: string) => void | Promise<void>;
|
||||
}) {
|
||||
const { user } = useAuthenticatedSession();
|
||||
|
||||
@@ -93,9 +95,14 @@ export function CreateOrganisation({
|
||||
console.error(actionErr);
|
||||
}
|
||||
},
|
||||
onError: (err) => {
|
||||
onError: async (err) => {
|
||||
setError(err || "failed to create organisation");
|
||||
setSubmitting(false);
|
||||
try {
|
||||
await errorAction?.(err || "failed to create organisation");
|
||||
} catch (actionErr) {
|
||||
console.error(actionErr);
|
||||
}
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { PROJECT_NAME_MAX_LENGTH, type ProjectRecord } from "@issue/shared";
|
||||
import { type FormEvent, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { useAuthenticatedSession } from "@/components/session-provider";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
@@ -98,9 +99,13 @@ export function CreateProject({
|
||||
console.error(actionErr);
|
||||
}
|
||||
},
|
||||
onError: (message) => {
|
||||
setError(message);
|
||||
onError: (error) => {
|
||||
setError(error);
|
||||
setSubmitting(false);
|
||||
|
||||
toast.error(`Error creating project: ${error}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { DEFAULT_SPRINT_COLOUR, type SprintRecord } from "@issue/shared";
|
||||
import { type FormEvent, useMemo, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { useAuthenticatedSession } from "@/components/session-provider";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
@@ -134,9 +135,13 @@ export function CreateSprint({
|
||||
console.error(actionErr);
|
||||
}
|
||||
},
|
||||
onError: (message) => {
|
||||
setError(message);
|
||||
onError: (error) => {
|
||||
setError(error);
|
||||
setSubmitting(false);
|
||||
|
||||
toast.error(`Error creating sprint: ${error}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
} catch (submitError) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import { SelectTrigger } from "@/components/ui/select";
|
||||
import { UserSelect } from "@/components/user-select";
|
||||
import { issue } from "@/lib/server";
|
||||
import { issueID } from "@/lib/utils";
|
||||
import SmallSprintDisplay from "./small-sprint-display";
|
||||
import { SprintSelect } from "./sprint-select";
|
||||
|
||||
export function IssueDetailPane({
|
||||
@@ -68,10 +69,40 @@ export function IssueDetailPane({
|
||||
sprintId: newSprintId,
|
||||
onSuccess: () => {
|
||||
onIssueUpdate?.();
|
||||
|
||||
toast.success(
|
||||
<>
|
||||
Successfully updated sprint to{" "}
|
||||
{value === "unassigned" ? (
|
||||
"Unassigned"
|
||||
) : (
|
||||
<SmallSprintDisplay sprint={sprints.find((s) => s.id === newSprintId)} />
|
||||
)}{" "}
|
||||
for {issueID(project.Project.key, issueData.Issue.number)}
|
||||
</>,
|
||||
{
|
||||
dismissible: false,
|
||||
},
|
||||
);
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error("error updating sprint:", error);
|
||||
setSprintId(issueData.Issue.sprintId?.toString() ?? "unassigned");
|
||||
|
||||
toast.error(
|
||||
<>
|
||||
Error updating sprint to{" "}
|
||||
{value === "unassigned" ? (
|
||||
"Unassigned"
|
||||
) : (
|
||||
<SmallSprintDisplay sprint={sprints.find((s) => s.id === newSprintId)} />
|
||||
)}{" "}
|
||||
for {issueID(project.Project.key, issueData.Issue.number)}
|
||||
</>,
|
||||
{
|
||||
dismissible: false,
|
||||
},
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -96,6 +127,10 @@ export function IssueDetailPane({
|
||||
onError: (error) => {
|
||||
console.error("error updating assignee:", error);
|
||||
setAssigneeId(issueData.Issue.assigneeId?.toString() ?? "unassigned");
|
||||
|
||||
toast.error(`Error updating assignee: ${error}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -119,6 +154,10 @@ export function IssueDetailPane({
|
||||
onError: (error) => {
|
||||
console.error("error updating status:", error);
|
||||
setStatus(issueData.Issue.status);
|
||||
|
||||
toast.error(`Error updating status: ${error}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -148,9 +187,23 @@ export function IssueDetailPane({
|
||||
issueId: issueData.Issue.id,
|
||||
onSuccess: async () => {
|
||||
await onIssueDelete?.(issueData.Issue.id);
|
||||
|
||||
toast.success(`Deleted issue ${issueID(project.Project.key, issueData.Issue.number)}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error("error deleting issue:", error);
|
||||
console.error(
|
||||
`error deleting issue ${issueID(project.Project.key, issueData.Issue.number)}`,
|
||||
error,
|
||||
);
|
||||
|
||||
toast.error(
|
||||
`Error deleting issue ${issueID(project.Project.key, issueData.Issue.number)}: ${error}`,
|
||||
{
|
||||
dismissible: false,
|
||||
},
|
||||
);
|
||||
},
|
||||
});
|
||||
setDeleteOpen(false);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { OrganisationRecord, OrganisationResponse } from "@issue/shared";
|
||||
import { useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { CreateOrganisation } from "@/components/create-organisation";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
@@ -86,6 +87,11 @@ export function OrganisationSelect({
|
||||
console.error(err);
|
||||
}
|
||||
}}
|
||||
errorAction={async (errorMessage) => {
|
||||
toast.error(`Error creating organisation: ${errorMessage}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
@@ -98,6 +98,10 @@ function OrganisationsDialog({
|
||||
onError: (error) => {
|
||||
console.error(error);
|
||||
setMembers([]);
|
||||
|
||||
toast.error(`Error fetching members: ${error}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
@@ -125,15 +129,23 @@ function OrganisationsDialog({
|
||||
role: newRole,
|
||||
onSuccess: () => {
|
||||
closeConfirmDialog();
|
||||
|
||||
toast.success(`${capitalise(action)}d ${memberName} to ${newRole} successfully`, {
|
||||
dismissible: false,
|
||||
});
|
||||
|
||||
void refetchMembers();
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(error);
|
||||
},
|
||||
});
|
||||
|
||||
toast.success(`${capitalise(action)}d ${memberName} to ${newRole} successfully`, {
|
||||
toast.error(
|
||||
`Error ${action.slice(0, -1)}ing ${memberName} to ${newRole}: ${error}`,
|
||||
{
|
||||
dismissible: false,
|
||||
},
|
||||
);
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
@@ -162,12 +174,6 @@ function OrganisationsDialog({
|
||||
userId: memberUserId,
|
||||
onSuccess: () => {
|
||||
closeConfirmDialog();
|
||||
void refetchMembers();
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(error);
|
||||
},
|
||||
});
|
||||
|
||||
toast.success(
|
||||
`Removed ${memberName} from ${selectedOrganisation.Organisation.name} successfully`,
|
||||
@@ -175,6 +181,20 @@ function OrganisationsDialog({
|
||||
dismissible: false,
|
||||
},
|
||||
);
|
||||
|
||||
void refetchMembers();
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(error);
|
||||
|
||||
toast.error(
|
||||
`Error removing member from ${selectedOrganisation.Organisation.name}: ${error}`,
|
||||
{
|
||||
dismissible: false,
|
||||
},
|
||||
);
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
@@ -191,6 +211,8 @@ function OrganisationsDialog({
|
||||
const updateStatuses = async (
|
||||
newStatuses: Record<string, string>,
|
||||
statusRemoved?: { name: string; colour: string },
|
||||
statusAdded?: { name: string; colour: string },
|
||||
statusMoved?: { name: string; colour: string; currentIndex: number; nextIndex: number },
|
||||
) => {
|
||||
if (!selectedOrganisation) return;
|
||||
|
||||
@@ -200,7 +222,17 @@ function OrganisationsDialog({
|
||||
statuses: newStatuses,
|
||||
onSuccess: () => {
|
||||
setStatuses(newStatuses);
|
||||
if (statusRemoved) {
|
||||
if (statusAdded) {
|
||||
toast.success(
|
||||
<>
|
||||
Created <StatusTag status={statusAdded.name} colour={statusAdded.colour} />{" "}
|
||||
status successfully
|
||||
</>,
|
||||
{
|
||||
dismissible: false,
|
||||
},
|
||||
);
|
||||
} else if (statusRemoved) {
|
||||
toast.success(
|
||||
<>
|
||||
Removed{" "}
|
||||
@@ -211,11 +243,58 @@ function OrganisationsDialog({
|
||||
dismissible: false,
|
||||
},
|
||||
);
|
||||
} else if (statusMoved) {
|
||||
toast.success(
|
||||
<>
|
||||
Moved <StatusTag status={statusMoved.name} colour={statusMoved.colour} /> from
|
||||
position {statusMoved.currentIndex + 1} to {statusMoved.nextIndex + 1}{" "}
|
||||
successfully
|
||||
</>,
|
||||
{
|
||||
dismissible: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
void refetchOrganisations();
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error("error updating statuses:", error);
|
||||
|
||||
if (statusAdded) {
|
||||
toast.error(
|
||||
<>
|
||||
Error adding{" "}
|
||||
<StatusTag status={statusAdded.name} colour={statusAdded.colour} /> to{" "}
|
||||
{selectedOrganisation.Organisation.name}: {error}
|
||||
</>,
|
||||
{
|
||||
dismissible: false,
|
||||
},
|
||||
);
|
||||
} else if (statusRemoved) {
|
||||
toast.error(
|
||||
<>
|
||||
Error removing{" "}
|
||||
<StatusTag status={statusRemoved.name} colour={statusRemoved.colour} /> from{" "}
|
||||
{selectedOrganisation.Organisation.name}: {error}
|
||||
</>,
|
||||
{
|
||||
dismissible: false,
|
||||
},
|
||||
);
|
||||
} else if (statusMoved) {
|
||||
toast.error(
|
||||
<>
|
||||
Error moving{" "}
|
||||
<StatusTag status={statusMoved.name} colour={statusMoved.colour} />
|
||||
from position {statusMoved.currentIndex + 1} to {statusMoved.nextIndex + 1}{" "}
|
||||
{selectedOrganisation.Organisation.name}: {error}
|
||||
</>,
|
||||
{
|
||||
dismissible: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
@@ -240,17 +319,7 @@ function OrganisationsDialog({
|
||||
}
|
||||
const newStatuses = { ...statuses };
|
||||
newStatuses[trimmed] = newStatusColour;
|
||||
await updateStatuses(newStatuses);
|
||||
|
||||
toast.success(
|
||||
<>
|
||||
Created <StatusTag status={newStatusName.trim()} colour={newStatusColour} /> status
|
||||
successfully
|
||||
</>,
|
||||
{
|
||||
dismissible: false,
|
||||
},
|
||||
);
|
||||
await updateStatuses(newStatuses, undefined, { name: trimmed, colour: newStatusColour });
|
||||
|
||||
setNewStatusName("");
|
||||
setNewStatusColour(DEFAULT_STATUS_COLOUR);
|
||||
@@ -282,6 +351,16 @@ function OrganisationsDialog({
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error("error checking status usage:", error);
|
||||
|
||||
toast.error(
|
||||
<>
|
||||
Error checking status usage for{" "}
|
||||
<StatusTag status={status} colour={statuses[status]} />: {error}
|
||||
</>,
|
||||
{
|
||||
dismissible: false,
|
||||
},
|
||||
);
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
@@ -301,15 +380,11 @@ function OrganisationsDialog({
|
||||
nextStatuses[currentIndex],
|
||||
];
|
||||
|
||||
await updateStatuses(Object.fromEntries(nextStatuses.map((status) => [status, statuses[status]])));
|
||||
toast.success(
|
||||
<>
|
||||
Moved <StatusTag status={status} colour={statuses[status]} /> from position {currentIndex + 1}{" "}
|
||||
to {nextIndex + 1} successfully
|
||||
</>,
|
||||
{
|
||||
dismissible: false,
|
||||
},
|
||||
await updateStatuses(
|
||||
Object.fromEntries(nextStatuses.map((status) => [status, statuses[status]])),
|
||||
undefined,
|
||||
undefined,
|
||||
{ name: status, colour: statuses[status], currentIndex, nextIndex },
|
||||
);
|
||||
};
|
||||
|
||||
@@ -331,6 +406,17 @@ function OrganisationsDialog({
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error("error replacing status:", error);
|
||||
|
||||
toast.error(
|
||||
<>
|
||||
Error removing <StatusTag status={statusToRemove} colour={statuses[statusToRemove]} />{" "}
|
||||
from
|
||||
{selectedOrganisation.Organisation.name}: {error}{" "}
|
||||
</>,
|
||||
{
|
||||
dismissible: false,
|
||||
},
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
||||
@@ -482,6 +568,7 @@ function OrganisationsDialog({
|
||||
dismissible: false,
|
||||
},
|
||||
);
|
||||
|
||||
refetchMembers();
|
||||
}}
|
||||
trigger={
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { TimerState } from "@issue/shared";
|
||||
import { useEffect, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { timer } from "@/lib/server";
|
||||
import { formatTime } from "@/lib/utils";
|
||||
|
||||
@@ -24,9 +25,13 @@ export function TimerDisplay({ issueId }: { issueId: number }) {
|
||||
setWorkTimeMs(data?.workTimeMs ?? 0);
|
||||
setError(null);
|
||||
},
|
||||
onError: (message) => {
|
||||
onError: (error) => {
|
||||
if (!isMounted) return;
|
||||
setError(message);
|
||||
setError(error);
|
||||
|
||||
toast.error(`Error fetching timer data: ${error}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -42,9 +47,13 @@ export function TimerDisplay({ issueId }: { issueId: number }) {
|
||||
setInactiveWorkTimeMs(totalWorkTime);
|
||||
setError(null);
|
||||
},
|
||||
onError: (message) => {
|
||||
onError: (error) => {
|
||||
if (!isMounted) return;
|
||||
setError(message);
|
||||
setError(error);
|
||||
|
||||
toast.error(`Error fetching timer data: ${error}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@@ -38,15 +38,25 @@ export function UploadAvatar({
|
||||
onSuccess: (url) => {
|
||||
onAvatarUploaded(url);
|
||||
setUploading(false);
|
||||
},
|
||||
onError: (msg) => {
|
||||
setError(msg);
|
||||
setUploading(false);
|
||||
},
|
||||
});
|
||||
|
||||
toast.success(`Avatar uploaded successfully`, {
|
||||
toast.success(
|
||||
<div className="flex flex-col items-center gap-4">
|
||||
<img src={url} alt="Avatar" className="w-32 h-32" />
|
||||
Avatar uploaded successfully
|
||||
</div>,
|
||||
{
|
||||
dismissible: false,
|
||||
},
|
||||
);
|
||||
},
|
||||
onError: (error) => {
|
||||
setError(error);
|
||||
setUploading(false);
|
||||
|
||||
toast.error(`Error uploading avatar: ${error}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -168,6 +168,12 @@ export default function App() {
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error("error fetching organisations:", error);
|
||||
setOrganisations([]);
|
||||
setSelectedOrganisation(null);
|
||||
|
||||
toast.error(`Error fetching organisations: ${error}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
@@ -240,6 +246,12 @@ export default function App() {
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error("error fetching projects:", error);
|
||||
setProjects([]);
|
||||
setSelectedProject(null);
|
||||
|
||||
toast.error(`Error fetching projects: ${error}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
@@ -258,6 +270,10 @@ export default function App() {
|
||||
onError: (error) => {
|
||||
console.error("error fetching members:", error);
|
||||
setMembers([]);
|
||||
|
||||
toast.error(`Error fetching members: ${error}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
@@ -276,6 +292,10 @@ export default function App() {
|
||||
onError: (error) => {
|
||||
console.error("error fetching sprints:", error);
|
||||
setSprints([]);
|
||||
|
||||
toast.error(`Error fetching sprints: ${error}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
@@ -324,6 +344,11 @@ export default function App() {
|
||||
onError: (error) => {
|
||||
console.error("error fetching issues:", error);
|
||||
setIssues([]);
|
||||
setSelectedIssue(null);
|
||||
|
||||
toast.error(`Error fetching issues: ${error}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
@@ -413,9 +438,11 @@ export default function App() {
|
||||
}}
|
||||
onCreateProject={async (project) => {
|
||||
if (!selectedOrganisation) return;
|
||||
|
||||
toast.success(`Created Project ${project.name}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
|
||||
await refetchProjects(selectedOrganisation.Organisation.id, {
|
||||
selectProjectId: project.id,
|
||||
});
|
||||
@@ -440,6 +467,11 @@ export default function App() {
|
||||
);
|
||||
await refetchIssues();
|
||||
}}
|
||||
errorAction={async (errorMessage) => {
|
||||
toast.error(`Error creating issue: ${errorMessage}`, {
|
||||
dismissible: false,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
{isAdmin && (
|
||||
<CreateSprint
|
||||
|
||||
Reference in New Issue
Block a user