forked from github/plane
chore: settings page refactoring (#2477)
* chore: implemented project layout and integrated sidebar component * chore: implemented workspace layout and integrated sidebar component
This commit is contained in:
parent
0ec0ca133a
commit
c270c8689f
@ -15,7 +15,6 @@ type Props = {
|
||||
onClick: () => void;
|
||||
};
|
||||
secondaryButton?: React.ReactNode;
|
||||
isFullScreen?: boolean;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
@ -25,10 +24,9 @@ export const EmptyState: React.FC<Props> = ({
|
||||
image,
|
||||
primaryButton,
|
||||
secondaryButton,
|
||||
isFullScreen = true,
|
||||
disabled = false,
|
||||
}) => (
|
||||
<div className={`h-full w-full mx-auto grid place-items-center p-8 ${isFullScreen ? "md:w-4/5 lg:w-3/5" : ""}`}>
|
||||
<div className={`flex items-center justify-center h-full w-full`}>
|
||||
<div className="text-center flex flex-col items-center w-full">
|
||||
<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>
|
||||
|
@ -11,3 +11,5 @@ export * from "./projects";
|
||||
export * from "./profile-preferences";
|
||||
export * from "./cycles";
|
||||
export * from "./modules";
|
||||
export * from "./project-settings";
|
||||
export * from "./workspace-settings";
|
||||
|
57
web/components/headers/project-settings.tsx
Normal file
57
web/components/headers/project-settings.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
import { FC } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
|
||||
import { ArrowLeft } from "lucide-react";
|
||||
// ui
|
||||
import { BreadcrumbItem, Breadcrumbs } from "@plane/ui";
|
||||
// helper
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
// hooks
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
export interface IProjectSettingHeader {
|
||||
title: string;
|
||||
}
|
||||
|
||||
export const ProjectSettingHeader: FC<IProjectSettingHeader> = observer((props) => {
|
||||
const { title } = props;
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
// store
|
||||
const { project: projectStore } = useMobxStore();
|
||||
const projectDetails = projectId ? projectStore.project_details[projectId.toString()] : null;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`relative flex w-full flex-shrink-0 flex-row z-10 items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4`}
|
||||
>
|
||||
<div className="flex items-center gap-2 flex-grow w-full whitespace-nowrap overflow-ellipsis">
|
||||
<div className="block md:hidden">
|
||||
<button
|
||||
type="button"
|
||||
className="grid h-8 w-8 place-items-center rounded border border-custom-border-200"
|
||||
onClick={() => router.back()}
|
||||
>
|
||||
<ArrowLeft fontSize={14} strokeWidth={2} />
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<Breadcrumbs onBack={() => router.back()}>
|
||||
<BreadcrumbItem
|
||||
link={
|
||||
<Link href={`/${workspaceSlug}/projects/${projectDetails?.id}/issues`}>
|
||||
<a className={`border-r-2 border-custom-sidebar-border-200 px-3 text-sm `}>
|
||||
<p className="truncate">{`${truncateText(projectDetails?.name ?? "Project", 32)}`}</p>
|
||||
</a>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
<BreadcrumbItem title={title} unshrinkTitle />
|
||||
</Breadcrumbs>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
66
web/components/headers/workspace-settings.tsx
Normal file
66
web/components/headers/workspace-settings.tsx
Normal file
@ -0,0 +1,66 @@
|
||||
import { FC } from "react";
|
||||
import useSWR from "swr";
|
||||
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
|
||||
import { ArrowLeft } from "lucide-react";
|
||||
// ui
|
||||
import { BreadcrumbItem, Breadcrumbs } from "@plane/ui";
|
||||
// hooks
|
||||
import { observer } from "mobx-react-lite";
|
||||
// services
|
||||
import { WorkspaceService } from "services/workspace.service";
|
||||
// helpers
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
// constant
|
||||
import { WORKSPACE_DETAILS } from "constants/fetch-keys";
|
||||
|
||||
const workspaceService = new WorkspaceService();
|
||||
|
||||
export interface IWorkspaceSettingHeader {
|
||||
title: string;
|
||||
}
|
||||
|
||||
export const WorkspaceSettingHeader: FC<IWorkspaceSettingHeader> = observer((props) => {
|
||||
const { title } = props;
|
||||
const router = useRouter();
|
||||
|
||||
const { workspaceSlug } = router.query;
|
||||
|
||||
const { data: activeWorkspace } = useSWR(workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null, () =>
|
||||
workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`relative flex w-full flex-shrink-0 flex-row z-10 items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 p-4`}
|
||||
>
|
||||
<div className="flex items-center gap-2 flex-grow w-full whitespace-nowrap overflow-ellipsis">
|
||||
<div className="block md:hidden">
|
||||
<button
|
||||
type="button"
|
||||
className="grid h-8 w-8 place-items-center rounded border border-custom-border-200"
|
||||
onClick={() => router.back()}
|
||||
>
|
||||
<ArrowLeft fontSize={14} strokeWidth={2} />
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<Breadcrumbs onBack={() => router.back()}>
|
||||
<BreadcrumbItem
|
||||
link={
|
||||
<Link href={`/${workspaceSlug}`}>
|
||||
<a className={`border-r-2 border-custom-sidebar-border-200 px-3 text-sm `}>
|
||||
<p className="truncate">{`${truncateText(activeWorkspace?.name ?? "Workspace", 32)}`}</p>
|
||||
</a>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
<BreadcrumbItem title={title} unshrinkTitle />
|
||||
</Breadcrumbs>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
@ -173,7 +173,6 @@ export const NotificationPopover = () => {
|
||||
title="You're updated with all the notifications"
|
||||
description="You have read all the notifications."
|
||||
image={emptyNotification}
|
||||
isFullScreen={false}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
63
web/components/project/delete-project-section.tsx
Normal file
63
web/components/project/delete-project-section.tsx
Normal file
@ -0,0 +1,63 @@
|
||||
import React from "react";
|
||||
|
||||
// ui
|
||||
import { Disclosure, Transition } from "@headlessui/react";
|
||||
import { Button, Loader } from "@plane/ui";
|
||||
// icons
|
||||
import { ChevronDown, ChevronUp } from "lucide-react";
|
||||
// types
|
||||
import { IProject } from "types";
|
||||
|
||||
export interface IDeleteProjectSection {
|
||||
projectDetails: IProject;
|
||||
handleDelete: () => void;
|
||||
}
|
||||
|
||||
export const DeleteProjectSection: React.FC<IDeleteProjectSection> = (props) => {
|
||||
const { projectDetails, handleDelete } = props;
|
||||
return (
|
||||
<Disclosure as="div" className="border-t border-custom-border-400">
|
||||
{({ open }) => (
|
||||
<div className="w-full">
|
||||
<Disclosure.Button as="button" type="button" className="flex items-center justify-between w-full py-4">
|
||||
<span className="text-xl tracking-tight">Delete Project</span>
|
||||
{open ? <ChevronUp className="h-5 w-5" /> : <ChevronDown className="h-5 w-5" />}
|
||||
</Disclosure.Button>
|
||||
|
||||
<Transition
|
||||
show={open}
|
||||
enter="transition duration-100 ease-out"
|
||||
enterFrom="transform opacity-0"
|
||||
enterTo="transform opacity-100"
|
||||
leave="transition duration-75 ease-out"
|
||||
leaveFrom="transform opacity-100"
|
||||
leaveTo="transform opacity-0"
|
||||
>
|
||||
<Disclosure.Panel>
|
||||
<div className="flex flex-col gap-8">
|
||||
<span className="text-sm tracking-tight">
|
||||
The danger zone of the project delete page is a critical area that requires careful consideration and
|
||||
attention. When deleting a project, all of the data and resources within that project will be
|
||||
permanently removed and cannot be recovered.
|
||||
</span>
|
||||
<div>
|
||||
{projectDetails ? (
|
||||
<div>
|
||||
<Button variant="danger" onClick={handleDelete}>
|
||||
Delete my project
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<Loader className="mt-2 w-full">
|
||||
<Loader.Item height="38px" width="144px" />
|
||||
</Loader>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Disclosure.Panel>
|
||||
</Transition>
|
||||
</div>
|
||||
)}
|
||||
</Disclosure>
|
||||
);
|
||||
};
|
@ -14,3 +14,4 @@ export * from "./card";
|
||||
export * from "./join-project-modal";
|
||||
export * from "./form";
|
||||
export * from "./form-loader";
|
||||
export * from "./delete-project-section";
|
||||
|
@ -0,0 +1,2 @@
|
||||
export * from "./layout";
|
||||
export * from "./sidebar";
|
38
web/layouts/setting-layout/project-setting-layout/layout.tsx
Normal file
38
web/layouts/setting-layout/project-setting-layout/layout.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import { FC, ReactNode } from "react";
|
||||
// layouts
|
||||
import { UserAuthWrapper, ProjectAuthWrapper } from "layouts/auth-layout";
|
||||
// components
|
||||
import { AppSidebar } from "layouts/app-layout";
|
||||
import { ProjectSettingsSidebar } from "./sidebar";
|
||||
|
||||
export interface IProjectSettingLayout {
|
||||
children: ReactNode;
|
||||
header: ReactNode;
|
||||
}
|
||||
|
||||
export const ProjectSettingLayout: FC<IProjectSettingLayout> = (props) => {
|
||||
const { children, header } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<UserAuthWrapper>
|
||||
<ProjectAuthWrapper>
|
||||
<div className="relative flex h-screen w-full overflow-hidden">
|
||||
<AppSidebar />
|
||||
<main className="relative flex flex-col h-full w-full overflow-hidden bg-custom-background-100">
|
||||
{header}
|
||||
<div className="h-full w-full overflow-hidden">
|
||||
<div className="flex gap-2 relative h-full w-full overflow-x-hidden overflow-y-scroll">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<ProjectSettingsSidebar />
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</ProjectAuthWrapper>
|
||||
</UserAuthWrapper>
|
||||
</>
|
||||
);
|
||||
};
|
@ -0,0 +1,70 @@
|
||||
import React from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
|
||||
export const ProjectSettingsSidebar = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
|
||||
const projectLinks: Array<{
|
||||
label: string;
|
||||
href: string;
|
||||
}> = [
|
||||
{
|
||||
label: "General",
|
||||
href: `/${workspaceSlug}/projects/${projectId}/settings`,
|
||||
},
|
||||
{
|
||||
label: "Members",
|
||||
href: `/${workspaceSlug}/projects/${projectId}/settings/members`,
|
||||
},
|
||||
{
|
||||
label: "Features",
|
||||
href: `/${workspaceSlug}/projects/${projectId}/settings/features`,
|
||||
},
|
||||
{
|
||||
label: "States",
|
||||
href: `/${workspaceSlug}/projects/${projectId}/settings/states`,
|
||||
},
|
||||
{
|
||||
label: "Labels",
|
||||
href: `/${workspaceSlug}/projects/${projectId}/settings/labels`,
|
||||
},
|
||||
{
|
||||
label: "Integrations",
|
||||
href: `/${workspaceSlug}/projects/${projectId}/settings/integrations`,
|
||||
},
|
||||
{
|
||||
label: "Estimates",
|
||||
href: `/${workspaceSlug}/projects/${projectId}/settings/estimates`,
|
||||
},
|
||||
{
|
||||
label: "Automations",
|
||||
href: `/${workspaceSlug}/projects/${projectId}/settings/automations`,
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div className="flex flex-col gap-6 w-80 px-5">
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="text-xs text-custom-sidebar-text-400 font-semibold">SETTINGS</span>
|
||||
<div className="flex flex-col gap-1 w-full">
|
||||
{projectLinks.map((link) => (
|
||||
<Link key={link.href} href={link.href}>
|
||||
<a>
|
||||
<div
|
||||
className={`px-4 py-2 text-sm font-medium rounded-md ${
|
||||
(link.label === "Import" ? router.asPath.includes(link.href) : router.asPath === link.href)
|
||||
? "bg-custom-primary-100/10 text-custom-primary-100"
|
||||
: "text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:bg-custom-sidebar-background-80"
|
||||
}`}
|
||||
>
|
||||
{link.label}
|
||||
</div>
|
||||
</a>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -0,0 +1,2 @@
|
||||
export * from "./layout";
|
||||
export * from "./sidebar";
|
@ -0,0 +1,38 @@
|
||||
import { FC, ReactNode } from "react";
|
||||
// layouts
|
||||
import { UserAuthWrapper, WorkspaceAuthWrapper } from "layouts/auth-layout";
|
||||
// components
|
||||
import { AppSidebar } from "layouts/app-layout";
|
||||
import { WorkspaceSettingsSidebar } from "./sidebar";
|
||||
|
||||
export interface IWorkspaceSettingLayout {
|
||||
children: ReactNode;
|
||||
header: ReactNode;
|
||||
}
|
||||
|
||||
export const WorkspaceSettingLayout: FC<IWorkspaceSettingLayout> = (props) => {
|
||||
const { children, header } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<UserAuthWrapper>
|
||||
<WorkspaceAuthWrapper>
|
||||
<div className="relative flex h-screen w-full overflow-hidden">
|
||||
<AppSidebar />
|
||||
<main className="relative flex flex-col h-full w-full overflow-hidden bg-custom-background-100">
|
||||
{header}
|
||||
<div className="h-full w-full overflow-hidden">
|
||||
<div className="flex gap-2 relative h-full w-full overflow-x-hidden overflow-y-scroll">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<WorkspaceSettingsSidebar />
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</WorkspaceAuthWrapper>
|
||||
</UserAuthWrapper>
|
||||
</>
|
||||
);
|
||||
};
|
101
web/layouts/setting-layout/workspace-setting-layout/sidebar.tsx
Normal file
101
web/layouts/setting-layout/workspace-setting-layout/sidebar.tsx
Normal file
@ -0,0 +1,101 @@
|
||||
import React from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
|
||||
export const WorkspaceSettingsSidebar = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = router.query;
|
||||
|
||||
const workspaceLinks: Array<{
|
||||
label: string;
|
||||
href: string;
|
||||
}> = [
|
||||
{
|
||||
label: "General",
|
||||
href: `/${workspaceSlug}/settings`,
|
||||
},
|
||||
{
|
||||
label: "Members",
|
||||
href: `/${workspaceSlug}/settings/members`,
|
||||
},
|
||||
{
|
||||
label: "Billing & Plans",
|
||||
href: `/${workspaceSlug}/settings/billing`,
|
||||
},
|
||||
{
|
||||
label: "Integrations",
|
||||
href: `/${workspaceSlug}/settings/integrations`,
|
||||
},
|
||||
{
|
||||
label: "Imports",
|
||||
href: `/${workspaceSlug}/settings/imports`,
|
||||
},
|
||||
{
|
||||
label: "Exports",
|
||||
href: `/${workspaceSlug}/settings/exports`,
|
||||
},
|
||||
];
|
||||
|
||||
const profileLinks: Array<{
|
||||
label: string;
|
||||
href: string;
|
||||
}> = [
|
||||
{
|
||||
label: "Profile",
|
||||
href: `/${workspaceSlug}/me/profile`,
|
||||
},
|
||||
{
|
||||
label: "Activity",
|
||||
href: `/${workspaceSlug}/me/profile/activity`,
|
||||
},
|
||||
{
|
||||
label: "Preferences",
|
||||
href: `/${workspaceSlug}/me/profile/preferences`,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-6 w-80 px-5">
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="text-xs text-custom-sidebar-text-400 font-semibold">SETTINGS</span>
|
||||
<div className="flex flex-col gap-1 w-full">
|
||||
{workspaceLinks.map((link) => (
|
||||
<Link key={link.href} href={link.href}>
|
||||
<a>
|
||||
<div
|
||||
className={`px-4 py-2 text-sm font-medium rounded-md ${
|
||||
(link.label === "Import" ? router.asPath.includes(link.href) : router.asPath === link.href)
|
||||
? "bg-custom-primary-100/10 text-custom-primary-100"
|
||||
: "text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:bg-custom-sidebar-background-80"
|
||||
}`}
|
||||
>
|
||||
{link.label}
|
||||
</div>
|
||||
</a>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="text-xs text-custom-sidebar-text-400 font-semibold">My Account</span>
|
||||
<div className="flex flex-col gap-1 w-full">
|
||||
{profileLinks.map((link) => (
|
||||
<Link key={link.href} href={link.href}>
|
||||
<a>
|
||||
<div
|
||||
className={`px-4 py-2 text-sm font-medium rounded-md ${
|
||||
(link.label === "Import" ? router.asPath.includes(link.href) : router.asPath === link.href)
|
||||
? "bg-custom-primary-100/10 text-custom-primary-100"
|
||||
: "text-custom-sidebar-text-200 hover:bg-custom-sidebar-background-80 focus:bg-custom-sidebar-background-80"
|
||||
}`}
|
||||
>
|
||||
{link.label}
|
||||
</div>
|
||||
</a>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -4,19 +4,19 @@ import Link from "next/link";
|
||||
// services
|
||||
import { UserService } from "services/user.service";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
import { WorkspaceSettingLayout } from "layouts/setting-layout/workspace-setting-layout";
|
||||
// components
|
||||
import { ActivityIcon, ActivityMessage } from "components/core";
|
||||
import { RichReadOnlyEditor } from "@plane/rich-text-editor";
|
||||
import { WorkspaceSettingHeader } from "components/headers";
|
||||
// icons
|
||||
import { History, MessageSquare } from "lucide-react";
|
||||
// ui
|
||||
import { BreadcrumbItem, Breadcrumbs, ExternalLinkIcon, Loader } from "@plane/ui";
|
||||
import { ExternalLinkIcon, Loader } from "@plane/ui";
|
||||
// fetch-keys
|
||||
import { USER_ACTIVITY } from "constants/fetch-keys";
|
||||
// helper
|
||||
import { timeAgo } from "helpers/date-time.helper";
|
||||
import { SettingsSidebar } from "components/project";
|
||||
|
||||
const userService = new UserService();
|
||||
|
||||
@ -30,18 +30,7 @@ const ProfileActivity = () => {
|
||||
);
|
||||
|
||||
return (
|
||||
<WorkspaceAuthorizationLayout
|
||||
breadcrumbs={
|
||||
<Breadcrumbs onBack={() => router.back()}>
|
||||
<BreadcrumbItem title="My Profile Activity" />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
>
|
||||
<div className="flex flex-row gap-2 h-full">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<SettingsSidebar />
|
||||
</div>
|
||||
|
||||
<WorkspaceSettingLayout header={<WorkspaceSettingHeader title="My Profile Activity" />}>
|
||||
{userActivity ? (
|
||||
<section className="pr-9 py-8 w-full overflow-y-auto">
|
||||
<div className="flex items-center py-3.5 border-b border-custom-border-200">
|
||||
@ -141,8 +130,7 @@ const ProfileActivity = () => {
|
||||
) : (
|
||||
<ActivityIcon activity={activityItem} />
|
||||
)
|
||||
) : activityItem.actor_detail.avatar &&
|
||||
activityItem.actor_detail.avatar !== "" ? (
|
||||
) : activityItem.actor_detail.avatar && activityItem.actor_detail.avatar !== "" ? (
|
||||
<img
|
||||
src={activityItem.actor_detail.avatar}
|
||||
alt={activityItem.actor_detail.display_name}
|
||||
@ -174,8 +162,7 @@ const ProfileActivity = () => {
|
||||
<a className="text-gray font-medium">{activityItem.actor_detail.display_name}</a>
|
||||
</Link>
|
||||
)}{" "}
|
||||
{message}{" "}
|
||||
<span className="whitespace-nowrap">{timeAgo(activityItem.created_at)}</span>
|
||||
{message} <span className="whitespace-nowrap">{timeAgo(activityItem.created_at)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
@ -196,8 +183,7 @@ const ProfileActivity = () => {
|
||||
<Loader.Item height="40px" />
|
||||
</Loader>
|
||||
)}
|
||||
</div>
|
||||
</WorkspaceAuthorizationLayout>
|
||||
</WorkspaceSettingLayout>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -9,12 +9,12 @@ import { UserService } from "services/user.service";
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
import useToast from "hooks/use-toast";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
import { WorkspaceSettingLayout } from "layouts/setting-layout/workspace-setting-layout";
|
||||
// components
|
||||
import { ImagePickerPopover, ImageUploadModal } from "components/core";
|
||||
import { SettingsSidebar } from "components/project";
|
||||
import { WorkspaceSettingHeader } from "components/headers";
|
||||
// ui
|
||||
import { BreadcrumbItem, Breadcrumbs, Button, Input, Spinner } from "@plane/ui";
|
||||
import { Button, Input, Spinner } from "@plane/ui";
|
||||
import { CustomSearchSelect, CustomSelect } from "components/ui";
|
||||
// icons
|
||||
import { User2, UserCircle2 } from "lucide-react";
|
||||
@ -144,13 +144,7 @@ const Profile: NextPage = () => {
|
||||
}));
|
||||
|
||||
return (
|
||||
<WorkspaceAuthorizationLayout
|
||||
breadcrumbs={
|
||||
<Breadcrumbs onBack={() => router.back()}>
|
||||
<BreadcrumbItem title="My Profile" />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
>
|
||||
<WorkspaceSettingLayout header={<WorkspaceSettingHeader title="My Profile" />}>
|
||||
<ImageUploadModal
|
||||
isOpen={isImageUploadModalOpen}
|
||||
onClose={() => setIsImageUploadModalOpen(false)}
|
||||
@ -166,10 +160,6 @@ const Profile: NextPage = () => {
|
||||
/>
|
||||
{myProfile ? (
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="flex flex-row gap-2 h-full">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<SettingsSidebar />
|
||||
</div>
|
||||
<div className={`flex flex-col gap-8 pr-9 py-9 w-full overflow-y-auto`}>
|
||||
<div className="relative h-44 w-full mt-6">
|
||||
<img
|
||||
@ -393,14 +383,13 @@ const Profile: NextPage = () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
) : (
|
||||
<div className="grid h-full w-full place-items-center px-4 sm:px-0">
|
||||
<Spinner />
|
||||
</div>
|
||||
)}
|
||||
</WorkspaceAuthorizationLayout>
|
||||
</WorkspaceSettingLayout>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -5,11 +5,10 @@ import { useTheme } from "next-themes";
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import useToast from "hooks/use-toast";
|
||||
// layouts
|
||||
import { AppLayout } from "layouts/app-layout";
|
||||
import { WorkspaceSettingLayout } from "layouts/setting-layout/workspace-setting-layout";
|
||||
// components
|
||||
import { CustomThemeSelector, ThemeSwitch } from "components/core";
|
||||
import { SettingsSidebar } from "components/project";
|
||||
import { ProfilePreferencesHeader } from "components/headers";
|
||||
import { WorkspaceSettingHeader } from "components/headers";
|
||||
// ui
|
||||
import { Spinner } from "@plane/ui";
|
||||
// constants
|
||||
@ -45,14 +44,8 @@ const ProfilePreferencesPage = observer(() => {
|
||||
};
|
||||
|
||||
return (
|
||||
<AppLayout header={<ProfilePreferencesHeader />}>
|
||||
<>
|
||||
<WorkspaceSettingLayout header={<WorkspaceSettingHeader title="My Profile Preferences" />}>
|
||||
{userStore.currentUser ? (
|
||||
<div className="flex flex-row gap-2 h-full">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<SettingsSidebar />
|
||||
</div>
|
||||
|
||||
<div className="pr-9 py-8 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">Preferences</h3>
|
||||
@ -68,14 +61,12 @@ const ProfilePreferencesPage = observer(() => {
|
||||
</div>
|
||||
{userTheme?.theme === "custom" && <CustomThemeSelector />}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid h-full w-full place-items-center px-4 sm:px-0">
|
||||
<Spinner />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
</AppLayout>
|
||||
</WorkspaceSettingLayout>
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -1,30 +1,25 @@
|
||||
import React from "react";
|
||||
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
|
||||
import useSWR, { mutate } from "swr";
|
||||
|
||||
// services
|
||||
import { ProjectService } from "services/project";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
import { ProjectSettingLayout } from "layouts/setting-layout/project-setting-layout";
|
||||
// hooks
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
import useProjectDetails from "hooks/use-project-details";
|
||||
import useToast from "hooks/use-toast";
|
||||
// components
|
||||
import { AutoArchiveAutomation, AutoCloseAutomation } from "components/automation";
|
||||
import { SettingsSidebar } from "components/project";
|
||||
// ui
|
||||
import { BreadcrumbItem, Breadcrumbs } from "@plane/ui";
|
||||
import { ProjectSettingHeader } from "components/headers";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
import { IProject } from "types";
|
||||
// constant
|
||||
import { PROJECTS_LIST, PROJECT_DETAILS, USER_PROJECT_VIEW } from "constants/fetch-keys";
|
||||
// helper
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
|
||||
// services
|
||||
const projectService = new ProjectService();
|
||||
@ -75,26 +70,7 @@ const AutomationsSettings: NextPage = () => {
|
||||
const isAdmin = memberDetails?.role === 20;
|
||||
|
||||
return (
|
||||
<ProjectAuthorizationWrapper
|
||||
breadcrumbs={
|
||||
<Breadcrumbs onBack={() => router.back()}>
|
||||
<BreadcrumbItem
|
||||
link={
|
||||
<Link href={`/${workspaceSlug}/projects/${projectDetails?.id}/issues`}>
|
||||
<a className={`border-r-2 border-custom-sidebar-border-200 px-3 text-sm `}>
|
||||
<p className="truncate">{`${truncateText(projectDetails?.name ?? "Project", 32)}`}</p>
|
||||
</a>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
<BreadcrumbItem title="Automations Settings" unshrinkTitle />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
>
|
||||
<div className="flex flex-row gap-2 h-full">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<SettingsSidebar />
|
||||
</div>
|
||||
<ProjectSettingLayout header={<ProjectSettingHeader title="Automations Settings" />}>
|
||||
<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>
|
||||
@ -102,8 +78,7 @@ const AutomationsSettings: NextPage = () => {
|
||||
<AutoArchiveAutomation projectDetails={projectDetails} handleChange={handleChange} disabled={!isAdmin} />
|
||||
<AutoCloseAutomation projectDetails={projectDetails} handleChange={handleChange} disabled={!isAdmin} />
|
||||
</section>
|
||||
</div>
|
||||
</ProjectAuthorizationWrapper>
|
||||
</ProjectSettingLayout>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,21 +1,21 @@
|
||||
import React, { useState } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
|
||||
import useSWR, { mutate } from "swr";
|
||||
// services
|
||||
import { ProjectService, ProjectEstimateService } from "services/project";
|
||||
// hooks
|
||||
import useProjectDetails from "hooks/use-project-details";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
import { ProjectSettingLayout } from "layouts/setting-layout/project-setting-layout";
|
||||
// components
|
||||
import { CreateUpdateEstimateModal, SingleEstimate } from "components/estimates";
|
||||
import { SettingsSidebar } from "components/project";
|
||||
import { ProjectSettingHeader } from "components/headers";
|
||||
//hooks
|
||||
import useToast from "hooks/use-toast";
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
// ui
|
||||
import { BreadcrumbItem, Breadcrumbs, Button, Loader } from "@plane/ui";
|
||||
import { Button, Loader } from "@plane/ui";
|
||||
import { EmptyState } from "components/common";
|
||||
// icons
|
||||
import { Plus } from "lucide-react";
|
||||
@ -26,8 +26,6 @@ import { IEstimate, IProject } from "types";
|
||||
import type { NextPage } from "next";
|
||||
// fetch-keys
|
||||
import { ESTIMATES_LIST, PROJECT_DETAILS } from "constants/fetch-keys";
|
||||
// helper
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
|
||||
// services
|
||||
const projectService = new ProjectService();
|
||||
@ -110,28 +108,10 @@ const EstimatesSettings: NextPage = () => {
|
||||
}}
|
||||
user={user}
|
||||
/>
|
||||
<ProjectAuthorizationWrapper
|
||||
breadcrumbs={
|
||||
<Breadcrumbs onBack={() => router.back()}>
|
||||
<BreadcrumbItem
|
||||
link={
|
||||
<Link href={`/${workspaceSlug}/projects/${projectDetails?.id}/issues`}>
|
||||
<a className={`border-r-2 border-custom-sidebar-border-200 px-3 text-sm `}>
|
||||
<p className="truncate">{`${truncateText(projectDetails?.name ?? "Project", 32)}`}</p>
|
||||
</a>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
<BreadcrumbItem title="Estimates Settings" unshrinkTitle />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
>
|
||||
<div className="flex flex-row gap-2 h-full">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<SettingsSidebar />
|
||||
</div>
|
||||
<div className="pr-9 py-8 flex flex-col w-full overflow-y-auto">
|
||||
<section className="flex items-center justify-between pt-2 pb-3.5 border-b border-custom-border-200">
|
||||
|
||||
<ProjectSettingLayout header={<ProjectSettingHeader title="Estimates Settings" />}>
|
||||
<div className="pr-9 py-8 w-full overflow-y-auto">
|
||||
<section className="flex items-center justify-between py-3.5 border-b border-custom-border-200">
|
||||
<h3 className="text-xl font-medium">Estimates</h3>
|
||||
<div className="col-span-12 space-y-5 sm:col-span-7">
|
||||
<div className="flex items-center gap-2">
|
||||
@ -191,8 +171,7 @@ const EstimatesSettings: NextPage = () => {
|
||||
</Loader>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</ProjectAuthorizationWrapper>
|
||||
</ProjectSettingLayout>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -1,20 +1,19 @@
|
||||
import React from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
|
||||
import useSWR, { mutate } from "swr";
|
||||
// services
|
||||
import { ProjectService } from "services/project";
|
||||
import { TrackEventService, MiscellaneousEventType } from "services/track_event.service";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
import { ProjectSettingLayout } from "layouts/setting-layout/project-setting-layout";
|
||||
// hooks
|
||||
import useToast from "hooks/use-toast";
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
// components
|
||||
import { SettingsSidebar } from "components/project";
|
||||
import { ProjectSettingHeader } from "components/headers";
|
||||
// ui
|
||||
import { BreadcrumbItem, Breadcrumbs, ContrastIcon, DiceIcon, ToggleSwitch } from "@plane/ui";
|
||||
import { ContrastIcon, DiceIcon, ToggleSwitch } from "@plane/ui";
|
||||
// icons
|
||||
import { FileText, Inbox, Layers } from "lucide-react";
|
||||
// types
|
||||
@ -22,8 +21,6 @@ import { IProject, IUser } from "types";
|
||||
import type { NextPage } from "next";
|
||||
// fetch-keys
|
||||
import { PROJECTS_LIST, PROJECT_DETAILS, USER_PROJECT_VIEW } from "constants/fetch-keys";
|
||||
// helper
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
|
||||
const featuresList = [
|
||||
{
|
||||
@ -139,26 +136,7 @@ const FeaturesSettings: NextPage = () => {
|
||||
const isAdmin = memberDetails?.role === 20;
|
||||
|
||||
return (
|
||||
<ProjectAuthorizationWrapper
|
||||
breadcrumbs={
|
||||
<Breadcrumbs onBack={() => router.back()}>
|
||||
<BreadcrumbItem
|
||||
link={
|
||||
<Link href={`/${workspaceSlug}/projects/${projectDetails?.id}/issues`}>
|
||||
<a className={`border-r-2 border-custom-sidebar-border-200 px-3 text-sm `}>
|
||||
<p className="truncate">{`${truncateText(projectDetails?.name ?? "Project", 32)}`}</p>
|
||||
</a>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
<BreadcrumbItem title="Features Settings" unshrinkTitle />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
>
|
||||
<div className="flex flex-row gap-2 h-full">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<SettingsSidebar />
|
||||
</div>
|
||||
<ProjectSettingLayout header={<ProjectSettingHeader title="Features Settings" />}>
|
||||
<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>
|
||||
@ -203,8 +181,7 @@ const FeaturesSettings: NextPage = () => {
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</ProjectAuthorizationWrapper>
|
||||
</ProjectSettingLayout>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,28 +1,25 @@
|
||||
import { useState } from "react";
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
|
||||
import useSWR from "swr";
|
||||
import { Disclosure, Transition } from "@headlessui/react";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
// services
|
||||
import { ProjectService } from "services/project";
|
||||
import { ProjectSettingLayout } from "layouts/setting-layout/project-setting-layout";
|
||||
// components
|
||||
import { DeleteProjectModal, ProjectDetailsForm, ProjectDetailsFormLoader, SettingsSidebar } from "components/project";
|
||||
import { BreadcrumbItem, Breadcrumbs, Button, Loader } from "@plane/ui";
|
||||
import { ChevronDown, ChevronUp } from "lucide-react";
|
||||
// helpers
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
import { ProjectSettingHeader } from "components/headers";
|
||||
import {
|
||||
DeleteProjectModal,
|
||||
DeleteProjectSection,
|
||||
ProjectDetailsForm,
|
||||
ProjectDetailsFormLoader,
|
||||
} from "components/project";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
// fetch-keys
|
||||
import { USER_PROJECT_VIEW } from "constants/fetch-keys";
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
// services
|
||||
const projectService = new ProjectService();
|
||||
// const projectService = new ProjectService();
|
||||
|
||||
const GeneralSettings: NextPage = observer(() => {
|
||||
const { project: projectStore } = useMobxStore();
|
||||
@ -33,9 +30,6 @@ const GeneralSettings: NextPage = observer(() => {
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
// derived values
|
||||
const projectDetails = projectId ? projectStore.project_details[projectId.toString()] : null;
|
||||
console.log("projectDetails", projectDetails);
|
||||
console.log("condition", workspaceSlug && projectId && !projectDetails);
|
||||
console.log("wow", projectId);
|
||||
// api call to fetch project details
|
||||
useSWR(
|
||||
workspaceSlug && projectId ? "PROJECT_DETAILS" : null,
|
||||
@ -43,36 +37,15 @@ const GeneralSettings: NextPage = observer(() => {
|
||||
? () => projectStore.fetchProjectDetails(workspaceSlug.toString(), projectId.toString())
|
||||
: null
|
||||
);
|
||||
// API call to fetch user privileges
|
||||
const { data: memberDetails } = useSWR(
|
||||
workspaceSlug && projectId ? USER_PROJECT_VIEW(projectId.toString()) : null,
|
||||
workspaceSlug && projectId
|
||||
? () => projectService.projectMemberMe(workspaceSlug.toString(), projectId.toString())
|
||||
: null
|
||||
);
|
||||
|
||||
// const currentNetwork = NETWORK_CHOICES.find((n) => n.key === projectDetails?.network);
|
||||
// const selectedNetwork = NETWORK_CHOICES.find((n) => n.key === watch("network"));
|
||||
|
||||
const isAdmin = memberDetails?.role === 20;
|
||||
const isAdmin = projectDetails?.member_role === 20;
|
||||
console.log("isAdmin", isAdmin);
|
||||
|
||||
return (
|
||||
<ProjectAuthorizationWrapper
|
||||
breadcrumbs={
|
||||
<Breadcrumbs onBack={() => router.back()}>
|
||||
<BreadcrumbItem
|
||||
link={
|
||||
<Link href={`/${workspaceSlug}/projects/${projectDetails?.id}/issues`}>
|
||||
<a className={`border-r-2 border-custom-sidebar-border-200 px-3 text-sm `}>
|
||||
<p className="truncate">{`${truncateText(projectDetails?.name ?? "Project", 32)}`}</p>
|
||||
</a>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
<BreadcrumbItem title="General Settings" unshrinkTitle />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
>
|
||||
<ProjectSettingLayout header={<ProjectSettingHeader title="General Settings" />}>
|
||||
{projectDetails && (
|
||||
<DeleteProjectModal
|
||||
project={projectDetails}
|
||||
@ -81,10 +54,6 @@ const GeneralSettings: NextPage = observer(() => {
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="flex flex-row gap-2 h-full">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<SettingsSidebar />
|
||||
</div>
|
||||
<div className={`pr-9 py-8 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
|
||||
{projectDetails && workspaceSlug ? (
|
||||
<ProjectDetailsForm project={projectDetails} workspaceSlug={workspaceSlug.toString()} isAdmin={isAdmin} />
|
||||
@ -93,57 +62,13 @@ const GeneralSettings: NextPage = observer(() => {
|
||||
)}
|
||||
|
||||
{isAdmin && (
|
||||
<Disclosure as="div" className="border-t border-custom-border-400">
|
||||
{({ open }) => (
|
||||
<div className="w-full">
|
||||
<Disclosure.Button
|
||||
as="button"
|
||||
type="button"
|
||||
className="flex items-center justify-between w-full py-4"
|
||||
>
|
||||
<span className="text-xl tracking-tight">Delete Project</span>
|
||||
{open ? <ChevronUp className="h-5 w-5" /> : <ChevronDown className="h-5 w-5" />}
|
||||
</Disclosure.Button>
|
||||
|
||||
<Transition
|
||||
show={open}
|
||||
enter="transition duration-100 ease-out"
|
||||
enterFrom="transform opacity-0"
|
||||
enterTo="transform opacity-100"
|
||||
leave="transition duration-75 ease-out"
|
||||
leaveFrom="transform opacity-100"
|
||||
leaveTo="transform opacity-0"
|
||||
>
|
||||
<Disclosure.Panel>
|
||||
<div className="flex flex-col gap-8">
|
||||
<span className="text-sm tracking-tight">
|
||||
The danger zone of the project delete page is a critical area that requires careful
|
||||
consideration and attention. When deleting a project, all of the data and resources within
|
||||
that project will be permanently removed and cannot be recovered.
|
||||
</span>
|
||||
<div>
|
||||
{projectDetails ? (
|
||||
<div>
|
||||
<Button variant="danger" onClick={() => setSelectedProject(projectDetails.id ?? null)}>
|
||||
Delete my project
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<Loader className="mt-2 w-full">
|
||||
<Loader.Item height="38px" width="144px" />
|
||||
</Loader>
|
||||
<DeleteProjectSection
|
||||
projectDetails={projectDetails}
|
||||
handleDelete={() => setSelectedProject(projectDetails.id ?? null)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Disclosure.Panel>
|
||||
</Transition>
|
||||
</div>
|
||||
)}
|
||||
</Disclosure>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</ProjectAuthorizationWrapper>
|
||||
</ProjectSettingLayout>
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -1,29 +1,29 @@
|
||||
import React from "react";
|
||||
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
|
||||
import useSWR from "swr";
|
||||
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
import { ProjectSettingLayout } from "layouts/setting-layout/project-setting-layout";
|
||||
// services
|
||||
import { IntegrationService } from "services/integrations";
|
||||
import { ProjectService } from "services/project";
|
||||
// components
|
||||
import { SettingsSidebar, SingleIntegration } from "components/project";
|
||||
import { SingleIntegration } from "components/project";
|
||||
import { ProjectSettingHeader } from "components/headers";
|
||||
// ui
|
||||
import { EmptyState } from "components/common";
|
||||
import { BreadcrumbItem, Breadcrumbs, Loader } from "@plane/ui";
|
||||
import { Loader } from "@plane/ui";
|
||||
// images
|
||||
import emptyIntegration from "public/empty-state/integration.svg";
|
||||
// types
|
||||
import { IProject } from "types";
|
||||
import type { NextPage } from "next";
|
||||
// fetch-keys
|
||||
import { PROJECT_DETAILS, USER_PROJECT_VIEW, WORKSPACE_INTEGRATIONS } from "constants/fetch-keys";
|
||||
import { PROJECT_DETAILS, WORKSPACE_INTEGRATIONS } from "constants/fetch-keys";
|
||||
// helper
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
// import { useMobxStore } from "lib/mobx/store-provider";
|
||||
|
||||
// services
|
||||
const integrationService = new IntegrationService();
|
||||
@ -33,6 +33,10 @@ const ProjectIntegrations: NextPage = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
|
||||
// const { project: projectStore } = useMobxStore();
|
||||
|
||||
// const projectDetails = projectId ? projectStore.project_details[projectId.toString()] : null;
|
||||
|
||||
const { data: projectDetails } = useSWR<IProject>(
|
||||
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
|
||||
workspaceSlug && projectId ? () => projectService.getProject(workspaceSlug as string, projectId as string) : null
|
||||
@ -43,36 +47,10 @@ const ProjectIntegrations: NextPage = () => {
|
||||
() => (workspaceSlug ? integrationService.getWorkspaceIntegrationsList(workspaceSlug as string) : null)
|
||||
);
|
||||
|
||||
const { data: memberDetails } = useSWR(
|
||||
workspaceSlug && projectId ? USER_PROJECT_VIEW(projectId.toString()) : null,
|
||||
workspaceSlug && projectId
|
||||
? () => projectService.projectMemberMe(workspaceSlug.toString(), projectId.toString())
|
||||
: null
|
||||
);
|
||||
|
||||
const isAdmin = memberDetails?.role === 20;
|
||||
const isAdmin = projectDetails?.member_role === 20;
|
||||
|
||||
return (
|
||||
<ProjectAuthorizationWrapper
|
||||
breadcrumbs={
|
||||
<Breadcrumbs onBack={() => router.back()}>
|
||||
<BreadcrumbItem
|
||||
link={
|
||||
<Link href={`/${workspaceSlug}/projects/${projectId}/issues`}>
|
||||
<a className={`border-r-2 border-custom-sidebar-border-200 px-3 text-sm `}>
|
||||
<p className="truncate">{`${truncateText(projectDetails?.name ?? "Project", 32)}`}</p>
|
||||
</a>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
<BreadcrumbItem title="Integrations Settings" unshrinkTitle />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
>
|
||||
<div className="flex flex-row gap-2 h-full">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<SettingsSidebar />
|
||||
</div>
|
||||
<ProjectSettingLayout header={<ProjectSettingHeader title="Integrations Settings" />}>
|
||||
<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>
|
||||
@ -105,8 +83,7 @@ const ProjectIntegrations: NextPage = () => {
|
||||
</Loader>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</ProjectAuthorizationWrapper>
|
||||
</ProjectSettingLayout>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,17 +1,15 @@
|
||||
import React, { useState, useRef } from "react";
|
||||
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
|
||||
import useSWR from "swr";
|
||||
|
||||
// hooks
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
// services
|
||||
import { ProjectService } from "services/project";
|
||||
import { IssueLabelService } from "services/issue";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
import { ProjectSettingLayout } from "layouts/setting-layout/project-setting-layout";
|
||||
// components
|
||||
import {
|
||||
CreateUpdateLabelInline,
|
||||
@ -20,9 +18,9 @@ import {
|
||||
SingleLabel,
|
||||
SingleLabelGroup,
|
||||
} from "components/labels";
|
||||
import { SettingsSidebar } from "components/project";
|
||||
import { ProjectSettingHeader } from "components/headers";
|
||||
// ui
|
||||
import { BreadcrumbItem, Breadcrumbs, Button, Loader } from "@plane/ui";
|
||||
import { Button, Loader } from "@plane/ui";
|
||||
import { EmptyState } from "components/common";
|
||||
// images
|
||||
import emptyLabel from "public/empty-state/label.svg";
|
||||
@ -30,12 +28,9 @@ import emptyLabel from "public/empty-state/label.svg";
|
||||
import { IIssueLabels } from "types";
|
||||
import type { NextPage } from "next";
|
||||
// fetch-keys
|
||||
import { PROJECT_DETAILS, PROJECT_ISSUE_LABELS } from "constants/fetch-keys";
|
||||
// helper
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys";
|
||||
|
||||
// services
|
||||
const projectService = new ProjectService();
|
||||
const issueLabelService = new IssueLabelService();
|
||||
|
||||
const LabelsSettings: NextPage = () => {
|
||||
@ -60,11 +55,6 @@ const LabelsSettings: NextPage = () => {
|
||||
|
||||
const scrollToRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { data: projectDetails } = useSWR(
|
||||
workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null,
|
||||
workspaceSlug && projectId ? () => projectService.getProject(workspaceSlug as string, projectId as string) : null
|
||||
);
|
||||
|
||||
const { data: issueLabels } = useSWR(
|
||||
workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId as string) : null,
|
||||
workspaceSlug && projectId
|
||||
@ -102,28 +92,9 @@ const LabelsSettings: NextPage = () => {
|
||||
onClose={() => setSelectDeleteLabel(null)}
|
||||
user={user}
|
||||
/>
|
||||
<ProjectAuthorizationWrapper
|
||||
breadcrumbs={
|
||||
<Breadcrumbs onBack={() => router.back()}>
|
||||
<BreadcrumbItem
|
||||
link={
|
||||
<Link href={`/${workspaceSlug}/projects/${projectDetails?.id}/issues`}>
|
||||
<a className={`border-r-2 border-custom-sidebar-border-200 px-3 text-sm `}>
|
||||
<p className="truncate">{`${truncateText(projectDetails?.name ?? "Project", 32)}`}</p>
|
||||
</a>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
<BreadcrumbItem title="Labels Settings" unshrinkTitle />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
>
|
||||
<div className="flex flex-row gap-2 h-full">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<SettingsSidebar />
|
||||
</div>
|
||||
<ProjectSettingLayout header={<ProjectSettingHeader title="Labels Settings" />}>
|
||||
<section className="pr-9 py-8 gap-10 w-full overflow-y-auto">
|
||||
<div className="flex items-center justify-between pt-2 pb-3.5 border-b border-custom-border-200">
|
||||
<div className="flex items-center justify-between py-3.5 border-b border-custom-border-200">
|
||||
<h3 className="text-xl font-medium">Labels</h3>
|
||||
|
||||
<Button variant="primary" onClick={newLabel} size="sm">
|
||||
@ -194,7 +165,6 @@ const LabelsSettings: NextPage = () => {
|
||||
text: "Add label",
|
||||
onClick: () => newLabel(),
|
||||
}}
|
||||
isFullScreen={false}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
@ -208,8 +178,7 @@ const LabelsSettings: NextPage = () => {
|
||||
</>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</ProjectAuthorizationWrapper>
|
||||
</ProjectSettingLayout>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -12,13 +12,14 @@ import useProjectMembers from "hooks/use-project-members";
|
||||
import useProjectDetails from "hooks/use-project-details";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
import { ProjectSettingLayout } from "layouts/setting-layout/project-setting-layout";
|
||||
// components
|
||||
import ConfirmProjectMemberRemove from "components/project/confirm-project-member-remove";
|
||||
import SendProjectInvitationModal from "components/project/send-project-invitation-modal";
|
||||
import { MemberSelect, SettingsSidebar } from "components/project";
|
||||
import { MemberSelect } from "components/project";
|
||||
import { ProjectSettingHeader } from "components/headers";
|
||||
// ui
|
||||
import { BreadcrumbItem, Breadcrumbs, Button, Loader } from "@plane/ui";
|
||||
import { Button, Loader } from "@plane/ui";
|
||||
import { CustomMenu, CustomSelect } from "components/ui";
|
||||
// icons
|
||||
import { ChevronDown, X } from "lucide-react";
|
||||
@ -36,8 +37,6 @@ import {
|
||||
} from "constants/fetch-keys";
|
||||
// constants
|
||||
import { ROLE } from "constants/workspace";
|
||||
// helper
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
|
||||
const defaultValues: Partial<IProject> = {
|
||||
project_lead: null,
|
||||
@ -198,22 +197,7 @@ const MembersSettings: NextPage = () => {
|
||||
const isAdmin = memberDetails?.role === 20;
|
||||
|
||||
return (
|
||||
<ProjectAuthorizationWrapper
|
||||
breadcrumbs={
|
||||
<Breadcrumbs onBack={() => router.back()}>
|
||||
<BreadcrumbItem
|
||||
link={
|
||||
<Link href={`/${workspaceSlug}/projects/${projectDetails?.id}/issues`}>
|
||||
<a className={`border-r-2 border-custom-sidebar-border-200 px-3 text-sm `}>
|
||||
<p className="truncate">{`${truncateText(projectDetails?.name ?? "Project", 32)}`}</p>
|
||||
</a>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
<BreadcrumbItem title="Members Settings" unshrinkTitle />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
>
|
||||
<ProjectSettingLayout header={<ProjectSettingHeader title="Members Settings" />}>
|
||||
<ConfirmProjectMemberRemove
|
||||
isOpen={Boolean(selectedRemoveMember) || Boolean(selectedInviteRemoveMember)}
|
||||
onClose={() => {
|
||||
@ -252,10 +236,6 @@ const MembersSettings: NextPage = () => {
|
||||
user={user}
|
||||
onSuccess={() => mutateMembers()}
|
||||
/>
|
||||
<div className="flex flex-row gap-2 h-full">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<SettingsSidebar />
|
||||
</div>
|
||||
<section className={`pr-9 py-8 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">Defaults</h3>
|
||||
@ -444,8 +424,7 @@ const MembersSettings: NextPage = () => {
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
</div>
|
||||
</ProjectAuthorizationWrapper>
|
||||
</ProjectSettingLayout>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
|
||||
import useSWR from "swr";
|
||||
|
||||
@ -11,17 +10,16 @@ import { ProjectStateService } from "services/project";
|
||||
import useProjectDetails from "hooks/use-project-details";
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
// layouts
|
||||
import { ProjectAuthorizationWrapper } from "layouts/auth-layout-legacy";
|
||||
import { ProjectSettingLayout } from "layouts/setting-layout/project-setting-layout";
|
||||
// components
|
||||
import { CreateUpdateStateInline, DeleteStateModal, SingleState, StateGroup } from "components/states";
|
||||
import { SettingsSidebar } from "components/project";
|
||||
import { ProjectSettingHeader } from "components/headers";
|
||||
// ui
|
||||
import { BreadcrumbItem, Breadcrumbs, Loader } from "@plane/ui";
|
||||
import { Loader } from "@plane/ui";
|
||||
// icons
|
||||
import { Plus } from "lucide-react";
|
||||
// helpers
|
||||
import { getStatesList, orderStateGroups } from "helpers/state.helper";
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
// fetch-keys
|
||||
@ -59,26 +57,7 @@ const StatesSettings: NextPage = () => {
|
||||
onClose={() => setSelectDeleteState(null)}
|
||||
user={user}
|
||||
/>
|
||||
<ProjectAuthorizationWrapper
|
||||
breadcrumbs={
|
||||
<Breadcrumbs onBack={() => router.back()}>
|
||||
<BreadcrumbItem
|
||||
link={
|
||||
<Link href={`/${workspaceSlug}/projects/${projectDetails?.id}/issues`}>
|
||||
<a className={`border-r-2 border-custom-sidebar-border-200 px-3 text-sm `}>
|
||||
<p className="truncate">{`${truncateText(projectDetails?.name ?? "Project", 32)}`}</p>
|
||||
</a>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
<BreadcrumbItem title="States Settings" unshrinkTitle />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
>
|
||||
<div className="flex flex-row gap-2 h-full">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<SettingsSidebar />
|
||||
</div>
|
||||
<ProjectSettingLayout header={<ProjectSettingHeader title="States Settings" />}>
|
||||
<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>
|
||||
@ -152,8 +131,7 @@ const StatesSettings: NextPage = () => {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ProjectAuthorizationWrapper>
|
||||
</ProjectSettingLayout>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -1,57 +1,15 @@
|
||||
import React from "react";
|
||||
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
|
||||
import useSWR from "swr";
|
||||
|
||||
// services
|
||||
import { WorkspaceService } from "services/workspace.service";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
import { WorkspaceSettingLayout } from "layouts/setting-layout/workspace-setting-layout";
|
||||
// component
|
||||
import { SettingsSidebar } from "components/project";
|
||||
import { WorkspaceSettingHeader } from "components/headers";
|
||||
// ui
|
||||
import { BreadcrumbItem, Breadcrumbs, Button } from "@plane/ui";
|
||||
import { Button } from "@plane/ui";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
// fetch-keys
|
||||
import { WORKSPACE_DETAILS } from "constants/fetch-keys";
|
||||
// helper
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
|
||||
// services
|
||||
const workspaceService = new WorkspaceService();
|
||||
|
||||
const BillingSettings: NextPage = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = router.query;
|
||||
|
||||
const { data: activeWorkspace } = useSWR(workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null, () =>
|
||||
workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null
|
||||
);
|
||||
|
||||
return (
|
||||
<WorkspaceAuthorizationLayout
|
||||
breadcrumbs={
|
||||
<Breadcrumbs onBack={() => router.back()}>
|
||||
<BreadcrumbItem
|
||||
link={
|
||||
<Link href={`/${workspaceSlug}`}>
|
||||
<a className={`border-r-2 border-custom-sidebar-border-200 px-3 text-sm `}>
|
||||
<p className="truncate">{`${truncateText(activeWorkspace?.name ?? "Workspace", 32)}`}</p>
|
||||
</a>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
<BreadcrumbItem title="Billing & Plans Settings" unshrinkTitle />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
>
|
||||
<div className="flex flex-row gap-2 h-full">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<SettingsSidebar />
|
||||
</div>
|
||||
const BillingSettings: NextPage = () => (
|
||||
<WorkspaceSettingLayout header={<WorkspaceSettingHeader title="Billing & Plans Settings" />}>
|
||||
<section className="pr-9 py-8 w-full overflow-y-auto">
|
||||
<div>
|
||||
<div className="flex items-center py-3.5 border-b border-custom-border-200">
|
||||
@ -68,9 +26,7 @@ const BillingSettings: NextPage = () => {
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</WorkspaceAuthorizationLayout>
|
||||
);
|
||||
};
|
||||
</WorkspaceSettingLayout>
|
||||
);
|
||||
|
||||
export default BillingSettings;
|
||||
|
@ -1,65 +1,20 @@
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
|
||||
import useSWR from "swr";
|
||||
|
||||
// services
|
||||
import { WorkspaceService } from "services/workspace.service";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
// components
|
||||
import ExportGuide from "components/exporter/guide";
|
||||
import { SettingsSidebar } from "components/project";
|
||||
// ui
|
||||
import { BreadcrumbItem, Breadcrumbs } from "@plane/ui";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
// fetch-keys
|
||||
import { WORKSPACE_DETAILS } from "constants/fetch-keys";
|
||||
// helper
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
import { WorkspaceSettingLayout } from "layouts/setting-layout/workspace-setting-layout";
|
||||
import { WorkspaceSettingHeader } from "components/headers";
|
||||
|
||||
// services
|
||||
const workspaceService = new WorkspaceService();
|
||||
|
||||
const ImportExport: NextPage = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = router.query;
|
||||
|
||||
const { data: activeWorkspace } = useSWR(workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null, () =>
|
||||
workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null
|
||||
);
|
||||
|
||||
return (
|
||||
<WorkspaceAuthorizationLayout
|
||||
breadcrumbs={
|
||||
<Breadcrumbs onBack={() => router.back()}>
|
||||
<BreadcrumbItem
|
||||
link={
|
||||
<Link href={`/${workspaceSlug}`}>
|
||||
<a className={`border-r-2 border-custom-sidebar-border-200 px-3 text-sm `}>
|
||||
<p className="truncate">{`${truncateText(activeWorkspace?.name ?? "Workspace", 32)}`}</p>
|
||||
</a>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
<BreadcrumbItem title="Export Settings" unshrinkTitle />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
>
|
||||
<div className="flex flex-row gap-2 h-full">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<SettingsSidebar />
|
||||
</div>
|
||||
const ImportExport: NextPage = () => (
|
||||
<WorkspaceSettingLayout header={<WorkspaceSettingHeader title="Export Settings" />}>
|
||||
<div className="pr-9 py-8 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">Exports</h3>
|
||||
</div>
|
||||
<ExportGuide />
|
||||
</div>
|
||||
</div>
|
||||
</WorkspaceAuthorizationLayout>
|
||||
);
|
||||
};
|
||||
</WorkspaceSettingLayout>
|
||||
);
|
||||
|
||||
export default ImportExport;
|
||||
|
@ -1,65 +1,20 @@
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
|
||||
import useSWR from "swr";
|
||||
|
||||
// services
|
||||
import { WorkspaceService } from "services/workspace.service";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
import { WorkspaceSettingLayout } from "layouts/setting-layout/workspace-setting-layout";
|
||||
// components
|
||||
import IntegrationGuide from "components/integration/guide";
|
||||
import { SettingsSidebar } from "components/project";
|
||||
// ui
|
||||
import { BreadcrumbItem, Breadcrumbs } from "@plane/ui";
|
||||
import { WorkspaceSettingHeader } from "components/headers";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
// fetch-keys
|
||||
import { WORKSPACE_DETAILS } from "constants/fetch-keys";
|
||||
// helper
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
|
||||
// services
|
||||
const workspaceService = new WorkspaceService();
|
||||
|
||||
const ImportExport: NextPage = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = router.query;
|
||||
|
||||
const { data: activeWorkspace } = useSWR(workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null, () =>
|
||||
workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null
|
||||
);
|
||||
|
||||
return (
|
||||
<WorkspaceAuthorizationLayout
|
||||
breadcrumbs={
|
||||
<Breadcrumbs onBack={() => router.back()}>
|
||||
<BreadcrumbItem
|
||||
link={
|
||||
<Link href={`/${workspaceSlug}`}>
|
||||
<a className={`border-r-2 border-custom-sidebar-border-200 px-3 text-sm `}>
|
||||
<p className="truncate">{`${truncateText(activeWorkspace?.name ?? "Workspace", 32)}`}</p>
|
||||
</a>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
<BreadcrumbItem title="Import/ Export Settings" unshrinkTitle />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
>
|
||||
<div className="flex flex-row gap-2 h-full">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<SettingsSidebar />
|
||||
</div>
|
||||
const ImportExport: NextPage = () => (
|
||||
<WorkspaceSettingLayout header={<WorkspaceSettingHeader title="Import Settings" />}>
|
||||
<section className="pr-9 py-8 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">Imports</h3>
|
||||
</div>
|
||||
<IntegrationGuide />
|
||||
</section>
|
||||
</div>
|
||||
</WorkspaceAuthorizationLayout>
|
||||
);
|
||||
};
|
||||
</WorkspaceSettingLayout>
|
||||
);
|
||||
|
||||
export default ImportExport;
|
||||
|
@ -13,19 +13,17 @@ import { FileService } from "services/file.service";
|
||||
import useToast from "hooks/use-toast";
|
||||
import useUserAuth from "hooks/use-user-auth";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
import { WorkspaceSettingLayout } from "layouts/setting-layout/workspace-setting-layout";
|
||||
// components
|
||||
import { ImageUploadModal } from "components/core";
|
||||
import { DeleteWorkspaceModal } from "components/workspace";
|
||||
import { SettingsSidebar } from "components/project";
|
||||
import { WorkspaceSettingHeader } from "components/headers";
|
||||
// ui
|
||||
import { Disclosure, Transition } from "@headlessui/react";
|
||||
import { CustomSelect } from "components/ui";
|
||||
import { BreadcrumbItem, Breadcrumbs, Button, Input, Spinner } from "@plane/ui";
|
||||
import { Button, Input, Spinner } from "@plane/ui";
|
||||
// icons
|
||||
import { ChevronDown, ChevronUp, Pencil } from "lucide-react";
|
||||
// helpers
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
// types
|
||||
import type { IWorkspace } from "types";
|
||||
import type { NextPage } from "next";
|
||||
@ -68,7 +66,6 @@ const WorkspaceSettings: NextPage = () => {
|
||||
);
|
||||
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
control,
|
||||
reset,
|
||||
@ -156,13 +153,7 @@ const WorkspaceSettings: NextPage = () => {
|
||||
const isAdmin = memberDetails?.role === 20;
|
||||
|
||||
return (
|
||||
<WorkspaceAuthorizationLayout
|
||||
breadcrumbs={
|
||||
<Breadcrumbs onBack={() => router.back()}>
|
||||
<BreadcrumbItem title={`${truncateText(activeWorkspace?.name ?? "Workspace", 32)} Settings`} />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
>
|
||||
<WorkspaceSettingLayout header={<WorkspaceSettingHeader title="General Settings" />}>
|
||||
<ImageUploadModal
|
||||
isOpen={isImageUploadModalOpen}
|
||||
onClose={() => setIsImageUploadModalOpen(false)}
|
||||
@ -184,10 +175,6 @@ const WorkspaceSettings: NextPage = () => {
|
||||
data={activeWorkspace ?? null}
|
||||
user={user}
|
||||
/>
|
||||
<div className="flex flex-row gap-2 h-full">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<SettingsSidebar />
|
||||
</div>
|
||||
{activeWorkspace ? (
|
||||
<div className={`pr-9 py-8 w-full overflow-y-auto ${isAdmin ? "" : "opacity-60"}`}>
|
||||
<div className="flex gap-5 items-center pb-7 border-b border-custom-border-200">
|
||||
@ -292,7 +279,7 @@ const WorkspaceSettings: NextPage = () => {
|
||||
<Controller
|
||||
control={control}
|
||||
name="url"
|
||||
render={({ field: { value, onChange, ref } }) => (
|
||||
render={({ field: { onChange, ref } }) => (
|
||||
<Input
|
||||
id="url"
|
||||
name="url"
|
||||
@ -366,8 +353,7 @@ const WorkspaceSettings: NextPage = () => {
|
||||
<Spinner />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</WorkspaceAuthorizationLayout>
|
||||
</WorkspaceSettingLayout>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,65 +1,38 @@
|
||||
import React from "react";
|
||||
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
|
||||
import useSWR from "swr";
|
||||
|
||||
// services
|
||||
import { WorkspaceService } from "services/workspace.service";
|
||||
import { IntegrationService } from "services/integrations";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
import { WorkspaceSettingLayout } from "layouts/setting-layout/workspace-setting-layout";
|
||||
// components
|
||||
import { SingleIntegrationCard } from "components/integration";
|
||||
import { SettingsSidebar } from "components/project";
|
||||
import { WorkspaceSettingHeader } from "components/headers";
|
||||
import { Loader } from "@plane/ui";
|
||||
// ui
|
||||
import { IntegrationAndImportExportBanner } from "components/ui";
|
||||
import { BreadcrumbItem, Breadcrumbs, Loader } from "@plane/ui";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
// fetch-keys
|
||||
import { WORKSPACE_DETAILS, APP_INTEGRATIONS } from "constants/fetch-keys";
|
||||
import { APP_INTEGRATIONS } from "constants/fetch-keys";
|
||||
// helper
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
|
||||
// services
|
||||
const workspaceService = new WorkspaceService();
|
||||
const integrationService = new IntegrationService();
|
||||
|
||||
const WorkspaceIntegrations: NextPage = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = router.query;
|
||||
|
||||
const { data: activeWorkspace } = useSWR(workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug as string) : null, () =>
|
||||
workspaceSlug ? workspaceService.getWorkspace(workspaceSlug as string) : null
|
||||
);
|
||||
|
||||
const { data: appIntegrations } = useSWR(workspaceSlug ? APP_INTEGRATIONS : null, () =>
|
||||
workspaceSlug ? integrationService.getAppIntegrationsList() : null
|
||||
);
|
||||
|
||||
return (
|
||||
<WorkspaceAuthorizationLayout
|
||||
breadcrumbs={
|
||||
<Breadcrumbs onBack={() => router.back()}>
|
||||
<BreadcrumbItem
|
||||
link={
|
||||
<Link href={`/${workspaceSlug}`}>
|
||||
<a className={`border-r-2 border-custom-sidebar-border-200 px-3 text-sm `}>
|
||||
<p className="truncate">{`${truncateText(activeWorkspace?.name ?? "Workspace", 32)}`}</p>
|
||||
</a>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
<BreadcrumbItem title="Integrations Settings" unshrinkTitle />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
>
|
||||
<div className="flex flex-row gap-2 h-full">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<SettingsSidebar />
|
||||
</div>
|
||||
<WorkspaceSettingLayout header={<WorkspaceSettingHeader title="Export Settings" />}>
|
||||
<section className="pr-9 py-8 w-full overflow-y-auto">
|
||||
<IntegrationAndImportExportBanner bannerName="Integrations" />
|
||||
<div>
|
||||
@ -75,8 +48,7 @@ const WorkspaceIntegrations: NextPage = () => {
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</WorkspaceAuthorizationLayout>
|
||||
</WorkspaceSettingLayout>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -12,24 +12,23 @@ import useToast from "hooks/use-toast";
|
||||
import useUser from "hooks/use-user";
|
||||
import useWorkspaceMembers from "hooks/use-workspace-members";
|
||||
// layouts
|
||||
import { WorkspaceAuthorizationLayout } from "layouts/auth-layout-legacy";
|
||||
import { WorkspaceSettingLayout } from "layouts/setting-layout/workspace-setting-layout";
|
||||
// components
|
||||
import ConfirmWorkspaceMemberRemove from "components/workspace/confirm-workspace-member-remove";
|
||||
import SendWorkspaceInvitationModal from "components/workspace/send-workspace-invitation-modal";
|
||||
import { SettingsSidebar } from "components/project";
|
||||
import { WorkspaceSettingHeader } from "components/headers";
|
||||
// ui
|
||||
import { BreadcrumbItem, Breadcrumbs, Button, Loader } from "@plane/ui";
|
||||
import { Button, Loader } from "@plane/ui";
|
||||
import { CustomMenu, CustomSelect } from "components/ui";
|
||||
// icons
|
||||
import { ChevronDown, X } from "lucide-react";
|
||||
// types
|
||||
import type { NextPage } from "next";
|
||||
// fetch-keys
|
||||
import { WORKSPACE_DETAILS, WORKSPACE_INVITATION_WITH_EMAIL, WORKSPACE_MEMBERS_WITH_EMAIL } from "constants/fetch-keys";
|
||||
import { WORKSPACE_INVITATION_WITH_EMAIL, WORKSPACE_MEMBERS_WITH_EMAIL } from "constants/fetch-keys";
|
||||
// constants
|
||||
import { ROLE } from "constants/workspace";
|
||||
// helper
|
||||
import { truncateText } from "helpers/string.helper";
|
||||
|
||||
// services
|
||||
const workspaceService = new WorkspaceService();
|
||||
@ -48,10 +47,6 @@ const MembersSettings: NextPage = () => {
|
||||
|
||||
const { isOwner } = useWorkspaceMembers(workspaceSlug?.toString(), Boolean(workspaceSlug));
|
||||
|
||||
const { data: activeWorkspace } = useSWR(workspaceSlug ? WORKSPACE_DETAILS(workspaceSlug.toString()) : null, () =>
|
||||
workspaceSlug ? workspaceService.getWorkspace(workspaceSlug.toString()) : null
|
||||
);
|
||||
|
||||
const { data: workspaceMembers, mutate: mutateMembers } = useSWR(
|
||||
workspaceSlug ? WORKSPACE_MEMBERS_WITH_EMAIL(workspaceSlug.toString()) : null,
|
||||
workspaceSlug ? () => workspaceService.workspaceMembersWithEmail(workspaceSlug.toString()) : null
|
||||
@ -98,22 +93,7 @@ const MembersSettings: NextPage = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<WorkspaceAuthorizationLayout
|
||||
breadcrumbs={
|
||||
<Breadcrumbs onBack={() => router.back()}>
|
||||
<BreadcrumbItem
|
||||
link={
|
||||
<Link href={`/${workspaceSlug}`}>
|
||||
<a className={`border-r-2 border-custom-sidebar-border-200 px-3 text-sm `}>
|
||||
<p className="truncate">{`${truncateText(activeWorkspace?.name ?? "Workspace", 32)}`}</p>
|
||||
</a>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
<BreadcrumbItem title="Members Settings" unshrinkTitle />
|
||||
</Breadcrumbs>
|
||||
}
|
||||
>
|
||||
<WorkspaceSettingLayout header={<WorkspaceSettingHeader title="Members Settings" />}>
|
||||
<ConfirmWorkspaceMemberRemove
|
||||
isOpen={Boolean(selectedRemoveMember) || Boolean(selectedInviteRemoveMember)}
|
||||
onClose={() => {
|
||||
@ -181,14 +161,10 @@ const MembersSettings: NextPage = () => {
|
||||
user={user}
|
||||
onSuccess={handleInviteModalSuccess}
|
||||
/>
|
||||
<div className="flex flex-row gap-2 h-full">
|
||||
<div className="w-80 pt-8 overflow-y-hidden flex-shrink-0">
|
||||
<SettingsSidebar />
|
||||
</div>
|
||||
<section className="pr-9 py-8 w-full overflow-y-auto">
|
||||
<div className="flex items-center justify-between gap-4 pt-2 pb-3.5 border-b border-custom-border-200">
|
||||
<div className="flex items-center justify-between gap-4 py-3.5 border-b border-custom-border-200">
|
||||
<h4 className="text-xl font-medium">Members</h4>
|
||||
<Button variant="primary" onClick={() => setInviteModal(true)}>
|
||||
<Button variant="primary" size="sm" onClick={() => setInviteModal(true)}>
|
||||
Add Member
|
||||
</Button>
|
||||
</div>
|
||||
@ -328,8 +304,7 @@ const MembersSettings: NextPage = () => {
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
</div>
|
||||
</WorkspaceAuthorizationLayout>
|
||||
</WorkspaceSettingLayout>
|
||||
);
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user