Merge branch 'master' of github.com:makeplane/plane into build/merge_frontend_backend
This commit is contained in:
commit
45fe4b89db
55 changed files with 5928 additions and 937 deletions
|
|
@ -14,21 +14,18 @@ import { CYCLE_ISSUES, CYCLE_LIST } from "constants/fetch-keys";
|
|||
// layouts
|
||||
import AdminLayout from "layouts/AdminLayout";
|
||||
// components
|
||||
import SprintView from "components/project/cycles/CycleView";
|
||||
import CycleView from "components/project/cycles/CycleView";
|
||||
import ConfirmIssueDeletion from "components/project/issues/ConfirmIssueDeletion";
|
||||
import ConfirmSprintDeletion from "components/project/cycles/ConfirmCycleDeletion";
|
||||
import CreateUpdateIssuesModal from "components/project/issues/CreateUpdateIssueModal";
|
||||
import CreateUpdateSprintsModal from "components/project/cycles/CreateUpdateCyclesModal";
|
||||
// ui
|
||||
import { Spinner } from "ui";
|
||||
import { BreadcrumbItem, Breadcrumbs, HeaderButton, Spinner, EmptySpace, EmptySpaceItem } from "ui";
|
||||
// icons
|
||||
import { PlusIcon } from "@heroicons/react/20/solid";
|
||||
import { ArrowPathIcon } from "@heroicons/react/24/outline";
|
||||
// types
|
||||
import { IIssue, ICycle, SelectSprintType, SelectIssue } from "types";
|
||||
import { EmptySpace, EmptySpaceItem } from "ui/EmptySpace";
|
||||
import { ArrowPathIcon } from "@heroicons/react/24/outline";
|
||||
import HeaderButton from "ui/HeaderButton";
|
||||
import { BreadcrumbItem, Breadcrumbs } from "ui/Breadcrumbs";
|
||||
|
||||
const ProjectSprints: NextPage = () => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
|
@ -44,7 +41,7 @@ const ProjectSprints: NextPage = () => {
|
|||
|
||||
const { projectId } = router.query;
|
||||
|
||||
const { data: sprints } = useSWR<ICycle[]>(
|
||||
const { data: cycles } = useSWR<ICycle[]>(
|
||||
projectId && activeWorkspace ? CYCLE_LIST(projectId as string) : null,
|
||||
activeWorkspace && projectId
|
||||
? () => sprintService.getCycles(activeWorkspace.slug, projectId as string)
|
||||
|
|
@ -52,14 +49,14 @@ const ProjectSprints: NextPage = () => {
|
|||
);
|
||||
|
||||
const openIssueModal = (
|
||||
sprintId: string,
|
||||
cycleId: string,
|
||||
issue?: IIssue,
|
||||
actionType: "create" | "edit" | "delete" = "create"
|
||||
) => {
|
||||
const sprint = sprints?.find((sprint) => sprint.id === sprintId);
|
||||
if (sprint) {
|
||||
const cycle = cycles?.find((cycle) => cycle.id === cycleId);
|
||||
if (cycle) {
|
||||
setSelectedSprint({
|
||||
...sprint,
|
||||
...cycle,
|
||||
actionType: "create-issue",
|
||||
});
|
||||
if (issue) setSelectedIssues({ ...issue, actionType });
|
||||
|
|
@ -67,16 +64,16 @@ const ProjectSprints: NextPage = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const addIssueToSprint = (sprintId: string, issueId: string) => {
|
||||
const addIssueToSprint = (cycleId: string, issueId: string) => {
|
||||
if (!activeWorkspace || !projectId) return;
|
||||
|
||||
issuesServices
|
||||
.addIssueToSprint(activeWorkspace.slug, projectId as string, sprintId, {
|
||||
.addIssueToSprint(activeWorkspace.slug, projectId as string, cycleId, {
|
||||
issue: issueId,
|
||||
})
|
||||
.then((response) => {
|
||||
console.log(response);
|
||||
mutate(CYCLE_ISSUES(sprintId));
|
||||
mutate(CYCLE_ISSUES(cycleId));
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
|
|
@ -134,8 +131,8 @@ const ProjectSprints: NextPage = () => {
|
|||
setIsOpen={setIsOpen}
|
||||
projectId={projectId as string}
|
||||
/>
|
||||
{sprints ? (
|
||||
sprints.length > 0 ? (
|
||||
{cycles ? (
|
||||
cycles.length > 0 ? (
|
||||
<div className="h-full w-full space-y-5">
|
||||
<Breadcrumbs>
|
||||
<BreadcrumbItem title="Projects" link="/projects" />
|
||||
|
|
@ -146,15 +143,15 @@ const ProjectSprints: NextPage = () => {
|
|||
<HeaderButton Icon={PlusIcon} label="Add Cycle" onClick={() => setIsOpen(true)} />
|
||||
</div>
|
||||
<div className="h-full w-full">
|
||||
{sprints.map((sprint) => (
|
||||
<SprintView
|
||||
sprint={sprint}
|
||||
{cycles.map((cycle) => (
|
||||
<CycleView
|
||||
key={cycle.id}
|
||||
sprint={cycle}
|
||||
selectSprint={setSelectedSprint}
|
||||
projectId={projectId as string}
|
||||
workspaceSlug={activeWorkspace?.slug as string}
|
||||
openIssueModal={openIssueModal}
|
||||
addIssueToSprint={addIssueToSprint}
|
||||
key={sprint.id}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -53,7 +53,19 @@ const IssueDetail: NextPage = () => {
|
|||
handleSubmit,
|
||||
reset,
|
||||
control,
|
||||
} = useForm<IIssue>({});
|
||||
} = useForm<IIssue>({
|
||||
defaultValues: {
|
||||
name: "",
|
||||
description: "",
|
||||
state: "",
|
||||
assignees_list: [],
|
||||
priority: "low",
|
||||
blockers_list: [],
|
||||
blocked_list: [],
|
||||
target_date: new Date().toString(),
|
||||
cycle: "",
|
||||
},
|
||||
});
|
||||
|
||||
const { data: issueActivities } = useSWR<any[]>(
|
||||
activeWorkspace && projectId && issueId ? PROJECT_ISSUES_ACTIVITY : null,
|
||||
|
|
@ -150,24 +162,23 @@ const IssueDetail: NextPage = () => {
|
|||
/>
|
||||
|
||||
<div className="space-y-5">
|
||||
<Breadcrumbs>
|
||||
<BreadcrumbItem
|
||||
title={`${activeProject?.name ?? "Project"} Issues`}
|
||||
link={`/projects/${activeProject?.id}/issues`}
|
||||
/>
|
||||
<BreadcrumbItem
|
||||
title={`Issue ${activeProject?.identifier ?? "Project"}-${
|
||||
issueDetail?.sequence_id ?? "..."
|
||||
} Details`}
|
||||
/>
|
||||
</Breadcrumbs>
|
||||
<div className="flex items-center justify-between w-full">
|
||||
<h2 className="text-2xl font-medium">{`${activeProject?.name}/${activeProject?.identifier}-${issueDetail?.sequence_id}`}</h2>
|
||||
<Breadcrumbs>
|
||||
<BreadcrumbItem
|
||||
title={`${activeProject?.name ?? "Project"} Issues`}
|
||||
link={`/projects/${activeProject?.id}/issues`}
|
||||
/>
|
||||
<BreadcrumbItem
|
||||
title={`Issue ${activeProject?.identifier ?? "Project"}-${
|
||||
issueDetail?.sequence_id ?? "..."
|
||||
} Details`}
|
||||
/>
|
||||
</Breadcrumbs>
|
||||
<div className="flex items-center gap-x-3">
|
||||
<HeaderButton
|
||||
Icon={ChevronLeftIcon}
|
||||
disabled={!prevIssue}
|
||||
label="Previous"
|
||||
className={`${!prevIssue ? "cursor-not-allowed opacity-70" : ""}`}
|
||||
onClick={() => {
|
||||
if (!prevIssue) return;
|
||||
router.push(`/projects/${prevIssue.project}/issues/${prevIssue.id}`);
|
||||
|
|
@ -177,6 +188,7 @@ const IssueDetail: NextPage = () => {
|
|||
Icon={ChevronRightIcon}
|
||||
disabled={!nextIssue}
|
||||
label="Next"
|
||||
className={`${!nextIssue ? "cursor-not-allowed opacity-70" : ""}`}
|
||||
onClick={() => {
|
||||
if (!nextIssue) return;
|
||||
router.push(`/projects/${nextIssue.project}/issues/${nextIssue?.id}`);
|
||||
|
|
@ -188,7 +200,7 @@ const IssueDetail: NextPage = () => {
|
|||
{issueDetail && activeProject ? (
|
||||
<div className="grid grid-cols-4 gap-5">
|
||||
<div className="col-span-3 space-y-5">
|
||||
<div className="bg-secondary rounded-lg p-5">
|
||||
<div className="bg-secondary rounded-lg p-4">
|
||||
<TextArea
|
||||
id="name"
|
||||
placeholder="Enter issue name"
|
||||
|
|
@ -200,7 +212,7 @@ const IssueDetail: NextPage = () => {
|
|||
handleSubmit(submitChanges)();
|
||||
}, 5000)}
|
||||
mode="transparent"
|
||||
className="text-3xl sm:text-3xl"
|
||||
className="text-xl font-medium"
|
||||
/>
|
||||
<TextArea
|
||||
id="description"
|
||||
|
|
@ -217,7 +229,7 @@ const IssueDetail: NextPage = () => {
|
|||
register={register}
|
||||
/>
|
||||
</div>
|
||||
<div className="bg-secondary rounded-lg p-5">
|
||||
<div className="bg-secondary rounded-lg p-4">
|
||||
<div className="relative">
|
||||
<div className="absolute inset-0 flex items-center" aria-hidden="true">
|
||||
<div className="w-full border-t border-gray-300" />
|
||||
|
|
@ -233,7 +245,7 @@ const IssueDetail: NextPage = () => {
|
|||
<Tab
|
||||
key={item}
|
||||
className={({ selected }) =>
|
||||
`px-3 py-1 text-sm rounded-md border border-gray-700 ${
|
||||
`px-3 py-1 text-sm rounded-md border-2 border-gray-700 ${
|
||||
selected ? "bg-gray-700 text-white" : ""
|
||||
}`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,152 +141,154 @@ const ProjectIssues: NextPage = () => {
|
|||
<Spinner />
|
||||
</div>
|
||||
) : projectIssues.count > 0 ? (
|
||||
<div className="w-full space-y-5">
|
||||
<Breadcrumbs>
|
||||
<BreadcrumbItem title="Projects" link="/projects" />
|
||||
<BreadcrumbItem title={`${activeProject?.name ?? "Project"} Issues`} />
|
||||
</Breadcrumbs>
|
||||
<div className="flex items-center justify-between w-full">
|
||||
<h2 className="text-2xl font-medium">Project Issues</h2>
|
||||
<div className="flex items-center gap-x-3">
|
||||
<div className="flex items-center gap-x-1">
|
||||
<button
|
||||
type="button"
|
||||
className={`h-7 w-7 p-1 grid place-items-center rounded hover:bg-gray-200 duration-300 outline-none ${
|
||||
issueView === "list" ? "bg-gray-200" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setIssueView("list");
|
||||
setGroupByProperty(null);
|
||||
}}
|
||||
>
|
||||
<ListBulletIcon className="h-4 w-4" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`h-7 w-7 p-1 grid place-items-center rounded hover:bg-gray-200 duration-300 outline-none ${
|
||||
issueView === "kanban" ? "bg-gray-200" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setIssueView("kanban");
|
||||
setGroupByProperty("state_detail.name");
|
||||
}}
|
||||
>
|
||||
<Squares2X2Icon className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
<Menu as="div" className="relative inline-block w-40">
|
||||
<div className="w-full">
|
||||
<Menu.Button className="inline-flex justify-between items-center w-full rounded-md shadow-sm p-2 border border-gray-300 text-xs font-semibold text-gray-700 hover:bg-gray-100 focus:outline-none">
|
||||
<span className="flex gap-x-1 items-center">
|
||||
{groupByOptions.find((option) => option.key === groupByProperty)?.name ??
|
||||
"No Grouping"}
|
||||
</span>
|
||||
<div className="flex-grow flex justify-end">
|
||||
<ChevronDownIcon className="h-4 w-4" aria-hidden="true" />
|
||||
</div>
|
||||
</Menu.Button>
|
||||
<>
|
||||
<div className="w-full space-y-5 mb-5">
|
||||
<Breadcrumbs>
|
||||
<BreadcrumbItem title="Projects" link="/projects" />
|
||||
<BreadcrumbItem title={`${activeProject?.name ?? "Project"} Issues`} />
|
||||
</Breadcrumbs>
|
||||
<div className="flex items-center justify-between w-full">
|
||||
<h2 className="text-2xl font-medium">Project Issues</h2>
|
||||
<div className="flex items-center gap-x-3">
|
||||
<div className="flex items-center gap-x-1">
|
||||
<button
|
||||
type="button"
|
||||
className={`h-7 w-7 p-1 grid place-items-center rounded hover:bg-gray-200 duration-300 outline-none ${
|
||||
issueView === "list" ? "bg-gray-200" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setIssueView("list");
|
||||
setGroupByProperty(null);
|
||||
}}
|
||||
>
|
||||
<ListBulletIcon className="h-4 w-4" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`h-7 w-7 p-1 grid place-items-center rounded hover:bg-gray-200 duration-300 outline-none ${
|
||||
issueView === "kanban" ? "bg-gray-200" : ""
|
||||
}`}
|
||||
onClick={() => {
|
||||
setIssueView("kanban");
|
||||
setGroupByProperty("state_detail.name");
|
||||
}}
|
||||
>
|
||||
<Squares2X2Icon className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
<Menu as="div" className="relative inline-block w-40">
|
||||
<div className="w-full">
|
||||
<Menu.Button className="inline-flex justify-between items-center w-full rounded-md shadow-sm p-2 border border-gray-300 text-xs font-semibold text-gray-700 hover:bg-gray-100 focus:outline-none">
|
||||
<span className="flex gap-x-1 items-center">
|
||||
{groupByOptions.find((option) => option.key === groupByProperty)?.name ??
|
||||
"No Grouping"}
|
||||
</span>
|
||||
<div className="flex-grow flex justify-end">
|
||||
<ChevronDownIcon className="h-4 w-4" aria-hidden="true" />
|
||||
</div>
|
||||
</Menu.Button>
|
||||
</div>
|
||||
|
||||
<Transition
|
||||
as={React.Fragment}
|
||||
enter="transition ease-out duration-100"
|
||||
enterFrom="transform opacity-0 scale-95"
|
||||
enterTo="transform opacity-100 scale-100"
|
||||
leave="transition ease-in duration-75"
|
||||
leaveFrom="transform opacity-100 scale-100"
|
||||
leaveTo="transform opacity-0 scale-95"
|
||||
>
|
||||
<Menu.Items className="origin-top-left absolute left-0 mt-2 w-full rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none z-50">
|
||||
<div className="p-1">
|
||||
{groupByOptions.map((option) => (
|
||||
<Menu.Item key={option.key}>
|
||||
{({ active }) => (
|
||||
<button
|
||||
type="button"
|
||||
className={`${
|
||||
active ? "bg-theme text-white" : "text-gray-900"
|
||||
} group flex w-full items-center rounded-md p-2 text-xs`}
|
||||
onClick={() => setGroupByProperty(option.key)}
|
||||
>
|
||||
{option.name}
|
||||
</button>
|
||||
)}
|
||||
</Menu.Item>
|
||||
))}
|
||||
{issueView === "list" ? (
|
||||
<Menu.Item>
|
||||
{({ active }) => (
|
||||
<button
|
||||
type="button"
|
||||
className={`hover:bg-theme hover:text-white ${
|
||||
active ? "bg-theme text-white" : "text-gray-900"
|
||||
} group flex w-full items-center rounded-md p-2 text-xs`}
|
||||
onClick={() => setGroupByProperty(null)}
|
||||
>
|
||||
No grouping
|
||||
</button>
|
||||
)}
|
||||
</Menu.Item>
|
||||
) : null}
|
||||
</div>
|
||||
</Menu.Items>
|
||||
</Transition>
|
||||
</Menu>
|
||||
<Popover className="relative">
|
||||
{({ open }) => (
|
||||
<>
|
||||
<Popover.Button className="inline-flex justify-between items-center rounded-md shadow-sm p-2 border border-gray-300 text-xs font-semibold text-gray-700 hover:bg-gray-100 focus:outline-none w-40">
|
||||
<span>Properties</span>
|
||||
<ChevronDownIcon className="h-4 w-4" />
|
||||
</Popover.Button>
|
||||
|
||||
<Transition
|
||||
as={React.Fragment}
|
||||
enter="transition ease-out duration-200"
|
||||
enterFrom="opacity-0 translate-y-1"
|
||||
enterTo="opacity-100 translate-y-0"
|
||||
leave="transition ease-in duration-150"
|
||||
leaveFrom="opacity-100 translate-y-0"
|
||||
leaveTo="opacity-0 translate-y-1"
|
||||
>
|
||||
<Popover.Panel className="absolute left-1/2 z-10 mt-1 -translate-x-1/2 transform px-2 sm:px-0 w-full">
|
||||
<div className="overflow-hidden rounded-lg shadow-lg ring-1 ring-black ring-opacity-5">
|
||||
<div className="relative grid bg-white p-1">
|
||||
{Object.keys(properties).map((key) => (
|
||||
<Transition
|
||||
as={React.Fragment}
|
||||
enter="transition ease-out duration-100"
|
||||
enterFrom="transform opacity-0 scale-95"
|
||||
enterTo="transform opacity-100 scale-100"
|
||||
leave="transition ease-in duration-75"
|
||||
leaveFrom="transform opacity-100 scale-100"
|
||||
leaveTo="transform opacity-0 scale-95"
|
||||
>
|
||||
<Menu.Items className="origin-top-left absolute left-0 mt-2 w-full rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none z-50">
|
||||
<div className="p-1">
|
||||
{groupByOptions.map((option) => (
|
||||
<Menu.Item key={option.key}>
|
||||
{({ active }) => (
|
||||
<button
|
||||
key={key}
|
||||
className={`text-gray-900 hover:bg-theme hover:text-white flex justify-between w-full items-center rounded-md p-2 text-xs`}
|
||||
onClick={() => setProperties(key as keyof Properties)}
|
||||
type="button"
|
||||
className={`${
|
||||
active ? "bg-theme text-white" : "text-gray-900"
|
||||
} group flex w-full items-center rounded-md p-2 text-xs`}
|
||||
onClick={() => setGroupByProperty(option.key)}
|
||||
>
|
||||
<p className="capitalize">{key.replace("_", " ")}</p>
|
||||
<span className="self-end">
|
||||
{properties[key as keyof Properties] ? (
|
||||
<EyeIcon width="18" height="18" />
|
||||
) : (
|
||||
<EyeSlashIcon width="18" height="18" />
|
||||
)}
|
||||
</span>
|
||||
{option.name}
|
||||
</button>
|
||||
))}
|
||||
)}
|
||||
</Menu.Item>
|
||||
))}
|
||||
{issueView === "list" ? (
|
||||
<Menu.Item>
|
||||
{({ active }) => (
|
||||
<button
|
||||
type="button"
|
||||
className={`hover:bg-theme hover:text-white ${
|
||||
active ? "bg-theme text-white" : "text-gray-900"
|
||||
} group flex w-full items-center rounded-md p-2 text-xs`}
|
||||
onClick={() => setGroupByProperty(null)}
|
||||
>
|
||||
No grouping
|
||||
</button>
|
||||
)}
|
||||
</Menu.Item>
|
||||
) : null}
|
||||
</div>
|
||||
</Menu.Items>
|
||||
</Transition>
|
||||
</Menu>
|
||||
<Popover className="relative">
|
||||
{({ open }) => (
|
||||
<>
|
||||
<Popover.Button className="inline-flex justify-between items-center rounded-md shadow-sm p-2 border border-gray-300 text-xs font-semibold text-gray-700 hover:bg-gray-100 focus:outline-none w-40">
|
||||
<span>Properties</span>
|
||||
<ChevronDownIcon className="h-4 w-4" />
|
||||
</Popover.Button>
|
||||
|
||||
<Transition
|
||||
as={React.Fragment}
|
||||
enter="transition ease-out duration-200"
|
||||
enterFrom="opacity-0 translate-y-1"
|
||||
enterTo="opacity-100 translate-y-0"
|
||||
leave="transition ease-in duration-150"
|
||||
leaveFrom="opacity-100 translate-y-0"
|
||||
leaveTo="opacity-0 translate-y-1"
|
||||
>
|
||||
<Popover.Panel className="absolute left-1/2 z-10 mt-1 -translate-x-1/2 transform px-2 sm:px-0 w-full">
|
||||
<div className="overflow-hidden rounded-lg shadow-lg ring-1 ring-black ring-opacity-5">
|
||||
<div className="relative grid bg-white p-1">
|
||||
{Object.keys(properties).map((key) => (
|
||||
<button
|
||||
key={key}
|
||||
className={`text-gray-900 hover:bg-theme hover:text-white flex justify-between w-full items-center rounded-md p-2 text-xs`}
|
||||
onClick={() => setProperties(key as keyof Properties)}
|
||||
>
|
||||
<p className="capitalize">{key.replace("_", " ")}</p>
|
||||
<span className="self-end">
|
||||
{properties[key as keyof Properties] ? (
|
||||
<EyeIcon width="18" height="18" />
|
||||
) : (
|
||||
<EyeSlashIcon width="18" height="18" />
|
||||
)}
|
||||
</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Popover.Panel>
|
||||
</Transition>
|
||||
</>
|
||||
)}
|
||||
</Popover>
|
||||
<HeaderButton
|
||||
Icon={PlusIcon}
|
||||
label="Add Issue"
|
||||
onClick={() => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "i",
|
||||
ctrlKey: true,
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
/>
|
||||
</Popover.Panel>
|
||||
</Transition>
|
||||
</>
|
||||
)}
|
||||
</Popover>
|
||||
<HeaderButton
|
||||
Icon={PlusIcon}
|
||||
label="Add Issue"
|
||||
onClick={() => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
key: "i",
|
||||
ctrlKey: true,
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{issueView === "list" ? (
|
||||
|
|
@ -298,14 +300,16 @@ const ProjectIssues: NextPage = () => {
|
|||
handleDeleteIssue={setDeleteIssue}
|
||||
/>
|
||||
) : (
|
||||
<BoardView
|
||||
properties={properties}
|
||||
selectedGroup={groupByProperty}
|
||||
groupedByIssues={groupedByIssues}
|
||||
members={members}
|
||||
/>
|
||||
<div className="h-full pb-7 mb-7">
|
||||
<BoardView
|
||||
properties={properties}
|
||||
selectedGroup={groupByProperty}
|
||||
groupedByIssues={groupedByIssues}
|
||||
members={members}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className="h-full w-full grid place-items-center px-4 sm:px-0">
|
||||
<EmptySpace
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ import {
|
|||
CheckIcon,
|
||||
PlusIcon,
|
||||
PencilSquareIcon,
|
||||
RectangleGroupIcon,
|
||||
PencilIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
// types
|
||||
import type { IProject, IState, IWorkspace, WorkspaceMember } from "types";
|
||||
|
|
@ -58,6 +60,7 @@ const ProjectSettings: NextPage = () => {
|
|||
|
||||
const [isCreateStateModalOpen, setIsCreateStateModalOpen] = useState(false);
|
||||
const [selectedState, setSelectedState] = useState<string | undefined>();
|
||||
const [newGroupForm, setNewGroupForm] = useState(false);
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
|
|
@ -414,8 +417,8 @@ const ProjectSettings: NextPage = () => {
|
|||
<div className="w-full space-y-5">
|
||||
{states?.map((state) => (
|
||||
<div
|
||||
className="border p-1 px-4 rounded flex justify-between items-center"
|
||||
key={state.id}
|
||||
className="bg-white px-4 py-2 rounded flex justify-between items-center"
|
||||
>
|
||||
<div className="flex items-center gap-x-2">
|
||||
<div
|
||||
|
|
@ -433,25 +436,69 @@ const ProjectSettings: NextPage = () => {
|
|||
</div>
|
||||
</div>
|
||||
))}
|
||||
<button
|
||||
<Button
|
||||
type="button"
|
||||
className="flex items-center gap-x-1"
|
||||
onClick={() => setIsCreateStateModalOpen(true)}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4 text-gray-400" />
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
<span>Add State</span>
|
||||
</button>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className="space-y-5">
|
||||
<div>
|
||||
<h3 className="text-lg font-medium leading-6 text-gray-900">Labels</h3>
|
||||
<p className="mt-1 text-sm text-gray-500">
|
||||
Manage the labels of this project.
|
||||
</p>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="text-lg font-medium leading-6 text-gray-900">Labels</h3>
|
||||
<p className="mt-1 text-sm text-gray-500">
|
||||
Manage the labels of this project.
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
className="flex items-center gap-x-1"
|
||||
onClick={() => setNewGroupForm(true)}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
New group
|
||||
</Button>
|
||||
</div>
|
||||
<div className="space-y-5">
|
||||
<div
|
||||
className={`bg-white px-4 py-2 flex items-center gap-2 ${
|
||||
newGroupForm ? "" : "hidden"
|
||||
}`}
|
||||
>
|
||||
<Input type="text" name="groupName" />
|
||||
<Button
|
||||
type="button"
|
||||
theme="secondary"
|
||||
onClick={() => setNewGroupForm(false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="button">Save</Button>
|
||||
</div>
|
||||
{["", ""].map((group, index) => (
|
||||
<div key={index} className="bg-white p-4 text-gray-900 rounded-md">
|
||||
<h3 className="font-medium leading-5 flex items-center gap-2">
|
||||
<RectangleGroupIcon className="h-5 w-5" />
|
||||
This is the label group title
|
||||
</h3>
|
||||
<div className="pl-5 mt-4">
|
||||
<div className="group text-sm flex justify-between items-center p-2 hover:bg-gray-100 rounded">
|
||||
<h5 className="flex items-center gap-2">
|
||||
<div className="w-2 h-2 bg-red-600 rounded-full"></div>
|
||||
This is the label title
|
||||
</h5>
|
||||
<div className="hidden group-hover:block">
|
||||
<PencilIcon className="h-3 w-3" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div></div>
|
||||
</section>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue