mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: update empty states, fix: delete issue modal (#1743)
* chore: update empty states * fix: delete issue modal --------- Co-authored-by: Aaryan Khandelwal <aaryankhandu123@gmail.com>
This commit is contained in:
parent
e48147f87e
commit
4e297d92f3
@ -21,9 +21,9 @@ import {
|
||||
GanttChartView,
|
||||
} from "components/core";
|
||||
// ui
|
||||
import { EmptyState, SecondaryButton, Spinner } from "components/ui";
|
||||
import { EmptyState, Spinner } from "components/ui";
|
||||
// icons
|
||||
import { PlusIcon, TrashIcon } from "@heroicons/react/24/outline";
|
||||
import { TrashIcon } from "@heroicons/react/24/outline";
|
||||
// images
|
||||
import emptyIssue from "public/empty-state/issue.svg";
|
||||
import emptyIssueArchive from "public/empty-state/issue-archive.svg";
|
||||
@ -39,6 +39,16 @@ type Props = {
|
||||
addIssueToGroup: (groupTitle: string) => void;
|
||||
disableUserActions: boolean;
|
||||
dragDisabled?: boolean;
|
||||
emptyState: {
|
||||
title: string;
|
||||
description?: string;
|
||||
primaryButton?: {
|
||||
icon: any;
|
||||
text: string;
|
||||
onClick: () => void;
|
||||
};
|
||||
secondaryButton?: React.ReactNode;
|
||||
};
|
||||
handleIssueAction: (issue: IIssue, action: "copy" | "delete" | "edit") => void;
|
||||
handleOnDragEnd: (result: DropResult) => Promise<void>;
|
||||
openIssuesListModal: (() => void) | null;
|
||||
@ -53,6 +63,7 @@ export const AllViews: React.FC<Props> = ({
|
||||
addIssueToGroup,
|
||||
disableUserActions,
|
||||
dragDisabled = false,
|
||||
emptyState,
|
||||
handleIssueAction,
|
||||
handleOnDragEnd,
|
||||
openIssuesListModal,
|
||||
@ -156,41 +167,28 @@ export const AllViews: React.FC<Props> = ({
|
||||
title="Archived Issues will be shown here"
|
||||
description="All the issues that have been in the completed or canceled groups for the configured period of time can be viewed here."
|
||||
image={emptyIssueArchive}
|
||||
buttonText="Go to Automation Settings"
|
||||
onClick={() => {
|
||||
primaryButton={{
|
||||
text: "Go to Automation Settings",
|
||||
onClick: () => {
|
||||
router.push(`/${workspaceSlug}/projects/${projectId}/settings/automations`);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<EmptyState
|
||||
title={
|
||||
cycleId
|
||||
? "Cycle issues will appear here"
|
||||
: moduleId
|
||||
? "Module issues will appear here"
|
||||
: "Project issues will appear here"
|
||||
}
|
||||
description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done."
|
||||
title={emptyState.title}
|
||||
description={emptyState.description}
|
||||
image={emptyIssue}
|
||||
buttonText="New Issue"
|
||||
buttonIcon={<PlusIcon className="h-4 w-4" />}
|
||||
secondaryButton={
|
||||
cycleId || moduleId ? (
|
||||
<SecondaryButton
|
||||
className="flex items-center gap-1.5"
|
||||
onClick={openIssuesListModal ?? (() => {})}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
Add an existing issue
|
||||
</SecondaryButton>
|
||||
) : null
|
||||
primaryButton={
|
||||
emptyState.primaryButton
|
||||
? {
|
||||
icon: emptyState.primaryButton.icon,
|
||||
text: emptyState.primaryButton.text,
|
||||
onClick: emptyState.primaryButton.onClick,
|
||||
}
|
||||
onClick={() => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "c",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
: undefined
|
||||
}
|
||||
secondaryButton={emptyState.secondaryButton}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
|
@ -22,7 +22,7 @@ import { FiltersList, AllViews } from "components/core";
|
||||
import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues";
|
||||
import { CreateUpdateViewModal } from "components/views";
|
||||
// ui
|
||||
import { PrimaryButton } from "components/ui";
|
||||
import { PrimaryButton, SecondaryButton } from "components/ui";
|
||||
// icons
|
||||
import { PlusIcon } from "@heroicons/react/24/outline";
|
||||
// helpers
|
||||
@ -515,6 +515,35 @@ export const IssuesView: React.FC<Props> = ({
|
||||
selectedGroup === "labels" ||
|
||||
selectedGroup === "state_detail.group"
|
||||
}
|
||||
emptyState={{
|
||||
title: cycleId
|
||||
? "Cycle issues will appear here"
|
||||
: moduleId
|
||||
? "Module issues will appear here"
|
||||
: "Project issues will appear here",
|
||||
description:
|
||||
"Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done.",
|
||||
primaryButton: {
|
||||
icon: <PlusIcon className="h-4 w-4" />,
|
||||
text: "New Issue",
|
||||
onClick: () => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "c",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
},
|
||||
},
|
||||
secondaryButton:
|
||||
cycleId || moduleId ? (
|
||||
<SecondaryButton
|
||||
className="flex items-center gap-1.5"
|
||||
onClick={openIssuesListModal ?? (() => {})}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
Add an existing issue
|
||||
</SecondaryButton>
|
||||
) : null,
|
||||
}}
|
||||
handleOnDragEnd={handleOnDragEnd}
|
||||
handleIssueAction={handleIssueAction}
|
||||
openIssuesListModal={openIssuesListModal ? openIssuesListModal : null}
|
||||
|
@ -59,8 +59,9 @@ export const DeleteIssueModal: React.FC<Props> = ({ isOpen, handleClose, data, u
|
||||
};
|
||||
|
||||
const handleDeletion = async () => {
|
||||
if (!workspaceSlug || !data) return;
|
||||
|
||||
setIsDeleteLoading(true);
|
||||
if (!workspaceSlug || !projectId || !data) return;
|
||||
|
||||
await issueServices
|
||||
.deleteIssue(workspaceSlug as string, data.project, data.id, user)
|
||||
@ -112,7 +113,7 @@ export const DeleteIssueModal: React.FC<Props> = ({ isOpen, handleClose, data, u
|
||||
} else {
|
||||
if (cycleId) mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params));
|
||||
else if (moduleId) mutate(MODULE_ISSUES_WITH_PARAMS(moduleId as string, params));
|
||||
else mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params));
|
||||
else mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(data.project, params));
|
||||
}
|
||||
|
||||
handleClose();
|
||||
|
@ -21,6 +21,7 @@ import { orderArrayBy } from "helpers/array.helper";
|
||||
import { IIssue, IIssueFilterOptions } from "types";
|
||||
// fetch-keys
|
||||
import { USER_ISSUES, WORKSPACE_LABELS } from "constants/fetch-keys";
|
||||
import { PlusIcon } from "@heroicons/react/24/outline";
|
||||
|
||||
type Props = {
|
||||
openIssuesListModal?: () => void;
|
||||
@ -262,6 +263,20 @@ export const MyIssuesView: React.FC<Props> = ({
|
||||
addIssueToGroup={addIssueToGroup}
|
||||
disableUserActions={disableUserActions}
|
||||
dragDisabled={groupBy !== "priority"}
|
||||
emptyState={{
|
||||
title: "You don't have any issue assigned to you yet",
|
||||
description: "Keep track of your work in a single place.",
|
||||
primaryButton: {
|
||||
icon: <PlusIcon className="h-4 w-4" />,
|
||||
text: "New Issue",
|
||||
onClick: () => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "c",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
},
|
||||
},
|
||||
}}
|
||||
handleOnDragEnd={handleOnDragEnd}
|
||||
handleIssueAction={handleIssueAction}
|
||||
openIssuesListModal={openIssuesListModal ? openIssuesListModal : null}
|
||||
|
@ -56,13 +56,15 @@ export const RecentPagesList: React.FC<TPagesListProps> = ({ viewType }) => {
|
||||
title="Have your thoughts in place"
|
||||
description="You can think of Pages as an AI-powered notepad."
|
||||
image={emptyPage}
|
||||
buttonText="New Page"
|
||||
buttonIcon={<PlusIcon className="h-4 w-4" />}
|
||||
onClick={() => {
|
||||
primaryButton={{
|
||||
icon: <PlusIcon className="h-4 w-4" />,
|
||||
text: "New Page",
|
||||
onClick: () => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "d",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
@ -260,13 +260,15 @@ export const PagesView: React.FC<Props> = ({ pages, viewType }) => {
|
||||
title="Have your thoughts in place"
|
||||
description="You can think of Pages as an AI-powered notepad."
|
||||
image={emptyPage}
|
||||
buttonText="New Page"
|
||||
buttonIcon={<PlusIcon className="h-4 w-4" />}
|
||||
onClick={() => {
|
||||
primaryButton={{
|
||||
icon: <PlusIcon className="h-4 w-4" />,
|
||||
text: "New Page",
|
||||
onClick: () => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "d",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
@ -140,10 +140,26 @@ export const ProfileIssuesView = () => {
|
||||
]
|
||||
);
|
||||
|
||||
const addIssueToGroup = useCallback((groupTitle: string) => {
|
||||
const addIssueToGroup = useCallback(
|
||||
(groupTitle: string) => {
|
||||
setCreateIssueModal(true);
|
||||
return;
|
||||
}, []);
|
||||
|
||||
let preloadedValue: string | string[] = groupTitle;
|
||||
|
||||
if (groupByProperty === "labels") {
|
||||
if (groupTitle === "None") preloadedValue = [];
|
||||
else preloadedValue = [groupTitle];
|
||||
}
|
||||
|
||||
if (groupByProperty)
|
||||
setPreloadedData({
|
||||
[groupByProperty]: preloadedValue,
|
||||
actionType: "createIssue",
|
||||
});
|
||||
else setPreloadedData({ actionType: "createIssue" });
|
||||
},
|
||||
[setCreateIssueModal, setPreloadedData, groupByProperty]
|
||||
);
|
||||
|
||||
const addIssueToDate = useCallback(
|
||||
(date: string) => {
|
||||
@ -250,6 +266,13 @@ export const ProfileIssuesView = () => {
|
||||
addIssueToGroup={addIssueToGroup}
|
||||
disableUserActions={false}
|
||||
dragDisabled={groupByProperty !== "priority"}
|
||||
emptyState={{
|
||||
title: router.pathname.includes("assigned")
|
||||
? `Issues assigned to ${user?.first_name} ${user?.last_name} will appear here`
|
||||
: router.pathname.includes("created")
|
||||
? `Issues created by ${user?.first_name} ${user?.last_name} will appear here`
|
||||
: `Issues subscribed by ${user?.first_name} ${user?.last_name} will appear here`,
|
||||
}}
|
||||
handleOnDragEnd={handleOnDragEnd}
|
||||
handleIssueAction={handleIssueAction}
|
||||
openIssuesListModal={null}
|
||||
|
@ -9,10 +9,12 @@ type Props = {
|
||||
title: string;
|
||||
description: React.ReactNode | string;
|
||||
image: any;
|
||||
buttonText?: string;
|
||||
buttonIcon?: any;
|
||||
primaryButton?: {
|
||||
icon?: any;
|
||||
text: string;
|
||||
onClick: () => void;
|
||||
};
|
||||
secondaryButton?: React.ReactNode;
|
||||
onClick?: () => void;
|
||||
isFullScreen?: boolean;
|
||||
};
|
||||
|
||||
@ -20,9 +22,7 @@ export const EmptyState: React.FC<Props> = ({
|
||||
title,
|
||||
description,
|
||||
image,
|
||||
onClick,
|
||||
buttonText,
|
||||
buttonIcon,
|
||||
primaryButton,
|
||||
secondaryButton,
|
||||
isFullScreen = true,
|
||||
}) => (
|
||||
@ -32,14 +32,14 @@ export const EmptyState: React.FC<Props> = ({
|
||||
}`}
|
||||
>
|
||||
<div className="text-center flex flex-col items-center w-full">
|
||||
<Image src={image} className="w-52 sm:w-60" alt={buttonText} />
|
||||
<Image src={image} className="w-52 sm:w-60" alt={primaryButton?.text} />
|
||||
<h6 className="text-xl font-semibold mt-6 sm:mt-8 mb-3">{title}</h6>
|
||||
<p className="text-custom-text-300 mb-7 sm:mb-8">{description}</p>
|
||||
<div className="flex items-center gap-4">
|
||||
{buttonText && (
|
||||
<PrimaryButton className="flex items-center gap-1.5" onClick={onClick}>
|
||||
{buttonIcon}
|
||||
{buttonText}
|
||||
{primaryButton && (
|
||||
<PrimaryButton className="flex items-center gap-1.5" onClick={primaryButton.onClick}>
|
||||
{primaryButton.icon}
|
||||
{primaryButton.text}
|
||||
</PrimaryButton>
|
||||
)}
|
||||
{secondaryButton}
|
||||
|
@ -71,12 +71,14 @@ const ProjectAuthorizationWrapped: React.FC<Props> = ({
|
||||
title="No such project exists"
|
||||
description="Try creating a new project"
|
||||
image={emptyProject}
|
||||
buttonText="Create Project"
|
||||
onClick={() => {
|
||||
primaryButton={{
|
||||
text: "Create Project",
|
||||
onClick: () => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "p",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
@ -134,13 +134,15 @@ const Analytics = () => {
|
||||
title="You can see your all projects' analytics here"
|
||||
description="Let's create your first project and analyse the stats with various graphs."
|
||||
image={emptyAnalytics}
|
||||
buttonText="New Project"
|
||||
buttonIcon={<PlusIcon className="h-4 w-4" />}
|
||||
onClick={() => {
|
||||
primaryButton={{
|
||||
icon: <PlusIcon className="h-4 w-4" />,
|
||||
text: "New Project",
|
||||
onClick: () => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "p",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
@ -121,13 +121,15 @@ const ProjectCycles: NextPage = () => {
|
||||
title="Plan your project with cycles"
|
||||
description="Cycle is a custom time period in which a team works to complete items on their backlog."
|
||||
image={emptyCycle}
|
||||
buttonText="New Cycle"
|
||||
buttonIcon={<PlusIcon className="h-4 w-4" />}
|
||||
onClick={() => {
|
||||
primaryButton={{
|
||||
icon: <PlusIcon className="h-4 w-4" />,
|
||||
text: "New Cycle",
|
||||
onClick: () => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "q",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
@ -146,13 +146,15 @@ const ProjectModules: NextPage = () => {
|
||||
title="Manage your project with modules"
|
||||
description="Modules are smaller, focused projects that help you group and organize issues."
|
||||
image={emptyModule}
|
||||
buttonText="New Module"
|
||||
buttonIcon={<PlusIcon className="h-4 w-4" />}
|
||||
onClick={() => {
|
||||
primaryButton={{
|
||||
icon: <PlusIcon className="h-4 w-4" />,
|
||||
text: "New Module",
|
||||
onClick: () => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "m",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
@ -166,11 +166,13 @@ const EstimatesSettings: NextPage = () => {
|
||||
title="No estimates yet"
|
||||
description="Estimates help you communicate the complexity of an issue."
|
||||
image={emptyEstimate}
|
||||
buttonText="Add Estimate"
|
||||
buttonIcon={<PlusIcon className="h-4 w-4" />}
|
||||
onClick={() => {
|
||||
primaryButton={{
|
||||
icon: <PlusIcon className="h-4 w-4" />,
|
||||
text: "Add Estimate",
|
||||
onClick: () => {
|
||||
setEstimateToUpdate(undefined);
|
||||
setEstimateFormOpen(true);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
@ -78,8 +78,10 @@ const ProjectIntegrations: NextPage = () => {
|
||||
title="You haven't configured integrations"
|
||||
description="Configure GitHub and other integrations to sync your project issues."
|
||||
image={emptyIntegration}
|
||||
buttonText="Configure now"
|
||||
onClick={() => router.push(`/${workspaceSlug}/settings/integrations`)}
|
||||
primaryButton={{
|
||||
text: "Configure now",
|
||||
onClick: () => router.push(`/${workspaceSlug}/settings/integrations`),
|
||||
}}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
|
@ -181,8 +181,10 @@ const LabelsSettings: NextPage = () => {
|
||||
title="No labels yet"
|
||||
description="Create labels to help organize and filter issues in you project"
|
||||
image={emptyLabel}
|
||||
buttonText="Add label"
|
||||
onClick={newLabel}
|
||||
primaryButton={{
|
||||
text: "Add label",
|
||||
onClick: () => newLabel(),
|
||||
}}
|
||||
isFullScreen={false}
|
||||
/>
|
||||
)
|
||||
|
@ -118,13 +118,15 @@ const ProjectViews: NextPage = () => {
|
||||
title="Get focused with views"
|
||||
description="Views aid in saving your issues by applying various filters and grouping options."
|
||||
image={emptyView}
|
||||
buttonText="New View"
|
||||
buttonIcon={<PlusIcon className="h-4 w-4" />}
|
||||
onClick={() => {
|
||||
primaryButton={{
|
||||
icon: <PlusIcon className="h-4 w-4" />,
|
||||
text: "New View",
|
||||
onClick: () => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "v",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
@ -111,13 +111,15 @@ const ProjectsPage: NextPage = () => {
|
||||
image={emptyProject}
|
||||
title="No projects yet"
|
||||
description="Get started by creating your first project"
|
||||
buttonText="New Project"
|
||||
buttonIcon={<PlusIcon className="h-4 w-4" />}
|
||||
onClick={() => {
|
||||
primaryButton={{
|
||||
icon: <PlusIcon className="h-4 w-4" />,
|
||||
text: "New Project",
|
||||
onClick: () => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "p",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
@ -186,8 +186,10 @@ const OnBoard: NextPage = () => {
|
||||
title="No pending invites"
|
||||
description="You can see here if someone invites you to a workspace."
|
||||
image={emptyInvitation}
|
||||
buttonText="Back to Dashboard"
|
||||
onClick={() => router.push("/")}
|
||||
primaryButton={{
|
||||
text: "Back to Dashboard",
|
||||
onClick: () => router.push("/"),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user