fix: implementing layouts using _app.tsx get layout method. (#2620)
* fix: implementing layouts in all pages * fix: layout fixes, implemting using standard nextjs parctice
This commit is contained in:
parent
a582021f2c
commit
3c884fd46e
57 changed files with 1653 additions and 1423 deletions
|
|
@ -1,10 +1,6 @@
|
|||
import React, { useCallback, useEffect, useState } from "react";
|
||||
|
||||
import { useCallback, useEffect, useState, ReactElement } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import useSWR, { mutate } from "swr";
|
||||
|
||||
// react-hook-form
|
||||
import { useForm } from "react-hook-form";
|
||||
// services
|
||||
import { IssueService, IssueArchiveService } from "services/issue";
|
||||
|
|
@ -22,7 +18,7 @@ import { ArchiveIcon, Loader } from "@plane/ui";
|
|||
import { History } from "lucide-react";
|
||||
// types
|
||||
import { IIssue } from "types";
|
||||
import type { NextPage } from "next";
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
// fetch-keys
|
||||
import { PROJECT_ISSUES_ACTIVITY, ISSUE_DETAILS } from "constants/fetch-keys";
|
||||
|
||||
|
|
@ -42,12 +38,13 @@ const defaultValues: Partial<IIssue> = {
|
|||
const issueService = new IssueService();
|
||||
const issueArchiveService = new IssueArchiveService();
|
||||
|
||||
const ArchivedIssueDetailsPage: NextPage = () => {
|
||||
const [isRestoring, setIsRestoring] = useState(false);
|
||||
|
||||
const ArchivedIssueDetailsPage: NextPageWithLayout = () => {
|
||||
// router
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, archivedIssueId } = router.query;
|
||||
|
||||
// states
|
||||
const [isRestoring, setIsRestoring] = useState(false);
|
||||
// hooks
|
||||
const { user } = useUserAuth();
|
||||
const { setToastAlert } = useToast();
|
||||
|
||||
|
|
@ -136,7 +133,7 @@ const ArchivedIssueDetailsPage: NextPage = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<AppLayout header={<ProjectArchivedIssueDetailsHeader />} withProjectWrapper>
|
||||
<>
|
||||
{issueDetails && projectId ? (
|
||||
<div className="flex h-full overflow-hidden">
|
||||
<div className="w-2/3 h-full overflow-y-auto space-y-2 divide-y-2 divide-custom-border-300 p-5">
|
||||
|
|
@ -187,6 +184,14 @@ const ArchivedIssueDetailsPage: NextPage = () => {
|
|||
</div>
|
||||
</Loader>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
ArchivedIssueDetailsPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AppLayout header={<ProjectArchivedIssueDetailsHeader />} withProjectWrapper>
|
||||
{page}
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { ReactElement } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
// layouts
|
||||
import { AppLayout } from "layouts/app-layout";
|
||||
// contexts
|
||||
|
|
@ -10,33 +10,38 @@ import { ProjectArchivedIssuesHeader } from "components/headers";
|
|||
// icons
|
||||
import { X } from "lucide-react";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
|
||||
const ProjectArchivedIssues: NextPage = () => {
|
||||
const ProjectArchivedIssuesPage: NextPageWithLayout = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
|
||||
return (
|
||||
<div className="h-full w-full flex flex-col">
|
||||
<div className="flex items-center ga-1 px-4 py-2.5 shadow-sm border-b border-custom-border-200">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => router.push(`/${workspaceSlug}/projects/${projectId}/issues/`)}
|
||||
className="flex items-center gap-1.5 rounded-full border border-custom-border-200 px-3 py-1.5 text-xs"
|
||||
>
|
||||
<ArchiveIcon className="h-4 w-4" />
|
||||
<span>Archived Issues</span>
|
||||
<X className="h-3 w-3" />
|
||||
</button>
|
||||
</div>
|
||||
{/* <IssuesView /> */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
ProjectArchivedIssuesPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<IssueViewContextProvider>
|
||||
<AppLayout header={<ProjectArchivedIssuesHeader />} withProjectWrapper>
|
||||
<div className="h-full w-full flex flex-col">
|
||||
<div className="flex items-center ga-1 px-4 py-2.5 shadow-sm border-b border-custom-border-200">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => router.push(`/${workspaceSlug}/projects/${projectId}/issues/`)}
|
||||
className="flex items-center gap-1.5 rounded-full border border-custom-border-200 px-3 py-1.5 text-xs"
|
||||
>
|
||||
<ArchiveIcon className="h-4 w-4" />
|
||||
<span>Archived Issues</span>
|
||||
|
||||
<X className="h-3 w-3" />
|
||||
</button>
|
||||
</div>
|
||||
{/* <IssuesView /> */}
|
||||
</div>
|
||||
{page}
|
||||
</AppLayout>
|
||||
</IssueViewContextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectArchivedIssues;
|
||||
export default ProjectArchivedIssuesPage;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState } from "react";
|
||||
import { useState, ReactElement } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import useSWR from "swr";
|
||||
// mobx store
|
||||
|
|
@ -22,10 +22,11 @@ import { EmptyState } from "components/common";
|
|||
import emptyCycle from "public/empty-state/cycle.svg";
|
||||
// types
|
||||
import { ISearchIssueResponse } from "types";
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
|
||||
const issueService = new IssueService();
|
||||
|
||||
const SingleCycle: React.FC = () => {
|
||||
const CycleDetailPage: NextPageWithLayout = () => {
|
||||
const [cycleIssuesListModal, setCycleIssuesListModal] = useState(false);
|
||||
|
||||
const router = useRouter();
|
||||
|
|
@ -75,7 +76,7 @@ const SingleCycle: React.FC = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<AppLayout header={<CycleIssuesHeader />} withProjectWrapper>
|
||||
<>
|
||||
{/* TODO: Update logic to bulk add issues to a cycle */}
|
||||
<ExistingIssuesListModal
|
||||
isOpen={cycleIssuesListModal}
|
||||
|
|
@ -113,8 +114,16 @@ const SingleCycle: React.FC = () => {
|
|||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
CycleDetailPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AppLayout header={<CycleIssuesHeader />} withProjectWrapper>
|
||||
{page}
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default SingleCycle;
|
||||
export default CycleDetailPage;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Fragment, useCallback, useEffect, useState } from "react";
|
||||
import { Fragment, useCallback, useEffect, useState, ReactElement } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import { Tab } from "@headlessui/react";
|
||||
import useSWR from "swr";
|
||||
|
|
@ -13,19 +13,20 @@ import { CyclesHeader } from "components/headers";
|
|||
import { CyclesView, ActiveCycleDetails, CycleCreateUpdateModal } from "components/cycles";
|
||||
// ui
|
||||
import { EmptyState } from "components/common";
|
||||
import { Tooltip } from "@plane/ui";
|
||||
// images
|
||||
import emptyCycle from "public/empty-state/cycle.svg";
|
||||
// types
|
||||
import { TCycleView, TCycleLayout } from "types";
|
||||
import type { NextPage } from "next";
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
// constants
|
||||
import { CYCLE_TAB_LIST, CYCLE_VIEWS } from "constants/cycle";
|
||||
// lib cookie
|
||||
import { setLocalStorage, getLocalStorage } from "lib/local-storage";
|
||||
import { Tooltip } from "@plane/ui";
|
||||
// helpers
|
||||
import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper";
|
||||
|
||||
const ProjectCyclesPage: NextPage = observer(() => {
|
||||
const ProjectCyclesPage: NextPageWithLayout = observer(() => {
|
||||
const [createModal, setCreateModal] = useState(false);
|
||||
// store
|
||||
const { project: projectStore, cycle: cycleStore } = useMobxStore();
|
||||
|
|
@ -85,7 +86,7 @@ const ProjectCyclesPage: NextPage = observer(() => {
|
|||
const cycleLayout = cycleStore?.cycleLayout;
|
||||
|
||||
return (
|
||||
<AppLayout header={<CyclesHeader name={currentProjectDetails?.name} />} withProjectWrapper>
|
||||
<>
|
||||
<CycleCreateUpdateModal
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
|
|
@ -217,8 +218,16 @@ const ProjectCyclesPage: NextPage = observer(() => {
|
|||
</Tab.Panels>
|
||||
</Tab.Group>
|
||||
)}
|
||||
</AppLayout>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
ProjectCyclesPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AppLayout header={<CyclesHeader />} withProjectWrapper>
|
||||
{page}
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectCyclesPage;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { ReactElement } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
// layouts
|
||||
import { AppLayout } from "layouts/app-layout";
|
||||
|
|
@ -8,32 +9,38 @@ import { ProjectDraftIssueHeader } from "components/headers";
|
|||
// icons
|
||||
import { X, PenSquare } from "lucide-react";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
|
||||
const ProjectDraftIssues: NextPage = () => {
|
||||
const ProjectDraftIssuesPage: NextPageWithLayout = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
|
||||
return (
|
||||
<div className="h-full w-full flex flex-col">
|
||||
<div className="flex items-center ga-1 px-4 py-2.5 shadow-sm border-b border-custom-border-200">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => router.push(`/${workspaceSlug}/projects/${projectId}/issues/`)}
|
||||
className="flex items-center gap-1.5 rounded border border-custom-border-200 px-3 py-1.5 text-xs"
|
||||
>
|
||||
<PenSquare className="h-3 w-3 text-custom-text-300" />
|
||||
<span>Draft Issues</span>
|
||||
|
||||
<X className="h-3 w-3" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
ProjectDraftIssuesPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<IssueViewContextProvider>
|
||||
<AppLayout header={<ProjectDraftIssueHeader />} withProjectWrapper>
|
||||
<div className="h-full w-full flex flex-col">
|
||||
<div className="flex items-center ga-1 px-4 py-2.5 shadow-sm border-b border-custom-border-200">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => router.push(`/${workspaceSlug}/projects/${projectId}/issues/`)}
|
||||
className="flex items-center gap-1.5 rounded border border-custom-border-200 px-3 py-1.5 text-xs"
|
||||
>
|
||||
<PenSquare className="h-3 w-3 text-custom-text-300" />
|
||||
<span>Draft Issues</span>
|
||||
|
||||
<X className="h-3 w-3" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{page}
|
||||
</AppLayout>
|
||||
</IssueViewContextProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectDraftIssues;
|
||||
export default ProjectDraftIssuesPage;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { ReactElement } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import { NextPage } from "next";
|
||||
import useSWR from "swr";
|
||||
// hooks
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
|
|
@ -9,8 +8,10 @@ import { AppLayout } from "layouts/app-layout";
|
|||
// components
|
||||
import { InboxActionsHeader, InboxMainContent, InboxIssuesListSidebar } from "components/inbox";
|
||||
import { ProjectInboxHeader } from "components/headers";
|
||||
// types
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
|
||||
const ProjectInbox: NextPage = () => {
|
||||
const ProjectInboxPage: NextPageWithLayout = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, inboxId } = router.query;
|
||||
|
||||
|
|
@ -24,18 +25,24 @@ const ProjectInbox: NextPage = () => {
|
|||
);
|
||||
|
||||
return (
|
||||
<AppLayout header={<ProjectInboxHeader />} withProjectWrapper>
|
||||
<div className="flex flex-col h-full">
|
||||
<InboxActionsHeader />
|
||||
<div className="grid grid-cols-4 flex-1 divide-x divide-custom-border-200 overflow-hidden">
|
||||
<InboxIssuesListSidebar />
|
||||
<div className="col-span-3 h-full overflow-auto">
|
||||
<InboxMainContent />
|
||||
</div>
|
||||
<div className="flex flex-col h-full">
|
||||
<InboxActionsHeader />
|
||||
<div className="grid grid-cols-4 flex-1 divide-x divide-custom-border-200 overflow-hidden">
|
||||
<InboxIssuesListSidebar />
|
||||
<div className="col-span-3 h-full overflow-auto">
|
||||
<InboxMainContent />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
ProjectInboxPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AppLayout header={<ProjectInboxHeader />} withProjectWrapper>
|
||||
{page}
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectInbox;
|
||||
export default ProjectInboxPage;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
import React, { useCallback, useEffect } from "react";
|
||||
|
||||
import React, { useCallback, useEffect, ReactElement } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import useSWR, { mutate } from "swr";
|
||||
|
||||
// react-hook-form
|
||||
import { useForm } from "react-hook-form";
|
||||
// services
|
||||
import { IssueService } from "services/issue";
|
||||
|
|
@ -21,10 +18,9 @@ import { Loader } from "@plane/ui";
|
|||
import emptyIssue from "public/empty-state/issue.svg";
|
||||
// types
|
||||
import { IIssue } from "types";
|
||||
import type { NextPage } from "next";
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
// fetch-keys
|
||||
import { PROJECT_ISSUES_ACTIVITY, ISSUE_DETAILS } from "constants/fetch-keys";
|
||||
// helper
|
||||
|
||||
const defaultValues: Partial<IIssue> = {
|
||||
description: "",
|
||||
|
|
@ -42,10 +38,10 @@ const defaultValues: Partial<IIssue> = {
|
|||
// services
|
||||
const issueService = new IssueService();
|
||||
|
||||
const IssueDetailsPage: NextPage = () => {
|
||||
const IssueDetailsPage: NextPageWithLayout = () => {
|
||||
// router
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, issueId } = router.query;
|
||||
// console.log(workspaceSlug, "workspaceSlug")
|
||||
|
||||
const { user } = useUserAuth();
|
||||
|
||||
|
|
@ -111,7 +107,8 @@ const IssueDetailsPage: NextPage = () => {
|
|||
}, [issueDetails, reset, issueId]);
|
||||
|
||||
return (
|
||||
<AppLayout header={<ProjectIssueDetailsHeader />} withProjectWrapper>
|
||||
<>
|
||||
{" "}
|
||||
{error ? (
|
||||
<EmptyState
|
||||
image={emptyIssue}
|
||||
|
|
@ -152,6 +149,14 @@ const IssueDetailsPage: NextPage = () => {
|
|||
</div>
|
||||
</Loader>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
IssueDetailsPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AppLayout header={<ProjectIssueDetailsHeader />} withProjectWrapper>
|
||||
{page}
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,17 +1,24 @@
|
|||
import { ReactElement } from "react";
|
||||
// components
|
||||
import { ProjectLayoutRoot } from "components/issues";
|
||||
import { ProjectIssuesHeader } from "components/headers";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
// layouts
|
||||
import { AppLayout } from "layouts/app-layout";
|
||||
|
||||
const ProjectIssues: NextPage = () => (
|
||||
<AppLayout header={<ProjectIssuesHeader />} withProjectWrapper>
|
||||
<div className="h-full w-full">
|
||||
<ProjectLayoutRoot />
|
||||
</div>
|
||||
</AppLayout>
|
||||
const ProjectIssuesPage: NextPageWithLayout = () => (
|
||||
<div className="h-full w-full">
|
||||
<ProjectLayoutRoot />
|
||||
</div>
|
||||
);
|
||||
|
||||
export default ProjectIssues;
|
||||
ProjectIssuesPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AppLayout header={<ProjectIssuesHeader />} withProjectWrapper>
|
||||
{page}
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectIssuesPage;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import React, { useState } from "react";
|
||||
import { useState, ReactElement } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import useSWR from "swr";
|
||||
// mobx store
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
|
||||
// services
|
||||
import { ModuleService } from "services/module.service";
|
||||
// hooks
|
||||
|
|
@ -22,23 +21,23 @@ import { EmptyState } from "components/common";
|
|||
// assets
|
||||
import emptyModule from "public/empty-state/module.svg";
|
||||
// types
|
||||
import { NextPage } from "next";
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
import { ISearchIssueResponse } from "types";
|
||||
|
||||
const moduleService = new ModuleService();
|
||||
|
||||
const ModuleIssuesPage: NextPage = () => {
|
||||
const ModuleIssuesPage: NextPageWithLayout = () => {
|
||||
// states
|
||||
const [moduleIssuesListModal, setModuleIssuesListModal] = useState(false);
|
||||
|
||||
// router
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, moduleId } = router.query;
|
||||
|
||||
// store
|
||||
const { module: moduleStore } = useMobxStore();
|
||||
|
||||
// hooks
|
||||
const { user } = useUser();
|
||||
|
||||
const { setToastAlert } = useToast();
|
||||
|
||||
// local storage
|
||||
const { setValue, storedValue } = useLocalStorage("module_sidebar_collapsed", "false");
|
||||
const isSidebarCollapsed = storedValue ? (storedValue === "true" ? true : false) : false;
|
||||
|
||||
|
|
@ -78,45 +77,51 @@ const ModuleIssuesPage: NextPage = () => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<AppLayout header={<ModuleIssuesHeader />} withProjectWrapper>
|
||||
{/* TODO: Update logic to bulk add issues to a cycle */}
|
||||
<ExistingIssuesListModal
|
||||
isOpen={moduleIssuesListModal}
|
||||
handleClose={() => setModuleIssuesListModal(false)}
|
||||
searchParams={{ module: true }}
|
||||
handleOnSubmit={handleAddIssuesToModule}
|
||||
{/* TODO: Update logic to bulk add issues to a cycle */}
|
||||
<ExistingIssuesListModal
|
||||
isOpen={moduleIssuesListModal}
|
||||
handleClose={() => setModuleIssuesListModal(false)}
|
||||
searchParams={{ module: true }}
|
||||
handleOnSubmit={handleAddIssuesToModule}
|
||||
/>
|
||||
{error ? (
|
||||
<EmptyState
|
||||
image={emptyModule}
|
||||
title="Module does not exist"
|
||||
description="The module you are looking for does not exist or has been deleted."
|
||||
primaryButton={{
|
||||
text: "View other modules",
|
||||
onClick: () => router.push(`/${workspaceSlug}/projects/${projectId}/modules`),
|
||||
}}
|
||||
/>
|
||||
{error ? (
|
||||
<EmptyState
|
||||
image={emptyModule}
|
||||
title="Module does not exist"
|
||||
description="The module you are looking for does not exist or has been deleted."
|
||||
primaryButton={{
|
||||
text: "View other modules",
|
||||
onClick: () => router.push(`/${workspaceSlug}/projects/${projectId}/modules`),
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<div className="flex h-full w-full">
|
||||
<div className="h-full w-full overflow-hidden">
|
||||
<ModuleLayoutRoot openIssuesListModal={openIssuesListModal} />
|
||||
</div>
|
||||
{moduleId && !isSidebarCollapsed && (
|
||||
<div
|
||||
className="flex flex-col gap-3.5 h-full w-[24rem] z-10 overflow-y-auto border-l border-custom-border-100 bg-custom-sidebar-background-100 px-6 py-3.5 duration-300 flex-shrink-0"
|
||||
style={{
|
||||
boxShadow:
|
||||
"0px 1px 4px 0px rgba(0, 0, 0, 0.06), 0px 2px 4px 0px rgba(16, 24, 40, 0.06), 0px 1px 8px -1px rgba(16, 24, 40, 0.06)",
|
||||
}}
|
||||
>
|
||||
<ModuleDetailsSidebar moduleId={moduleId.toString()} handleClose={toggleSidebar} />
|
||||
</div>
|
||||
)}
|
||||
) : (
|
||||
<div className="flex h-full w-full">
|
||||
<div className="h-full w-full overflow-hidden">
|
||||
<ModuleLayoutRoot openIssuesListModal={openIssuesListModal} />
|
||||
</div>
|
||||
)}
|
||||
</AppLayout>
|
||||
{moduleId && !isSidebarCollapsed && (
|
||||
<div
|
||||
className="flex flex-col gap-3.5 h-full w-[24rem] z-10 overflow-y-auto border-l border-custom-border-100 bg-custom-sidebar-background-100 px-6 py-3.5 duration-300 flex-shrink-0"
|
||||
style={{
|
||||
boxShadow:
|
||||
"0px 1px 4px 0px rgba(0, 0, 0, 0.06), 0px 2px 4px 0px rgba(16, 24, 40, 0.06), 0px 1px 8px -1px rgba(16, 24, 40, 0.06)",
|
||||
}}
|
||||
>
|
||||
<ModuleDetailsSidebar moduleId={moduleId.toString()} handleClose={toggleSidebar} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
ModuleIssuesPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AppLayout header={<ModuleIssuesHeader />} withProjectWrapper>
|
||||
{page}
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default ModuleIssuesPage;
|
||||
|
|
|
|||
|
|
@ -1,15 +1,20 @@
|
|||
import React from "react";
|
||||
import { NextPage } from "next";
|
||||
import { ReactElement } from "react";
|
||||
// layouts
|
||||
import { AppLayout } from "layouts/app-layout";
|
||||
// components
|
||||
import { ModulesListView } from "components/modules";
|
||||
import { ModulesListHeader } from "components/headers";
|
||||
// types
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
|
||||
const ProjectModules: NextPage = () => (
|
||||
<AppLayout header={<ModulesListHeader />} withProjectWrapper>
|
||||
<ModulesListView />
|
||||
</AppLayout>
|
||||
);
|
||||
const ProjectModulesPage: NextPageWithLayout = () => <ModulesListView />;
|
||||
|
||||
export default ProjectModules;
|
||||
ProjectModulesPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AppLayout header={<ModulesListHeader />} withProjectWrapper>
|
||||
{page}
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectModulesPage;
|
||||
|
|
|
|||
|
|
@ -1,18 +1,10 @@
|
|||
import React, { useEffect, useRef, useState } from "react";
|
||||
|
||||
import React, { useEffect, useRef, useState, ReactElement } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import useSWR, { mutate } from "swr";
|
||||
|
||||
// react-hook-form
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
// headless ui
|
||||
import { Popover, Transition } from "@headlessui/react";
|
||||
// react-color
|
||||
import { TwitterPicker } from "react-color";
|
||||
// react-beautiful-dnd
|
||||
import { DragDropContext, DropResult } from "react-beautiful-dnd";
|
||||
import StrictModeDroppable from "components/dnd/StrictModeDroppable";
|
||||
// services
|
||||
import { ProjectService } from "services/project";
|
||||
import { PageService } from "services/page.service";
|
||||
|
|
@ -23,6 +15,7 @@ import useUser from "hooks/use-user";
|
|||
// layouts
|
||||
import { AppLayout } from "layouts/app-layout";
|
||||
// components
|
||||
import StrictModeDroppable from "components/dnd/StrictModeDroppable";
|
||||
import { CreateUpdateBlockInline, SinglePageBlock } from "components/pages";
|
||||
import { CreateLabelModal } from "components/labels";
|
||||
import { CreateBlock } from "components/pages/create-block";
|
||||
|
|
@ -39,7 +32,7 @@ import { render24HourFormatTime, renderShortDate } from "helpers/date-time.helpe
|
|||
import { copyTextToClipboard } from "helpers/string.helper";
|
||||
import { orderArrayBy } from "helpers/array.helper";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
import { IIssueLabels, IPage, IPageBlock, IProjectMember } from "types";
|
||||
// fetch-keys
|
||||
import {
|
||||
|
|
@ -55,7 +48,7 @@ const projectService = new ProjectService();
|
|||
const pageService = new PageService();
|
||||
const issueLabelService = new IssueLabelService();
|
||||
|
||||
const SinglePage: NextPage = () => {
|
||||
const PageDetailsPage: NextPageWithLayout = () => {
|
||||
const [createBlockForm, setCreateBlockForm] = useState(false);
|
||||
const [labelModal, setLabelModal] = useState(false);
|
||||
const [showBlock, setShowBlock] = useState(false);
|
||||
|
|
@ -302,7 +295,7 @@ const SinglePage: NextPage = () => {
|
|||
}, [memberDetails]);
|
||||
|
||||
return (
|
||||
<AppLayout header={<PagesHeader />} withProjectWrapper>
|
||||
<>
|
||||
{error ? (
|
||||
<EmptyState
|
||||
image={emptyPage}
|
||||
|
|
@ -330,7 +323,7 @@ const SinglePage: NextPage = () => {
|
|||
<Controller
|
||||
name="name"
|
||||
control={control}
|
||||
render={({ field: { value, onChange } }) => (
|
||||
render={() => (
|
||||
<TextArea
|
||||
id="name"
|
||||
name="name"
|
||||
|
|
@ -627,8 +620,16 @@ const SinglePage: NextPage = () => {
|
|||
<Loader.Item height="200px" />
|
||||
</Loader>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
PageDetailsPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AppLayout header={<PagesHeader />} withProjectWrapper>
|
||||
{page}
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default SinglePage;
|
||||
export default PageDetailsPage;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
import { useState, Fragment } from "react";
|
||||
|
||||
import { useState, Fragment, ReactElement } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
// headless ui
|
||||
import { Tab } from "@headlessui/react";
|
||||
// hooks
|
||||
import useLocalStorage from "hooks/use-local-storage";
|
||||
|
|
@ -17,8 +14,7 @@ import { RecentPagesList, CreateUpdatePageModal, TPagesListProps } from "compone
|
|||
import { PagesHeader } from "components/headers";
|
||||
// types
|
||||
import { TPageViewProps } from "types";
|
||||
import type { NextPage } from "next";
|
||||
// fetch-keys
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
|
||||
const AllPagesList = dynamic<TPagesListProps>(() => import("components/pages").then((a) => a.AllPagesList), {
|
||||
ssr: false,
|
||||
|
|
@ -38,7 +34,7 @@ const OtherPagesList = dynamic<TPagesListProps>(() => import("components/pages")
|
|||
|
||||
const tabsList = ["Recent", "All", "Favorites", "Created by me", "Created by others"];
|
||||
|
||||
const ProjectPages: NextPage = () => {
|
||||
const ProjectPagesPage: NextPageWithLayout = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
// states
|
||||
|
|
@ -68,7 +64,7 @@ const ProjectPages: NextPage = () => {
|
|||
};
|
||||
|
||||
return (
|
||||
<AppLayout header={<PagesHeader showButton />} withProjectWrapper>
|
||||
<>
|
||||
{workspaceSlug && projectId && (
|
||||
<CreateUpdatePageModal
|
||||
isOpen={createUpdatePageModal}
|
||||
|
|
@ -160,8 +156,16 @@ const ProjectPages: NextPage = () => {
|
|||
</Tab.Panels>
|
||||
</Tab.Group>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
ProjectPagesPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AppLayout header={<PagesHeader showButton />} withProjectWrapper>
|
||||
{page}
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectPages;
|
||||
export default ProjectPagesPage;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
import React from "react";
|
||||
|
||||
import React, { ReactElement } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import useSWR, { mutate } from "swr";
|
||||
|
||||
// services
|
||||
import { ProjectService } from "services/project";
|
||||
// layouts
|
||||
|
|
@ -17,7 +14,7 @@ import useToast from "hooks/use-toast";
|
|||
import { AutoArchiveAutomation, AutoCloseAutomation } from "components/automation";
|
||||
import { ProjectSettingHeader } from "components/headers";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
import { IProject } from "types";
|
||||
// constant
|
||||
import { PROJECTS_LIST, PROJECT_DETAILS, USER_PROJECT_VIEW } from "constants/fetch-keys";
|
||||
|
|
@ -25,7 +22,7 @@ import { PROJECTS_LIST, PROJECT_DETAILS, USER_PROJECT_VIEW } from "constants/fet
|
|||
// services
|
||||
const projectService = new ProjectService();
|
||||
|
||||
const AutomationsSettings: NextPage = () => {
|
||||
const AutomationSettingsPage: NextPageWithLayout = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
|
||||
|
|
@ -70,19 +67,23 @@ const AutomationsSettings: NextPage = () => {
|
|||
|
||||
const isAdmin = memberDetails?.role === 20;
|
||||
|
||||
return (
|
||||
<section className={`pr-9 py-8 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
|
||||
<div className="flex items-center py-3.5 border-b border-custom-border-200">
|
||||
<h3 className="text-xl font-medium">Automations</h3>
|
||||
</div>
|
||||
<AutoArchiveAutomation projectDetails={projectDetails} handleChange={handleChange} disabled={!isAdmin} />
|
||||
<AutoCloseAutomation projectDetails={projectDetails} handleChange={handleChange} disabled={!isAdmin} />
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
AutomationSettingsPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AppLayout header={<ProjectSettingHeader title="Automations Settings" />} withProjectWrapper>
|
||||
<ProjectSettingLayout>
|
||||
<section className={`pr-9 py-8 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
|
||||
<div className="flex items-center py-3.5 border-b border-custom-border-200">
|
||||
<h3 className="text-xl font-medium">Automations</h3>
|
||||
</div>
|
||||
<AutoArchiveAutomation projectDetails={projectDetails} handleChange={handleChange} disabled={!isAdmin} />
|
||||
<AutoCloseAutomation projectDetails={projectDetails} handleChange={handleChange} disabled={!isAdmin} />
|
||||
</section>
|
||||
</ProjectSettingLayout>
|
||||
<ProjectSettingLayout>{page}</ProjectSettingLayout>
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default AutomationsSettings;
|
||||
export default AutomationSettingsPage;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React from "react";
|
||||
import { ReactElement } from "react";
|
||||
// layouts
|
||||
import { AppLayout } from "layouts/app-layout";
|
||||
import { ProjectSettingLayout } from "layouts/settings-layout";
|
||||
|
|
@ -6,16 +6,20 @@ import { ProjectSettingLayout } from "layouts/settings-layout";
|
|||
import { ProjectSettingHeader } from "components/headers";
|
||||
import { EstimatesList } from "components/estimates/estimate-list";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
|
||||
const EstimatesSettings: NextPage = () => (
|
||||
<AppLayout header={<ProjectSettingHeader title="Estimates Settings" />} withProjectWrapper>
|
||||
<ProjectSettingLayout>
|
||||
<div className="pr-9 py-8 w-full overflow-y-auto">
|
||||
<EstimatesList />
|
||||
</div>
|
||||
</ProjectSettingLayout>
|
||||
</AppLayout>
|
||||
const EstimatesSettingsPage: NextPageWithLayout = () => (
|
||||
<div className="pr-9 py-8 w-full overflow-y-auto">
|
||||
<EstimatesList />
|
||||
</div>
|
||||
);
|
||||
|
||||
export default EstimatesSettings;
|
||||
EstimatesSettingsPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AppLayout header={<ProjectSettingHeader title="Estimates Settings" />} withProjectWrapper>
|
||||
<ProjectSettingLayout>{page}; </ProjectSettingLayout>
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default EstimatesSettingsPage;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React from "react";
|
||||
import { ReactElement } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import useSWR from "swr";
|
||||
// mobx store
|
||||
|
|
@ -6,43 +6,43 @@ import { useMobxStore } from "lib/mobx/store-provider";
|
|||
// layouts
|
||||
import { AppLayout } from "layouts/app-layout";
|
||||
import { ProjectSettingLayout } from "layouts/settings-layout";
|
||||
// hooks
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
// components
|
||||
import { ProjectSettingHeader } from "components/headers";
|
||||
import { ProjectFeaturesList } from "components/project";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
|
||||
const FeaturesSettings: NextPage = () => {
|
||||
const FeaturesSettingsPage: NextPageWithLayout = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
|
||||
const {} = useUserAuth();
|
||||
|
||||
const { user: userStore } = useMobxStore();
|
||||
// store
|
||||
const {
|
||||
user: { fetchUserProjectInfo },
|
||||
} = useMobxStore();
|
||||
|
||||
const { data: memberDetails } = useSWR(
|
||||
workspaceSlug && projectId ? `PROJECT_MEMBERS_ME_${workspaceSlug}_${projectId}` : null,
|
||||
workspaceSlug && projectId
|
||||
? () => userStore.fetchUserProjectInfo(workspaceSlug.toString(), projectId.toString())
|
||||
: null
|
||||
workspaceSlug && projectId ? () => fetchUserProjectInfo(workspaceSlug.toString(), projectId.toString()) : null
|
||||
);
|
||||
|
||||
const isAdmin = memberDetails?.role === 20;
|
||||
|
||||
return (
|
||||
<section className={`pr-9 py-8 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
|
||||
<div className="flex items-center py-3.5 border-b border-custom-border-200">
|
||||
<h3 className="text-xl font-medium">Features</h3>
|
||||
</div>
|
||||
<ProjectFeaturesList />
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
FeaturesSettingsPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AppLayout header={<ProjectSettingHeader title="Features Settings" />} withProjectWrapper>
|
||||
<ProjectSettingLayout>
|
||||
<section className={`pr-9 py-8 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
|
||||
<div className="flex items-center py-3.5 border-b border-custom-border-200">
|
||||
<h3 className="text-xl font-medium">Features</h3>
|
||||
</div>
|
||||
<ProjectFeaturesList />
|
||||
</section>
|
||||
</ProjectSettingLayout>
|
||||
<ProjectSettingLayout>{page}</ProjectSettingLayout>
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default FeaturesSettings;
|
||||
export default FeaturesSettingsPage;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { useState } from "react";
|
||||
import { useState, ReactElement } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import useSWR from "swr";
|
||||
// layouts
|
||||
import { AppLayout } from "layouts/app-layout";
|
||||
|
|
@ -14,12 +13,12 @@ import {
|
|||
ProjectDetailsFormLoader,
|
||||
} from "components/project";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
// fetch-keys
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
const GeneralSettings: NextPage = observer(() => {
|
||||
const GeneralSettingsPage: NextPageWithLayout = observer(() => {
|
||||
// store
|
||||
const { project: projectStore } = useMobxStore();
|
||||
const { currentProjectDetails } = projectStore;
|
||||
|
|
@ -42,37 +41,43 @@ const GeneralSettings: NextPage = observer(() => {
|
|||
const isAdmin = currentProjectDetails?.member_role === 20;
|
||||
|
||||
return (
|
||||
<AppLayout header={<ProjectSettingHeader title="General Settings" />} withProjectWrapper>
|
||||
<ProjectSettingLayout>
|
||||
{currentProjectDetails && (
|
||||
<DeleteProjectModal
|
||||
<>
|
||||
{currentProjectDetails && (
|
||||
<DeleteProjectModal
|
||||
project={currentProjectDetails}
|
||||
isOpen={Boolean(selectProject)}
|
||||
onClose={() => setSelectedProject(null)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className={`pr-9 py-8 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
|
||||
{currentProjectDetails && workspaceSlug ? (
|
||||
<ProjectDetailsForm
|
||||
project={currentProjectDetails}
|
||||
isOpen={Boolean(selectProject)}
|
||||
onClose={() => setSelectedProject(null)}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
isAdmin={isAdmin}
|
||||
/>
|
||||
) : (
|
||||
<ProjectDetailsFormLoader />
|
||||
)}
|
||||
|
||||
<div className={`pr-9 py-8 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
|
||||
{currentProjectDetails && workspaceSlug ? (
|
||||
<ProjectDetailsForm
|
||||
project={currentProjectDetails}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
isAdmin={isAdmin}
|
||||
/>
|
||||
) : (
|
||||
<ProjectDetailsFormLoader />
|
||||
)}
|
||||
|
||||
{isAdmin && (
|
||||
<DeleteProjectSection
|
||||
projectDetails={currentProjectDetails}
|
||||
handleDelete={() => setSelectedProject(currentProjectDetails.id ?? null)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</ProjectSettingLayout>
|
||||
</AppLayout>
|
||||
{isAdmin && (
|
||||
<DeleteProjectSection
|
||||
projectDetails={currentProjectDetails}
|
||||
handleDelete={() => setSelectedProject(currentProjectDetails.id ?? null)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export default GeneralSettings;
|
||||
GeneralSettingsPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AppLayout header={<ProjectSettingHeader title="General Settings" />} withProjectWrapper>
|
||||
<ProjectSettingLayout>{page}</ProjectSettingLayout>
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default GeneralSettingsPage;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
import React from "react";
|
||||
|
||||
import { ReactElement } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
import useSWR from "swr";
|
||||
|
||||
// layouts
|
||||
import { AppLayout } from "layouts/app-layout";
|
||||
import { ProjectSettingLayout } from "layouts/settings-layout";
|
||||
|
|
@ -20,7 +17,7 @@ import { Loader } from "@plane/ui";
|
|||
import emptyIntegration from "public/empty-state/integration.svg";
|
||||
// types
|
||||
import { IProject } from "types";
|
||||
import type { NextPage } from "next";
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
// fetch-keys
|
||||
import { PROJECT_DETAILS, WORKSPACE_INTEGRATIONS } from "constants/fetch-keys";
|
||||
|
||||
|
|
@ -28,7 +25,7 @@ import { PROJECT_DETAILS, WORKSPACE_INTEGRATIONS } from "constants/fetch-keys";
|
|||
const integrationService = new IntegrationService();
|
||||
const projectService = new ProjectService();
|
||||
|
||||
const ProjectIntegrations: NextPage = () => {
|
||||
const ProjectIntegrationsPage: NextPageWithLayout = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
|
||||
|
|
@ -45,43 +42,47 @@ const ProjectIntegrations: NextPage = () => {
|
|||
const isAdmin = projectDetails?.member_role === 20;
|
||||
|
||||
return (
|
||||
<AppLayout withProjectWrapper header={<ProjectSettingHeader title="Integrations Settings" />}>
|
||||
<ProjectSettingLayout>
|
||||
<div className={`pr-9 py-8 gap-10 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
|
||||
<div className="flex items-center py-3.5 border-b border-custom-border-200">
|
||||
<h3 className="text-xl font-medium">Integrations</h3>
|
||||
<div className={`pr-9 py-8 gap-10 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
|
||||
<div className="flex items-center py-3.5 border-b border-custom-border-200">
|
||||
<h3 className="text-xl font-medium">Integrations</h3>
|
||||
</div>
|
||||
{workspaceIntegrations ? (
|
||||
workspaceIntegrations.length > 0 ? (
|
||||
<div>
|
||||
{workspaceIntegrations.map((integration) => (
|
||||
<IntegrationCard key={integration.integration_detail.id} integration={integration} />
|
||||
))}
|
||||
</div>
|
||||
{workspaceIntegrations ? (
|
||||
workspaceIntegrations.length > 0 ? (
|
||||
<div>
|
||||
{workspaceIntegrations.map((integration) => (
|
||||
<IntegrationCard key={integration.integration_detail.id} integration={integration} />
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<EmptyState
|
||||
title="You haven't configured integrations"
|
||||
description="Configure GitHub and other integrations to sync your project issues."
|
||||
image={emptyIntegration}
|
||||
primaryButton={{
|
||||
text: "Configure now",
|
||||
onClick: () => router.push(`/${workspaceSlug}/settings/integrations`),
|
||||
}}
|
||||
disabled={!isAdmin}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<Loader className="space-y-5">
|
||||
<Loader.Item height="40px" />
|
||||
<Loader.Item height="40px" />
|
||||
<Loader.Item height="40px" />
|
||||
<Loader.Item height="40px" />
|
||||
</Loader>
|
||||
)}
|
||||
</div>
|
||||
</ProjectSettingLayout>
|
||||
) : (
|
||||
<EmptyState
|
||||
title="You haven't configured integrations"
|
||||
description="Configure GitHub and other integrations to sync your project issues."
|
||||
image={emptyIntegration}
|
||||
primaryButton={{
|
||||
text: "Configure now",
|
||||
onClick: () => router.push(`/${workspaceSlug}/settings/integrations`),
|
||||
}}
|
||||
disabled={!isAdmin}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<Loader className="space-y-5">
|
||||
<Loader.Item height="40px" />
|
||||
<Loader.Item height="40px" />
|
||||
<Loader.Item height="40px" />
|
||||
<Loader.Item height="40px" />
|
||||
</Loader>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
ProjectIntegrationsPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AppLayout withProjectWrapper header={<ProjectSettingHeader title="Integrations Settings" />}>
|
||||
<ProjectSettingLayout>{page}</ProjectSettingLayout>
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectIntegrations;
|
||||
export default ProjectIntegrationsPage;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import React from "react";
|
||||
|
||||
import { ReactElement } from "react";
|
||||
// layouts
|
||||
import { AppLayout } from "layouts/app-layout";
|
||||
import { ProjectSettingLayout } from "layouts/settings-layout";
|
||||
|
|
@ -7,16 +6,20 @@ import { ProjectSettingLayout } from "layouts/settings-layout";
|
|||
import { ProjectSettingsLabelList } from "components/labels";
|
||||
import { ProjectSettingHeader } from "components/headers";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
|
||||
const LabelsSettings: NextPage = () => (
|
||||
<AppLayout withProjectWrapper header={<ProjectSettingHeader title="Labels Settings" />}>
|
||||
<ProjectSettingLayout>
|
||||
<div className="pr-9 py-8 gap-10 w-full overflow-y-auto">
|
||||
<ProjectSettingsLabelList />
|
||||
</div>
|
||||
</ProjectSettingLayout>
|
||||
</AppLayout>
|
||||
const LabelsSettingsPage: NextPageWithLayout = () => (
|
||||
<div className="pr-9 py-8 gap-10 w-full overflow-y-auto">
|
||||
<ProjectSettingsLabelList />
|
||||
</div>
|
||||
);
|
||||
|
||||
export default LabelsSettings;
|
||||
LabelsSettingsPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AppLayout withProjectWrapper header={<ProjectSettingHeader title="Labels Settings" />}>
|
||||
<ProjectSettingLayout>{page}</ProjectSettingLayout>
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default LabelsSettingsPage;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { ReactElement } from "react";
|
||||
// layouts
|
||||
import { AppLayout } from "layouts/app-layout";
|
||||
import { ProjectSettingLayout } from "layouts/settings-layout";
|
||||
|
|
@ -5,17 +6,21 @@ import { ProjectSettingLayout } from "layouts/settings-layout";
|
|||
import { ProjectSettingHeader } from "components/headers";
|
||||
import { ProjectMemberList, ProjectSettingsMemberDefaults } from "components/project";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
|
||||
const MembersSettings: NextPage = () => (
|
||||
<AppLayout header={<ProjectSettingHeader title="Members Settings" />} withProjectWrapper>
|
||||
<ProjectSettingLayout>
|
||||
<section className={`pr-9 py-8 w-full overflow-y-auto`}>
|
||||
<ProjectSettingsMemberDefaults />
|
||||
<ProjectMemberList />
|
||||
</section>
|
||||
</ProjectSettingLayout>
|
||||
</AppLayout>
|
||||
const MembersSettingsPage: NextPageWithLayout = () => (
|
||||
<section className={`pr-9 py-8 w-full overflow-y-auto`}>
|
||||
<ProjectSettingsMemberDefaults />
|
||||
<ProjectMemberList />
|
||||
</section>
|
||||
);
|
||||
|
||||
export default MembersSettings;
|
||||
MembersSettingsPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AppLayout header={<ProjectSettingHeader title="Members Settings" />} withProjectWrapper>
|
||||
<ProjectSettingLayout>{page}</ProjectSettingLayout>
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default MembersSettingsPage;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React from "react";
|
||||
import { ReactElement } from "react";
|
||||
// layout
|
||||
import { AppLayout } from "layouts/app-layout";
|
||||
import { ProjectSettingLayout } from "layouts/settings-layout";
|
||||
|
|
@ -6,20 +6,23 @@ import { ProjectSettingLayout } from "layouts/settings-layout";
|
|||
import { ProjectSettingStateList } from "components/states";
|
||||
import { ProjectSettingHeader } from "components/headers";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
|
||||
const StatesSettings: NextPage = () => (
|
||||
<AppLayout withProjectWrapper header={<ProjectSettingHeader title="States Settings" />}>
|
||||
<ProjectSettingLayout>
|
||||
<div className="pr-9 py-8 gap-10 w-full overflow-y-auto">
|
||||
<div className="flex items-center py-3.5 border-b border-custom-border-200">
|
||||
<h3 className="text-xl font-medium">States</h3>
|
||||
</div>
|
||||
|
||||
<ProjectSettingStateList />
|
||||
</div>
|
||||
</ProjectSettingLayout>
|
||||
</AppLayout>
|
||||
const StatesSettingsPage: NextPageWithLayout = () => (
|
||||
<div className="pr-9 py-8 gap-10 w-full overflow-y-auto">
|
||||
<div className="flex items-center py-3.5 border-b border-custom-border-200">
|
||||
<h3 className="text-xl font-medium">States</h3>
|
||||
</div>
|
||||
<ProjectSettingStateList />
|
||||
</div>
|
||||
);
|
||||
|
||||
export default StatesSettings;
|
||||
StatesSettingsPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AppLayout withProjectWrapper header={<ProjectSettingHeader title="States Settings" />}>
|
||||
<ProjectSettingLayout>{page}</ProjectSettingLayout>
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default StatesSettingsPage;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { ReactElement } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import useSWR from "swr";
|
||||
// mobx store
|
||||
|
|
@ -12,9 +13,9 @@ import { EmptyState } from "components/common";
|
|||
// assets
|
||||
import emptyView from "public/empty-state/view.svg";
|
||||
// types
|
||||
import { NextPage } from "next";
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
|
||||
const ProjectViewIssues: NextPage = () => {
|
||||
const ProjectViewIssuesPage: NextPageWithLayout = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, viewId } = router.query;
|
||||
|
||||
|
|
@ -28,7 +29,7 @@ const ProjectViewIssues: NextPage = () => {
|
|||
);
|
||||
|
||||
return (
|
||||
<AppLayout header={<ProjectViewIssuesHeader />} withProjectWrapper>
|
||||
<>
|
||||
{error ? (
|
||||
<EmptyState
|
||||
image={emptyView}
|
||||
|
|
@ -42,8 +43,16 @@ const ProjectViewIssues: NextPage = () => {
|
|||
) : (
|
||||
<ProjectViewLayoutRoot />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
ProjectViewIssuesPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AppLayout header={<ProjectViewIssuesHeader />} withProjectWrapper>
|
||||
{page}
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectViewIssues;
|
||||
export default ProjectViewIssuesPage;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import React from "react";
|
||||
import type { NextPage } from "next";
|
||||
import { ReactElement } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import useSWR from "swr";
|
||||
// mobx store
|
||||
|
|
@ -9,25 +8,31 @@ import { ProjectViewsHeader } from "components/headers";
|
|||
import { ProjectViewsList } from "components/views";
|
||||
// layouts
|
||||
import { AppLayout } from "layouts/app-layout";
|
||||
// types
|
||||
import { NextPageWithLayout } from "types/app";
|
||||
|
||||
const ProjectViews: NextPage = () => {
|
||||
const ProjectViewsPage: NextPageWithLayout = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
|
||||
const { projectViews: projectViewsStore } = useMobxStore();
|
||||
// store
|
||||
const {
|
||||
projectViews: { fetchAllViews },
|
||||
} = useMobxStore();
|
||||
|
||||
useSWR(
|
||||
workspaceSlug && projectId ? `PROJECT_VIEWS_LIST_${workspaceSlug.toString()}_${projectId.toString()}` : null,
|
||||
workspaceSlug && projectId
|
||||
? () => projectViewsStore.fetchAllViews(workspaceSlug.toString(), projectId.toString())
|
||||
: null
|
||||
workspaceSlug && projectId ? () => fetchAllViews(workspaceSlug.toString(), projectId.toString()) : null
|
||||
);
|
||||
|
||||
return <ProjectViewsList />;
|
||||
};
|
||||
|
||||
ProjectViewsPage.getLayout = function getLayout(page: ReactElement) {
|
||||
return (
|
||||
<AppLayout header={<ProjectViewsHeader />} withProjectWrapper>
|
||||
<ProjectViewsList />
|
||||
{page}
|
||||
</AppLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectViews;
|
||||
export default ProjectViewsPage;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue