style: issue list (#798)
* style: issue list * chore: changed the empty state images
@ -42,7 +42,7 @@ export const NotAuthorizedView: React.FC<Props> = ({ actionButton, type }) => {
|
|||||||
|
|
||||||
<div className="w-full text-base text-gray-500 max-w-md ">
|
<div className="w-full text-base text-gray-500 max-w-md ">
|
||||||
{user ? (
|
{user ? (
|
||||||
<p className="">
|
<p>
|
||||||
You have signed in as {user.email}. <br />
|
You have signed in as {user.email}. <br />
|
||||||
<Link href={`/signin?next=${currentPath}`}>
|
<Link href={`/signin?next=${currentPath}`}>
|
||||||
<a className="text-gray-900 font-medium">Sign in</a>
|
<a className="text-gray-900 font-medium">Sign in</a>
|
||||||
@ -50,7 +50,7 @@ export const NotAuthorizedView: React.FC<Props> = ({ actionButton, type }) => {
|
|||||||
with different account that has access to this page.
|
with different account that has access to this page.
|
||||||
</p>
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<p className="">
|
<p>
|
||||||
You need to{" "}
|
You need to{" "}
|
||||||
<Link href={`/signin?next=${currentPath}`}>
|
<Link href={`/signin?next=${currentPath}`}>
|
||||||
<a className="text-gray-900 font-medium">Sign in</a>
|
<a className="text-gray-900 font-medium">Sign in</a>
|
||||||
|
@ -23,7 +23,7 @@ import StrictModeDroppable from "components/dnd/StrictModeDroppable";
|
|||||||
import { CreateUpdateViewModal } from "components/views";
|
import { CreateUpdateViewModal } from "components/views";
|
||||||
import { TransferIssues, TransferIssuesModal } from "components/cycles";
|
import { TransferIssues, TransferIssuesModal } from "components/cycles";
|
||||||
// ui
|
// ui
|
||||||
import { EmptySpace, EmptySpaceItem, PrimaryButton, Spinner } from "components/ui";
|
import { EmptySpace, EmptySpaceItem, EmptyState, PrimaryButton, Spinner } from "components/ui";
|
||||||
import { CalendarView } from "./calendar-view";
|
import { CalendarView } from "./calendar-view";
|
||||||
// icons
|
// icons
|
||||||
import {
|
import {
|
||||||
@ -46,6 +46,8 @@ import {
|
|||||||
PROJECT_ISSUES_LIST_WITH_PARAMS,
|
PROJECT_ISSUES_LIST_WITH_PARAMS,
|
||||||
STATE_LIST,
|
STATE_LIST,
|
||||||
} from "constants/fetch-keys";
|
} from "constants/fetch-keys";
|
||||||
|
// image
|
||||||
|
import emptyCycle from "public/empty-state/empty-cycle.svg";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
type?: "issue" | "cycle" | "module";
|
type?: "issue" | "cycle" | "module";
|
||||||
@ -425,7 +427,7 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
handleClose={() => setTransferIssuesModal(false)}
|
handleClose={() => setTransferIssuesModal(false)}
|
||||||
isOpen={transferIssuesModal}
|
isOpen={transferIssuesModal}
|
||||||
/>
|
/>
|
||||||
<div className="mb-5 -mt-4">
|
<div>
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<FilterList filters={filters} setFilters={setFilters} />
|
<FilterList filters={filters} setFilters={setFilters} />
|
||||||
{Object.keys(filters).length > 0 &&
|
{Object.keys(filters).length > 0 &&
|
||||||
@ -480,24 +482,24 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
<>
|
<>
|
||||||
{isCompleted && <TransferIssues handleClick={() => setTransferIssuesModal(true)} />}
|
{isCompleted && <TransferIssues handleClick={() => setTransferIssuesModal(true)} />}
|
||||||
{issueView === "list" ? (
|
{issueView === "list" ? (
|
||||||
<AllLists
|
<AllLists
|
||||||
type={type}
|
type={type}
|
||||||
states={states}
|
states={states}
|
||||||
addIssueToState={addIssueToState}
|
addIssueToState={addIssueToState}
|
||||||
makeIssueCopy={makeIssueCopy}
|
makeIssueCopy={makeIssueCopy}
|
||||||
handleEditIssue={handleEditIssue}
|
handleEditIssue={handleEditIssue}
|
||||||
handleDeleteIssue={handleDeleteIssue}
|
handleDeleteIssue={handleDeleteIssue}
|
||||||
openIssuesListModal={type !== "issue" ? openIssuesListModal : null}
|
openIssuesListModal={type !== "issue" ? openIssuesListModal : null}
|
||||||
removeIssue={
|
removeIssue={
|
||||||
type === "cycle"
|
type === "cycle"
|
||||||
? removeIssueFromCycle
|
? removeIssueFromCycle
|
||||||
: type === "module"
|
: type === "module"
|
||||||
? removeIssueFromModule
|
? removeIssueFromModule
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
isCompleted={isCompleted}
|
isCompleted={isCompleted}
|
||||||
userAuth={memberRole}
|
userAuth={memberRole}
|
||||||
/>
|
/>
|
||||||
) : issueView === "kanban" ? (
|
) : issueView === "kanban" ? (
|
||||||
<AllBoards
|
<AllBoards
|
||||||
type={type}
|
type={type}
|
||||||
@ -523,38 +525,12 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div className="grid h-full w-full place-items-center px-4 sm:px-0">
|
<EmptyState
|
||||||
<EmptySpace
|
type="issue"
|
||||||
title="You don't have any issue yet."
|
title="Create New Issue"
|
||||||
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."
|
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."
|
||||||
Icon={RectangleStackIcon}
|
imgURL={emptyCycle}
|
||||||
>
|
/>
|
||||||
<EmptySpaceItem
|
|
||||||
title="Create a new issue"
|
|
||||||
description={
|
|
||||||
<span>
|
|
||||||
Use <pre className="inline rounded bg-gray-200 px-2 py-1">C</pre> shortcut to
|
|
||||||
create a new issue
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
Icon={PlusIcon}
|
|
||||||
action={() => {
|
|
||||||
const e = new KeyboardEvent("keydown", {
|
|
||||||
key: "c",
|
|
||||||
});
|
|
||||||
document.dispatchEvent(e);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{openIssuesListModal && (
|
|
||||||
<EmptySpaceItem
|
|
||||||
title="Add an existing issue"
|
|
||||||
description="Open list"
|
|
||||||
Icon={ListBulletIcon}
|
|
||||||
action={openIssuesListModal}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</EmptySpace>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
<div className="flex h-full w-full items-center justify-center">
|
<div className="flex h-full w-full items-center justify-center">
|
||||||
|
@ -36,7 +36,7 @@ export const AllLists: React.FC<Props> = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{groupedByIssues && (
|
{groupedByIssues && (
|
||||||
<div className="flex flex-col space-y-5">
|
<div className="flex flex-col space-y-5 gap-4 bg-white">
|
||||||
{Object.keys(groupedByIssues).map((singleGroup) => {
|
{Object.keys(groupedByIssues).map((singleGroup) => {
|
||||||
const currentState =
|
const currentState =
|
||||||
selectedGroup === "state" ? states?.find((s) => s.id === singleGroup) : null;
|
selectedGroup === "state" ? states?.find((s) => s.id === singleGroup) : null;
|
||||||
|
@ -191,7 +191,7 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
</ContextMenu.Item>
|
</ContextMenu.Item>
|
||||||
</a>
|
</a>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
<div className="border-b border-gray-300 last:border-b-0">
|
<div className="border-b mx-4 border-gray-300 last:border-b-0">
|
||||||
<div
|
<div
|
||||||
className="flex items-center justify-between gap-2 px-4 py-3"
|
className="flex items-center justify-between gap-2 px-4 py-3"
|
||||||
onContextMenu={(e) => {
|
onContextMenu={(e) => {
|
||||||
|
@ -132,10 +132,10 @@ export const SingleList: React.FC<Props> = ({
|
|||||||
return (
|
return (
|
||||||
<Disclosure key={groupTitle} as="div" defaultOpen>
|
<Disclosure key={groupTitle} as="div" defaultOpen>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
<div className="rounded-[10px] border border-gray-300 bg-white">
|
<div className="bg-white">
|
||||||
<div
|
<div
|
||||||
className={`flex items-center justify-between bg-gray-100 px-5 py-3 ${
|
className={`flex items-center justify-between bg-gray-100 px-5 py-3 ${
|
||||||
open ? "rounded-t-[10px]" : "rounded-[10px]"
|
open ? "" : "rounded-[10px]"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<Disclosure.Button>
|
<Disclosure.Button>
|
||||||
|
@ -5,6 +5,8 @@ import { useRouter } from "next/router";
|
|||||||
|
|
||||||
// contexts
|
// contexts
|
||||||
import { useProjectMyMembership, ProjectMemberProvider } from "contexts/project-member.context";
|
import { useProjectMyMembership, ProjectMemberProvider } from "contexts/project-member.context";
|
||||||
|
// hooks
|
||||||
|
import useIssuesView from "hooks/use-issues-view";
|
||||||
// layouts
|
// layouts
|
||||||
import Container from "layouts/container";
|
import Container from "layouts/container";
|
||||||
import AppHeader from "layouts/app-layout/app-header";
|
import AppHeader from "layouts/app-layout/app-header";
|
||||||
@ -19,6 +21,7 @@ import { PrimaryButton, Spinner } from "components/ui";
|
|||||||
// icons
|
// icons
|
||||||
import { LayerDiagonalIcon } from "components/icons";
|
import { LayerDiagonalIcon } from "components/icons";
|
||||||
|
|
||||||
|
|
||||||
type Meta = {
|
type Meta = {
|
||||||
title?: string | null;
|
title?: string | null;
|
||||||
description?: string | null;
|
description?: string | null;
|
||||||
@ -58,6 +61,10 @@ const ProjectAuthorizationWrapped: React.FC<Props> = ({
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
|
const {
|
||||||
|
issueView,
|
||||||
|
} = useIssuesView();
|
||||||
|
|
||||||
const { loading, error, memberRole: memberType } = useProjectMyMembership();
|
const { loading, error, memberRole: memberType } = useProjectMyMembership();
|
||||||
|
|
||||||
const settingsLayout = router.pathname.includes("/settings");
|
const settingsLayout = router.pathname.includes("/settings");
|
||||||
@ -131,7 +138,7 @@ const ProjectAuthorizationWrapped: React.FC<Props> = ({
|
|||||||
)}
|
)}
|
||||||
<div
|
<div
|
||||||
className={`flex w-full flex-grow flex-col ${
|
className={`flex w-full flex-grow flex-col ${
|
||||||
noPadding ? "" : settingsLayout ? "p-8 lg:px-28" : "p-8"
|
noPadding || issueView === "list" ? "" : settingsLayout ? "p-8 lg:px-28" : "p-8"
|
||||||
} ${
|
} ${
|
||||||
bg === "primary" ? "bg-primary" : bg === "secondary" ? "bg-secondary" : "bg-primary"
|
bg === "primary" ? "bg-primary" : bg === "secondary" ? "bg-secondary" : "bg-primary"
|
||||||
}`}
|
}`}
|
||||||
|
@ -121,7 +121,7 @@ const IssueDetailsPage: NextPage = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ProjectAuthorizationWrapper
|
<ProjectAuthorizationWrapper
|
||||||
noPadding={true}
|
noPadding
|
||||||
bg="secondary"
|
bg="secondary"
|
||||||
breadcrumbs={
|
breadcrumbs={
|
||||||
<Breadcrumbs>
|
<Breadcrumbs>
|
||||||
|
@ -21,6 +21,7 @@ import type { NextPage } from "next";
|
|||||||
import { PROJECT_DETAILS } from "constants/fetch-keys";
|
import { PROJECT_DETAILS } from "constants/fetch-keys";
|
||||||
|
|
||||||
const ProjectIssues: NextPage = () => {
|
const ProjectIssues: NextPage = () => {
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 76 KiB |