mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: app dir headers re-implementation (#4751)
* chore: header refactor. * fix: core imports * chore: refactor profile activity header and fix all other header imports. * fix: import fixes * chore: header refactor. * fix: app dir header reimplementation * fix: removing parllel headers * fix: adding route groups to handle pages * fix: disabling sentry for temp * chore: update default exports in layouts & headers for consistency. * fix: bugfixes * fix: build errors --------- Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
This commit is contained in:
parent
423bc15119
commit
05de4d83f3
@ -10,6 +10,6 @@ export const metadata: Metadata = {
|
||||
title: "Email Settings - God Mode",
|
||||
};
|
||||
|
||||
const EmailLayout = ({ children }: EmailLayoutProps) => <AdminLayout>{children}</AdminLayout>;
|
||||
|
||||
export default EmailLayout;
|
||||
export default function EmailLayout({ children }: EmailLayoutProps) {
|
||||
return <AdminLayout>{children}</AdminLayout>;
|
||||
}
|
||||
|
@ -10,6 +10,6 @@ export const metadata: Metadata = {
|
||||
title: "Images Settings - God Mode",
|
||||
};
|
||||
|
||||
const ImageLayout = ({ children }: ImageLayoutProps) => <AdminLayout>{children}</AdminLayout>;
|
||||
|
||||
export default ImageLayout;
|
||||
export default function ImageLayout({ children }: ImageLayoutProps) {
|
||||
return <AdminLayout>{children}</AdminLayout>;
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ import { UserProvider } from "@/lib/user-provider";
|
||||
// styles
|
||||
import "./globals.css";
|
||||
|
||||
function RootLayout({ children }: { children: ReactNode }) {
|
||||
export default function RootLayout({ children }: { children: ReactNode }) {
|
||||
// themes
|
||||
const { resolvedTheme } = useTheme();
|
||||
|
||||
@ -44,5 +44,3 @@ function RootLayout({ children }: { children: ReactNode }) {
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
export default RootLayout;
|
||||
|
8
web/app/[workspaceSlug]/(pages)/pages/layout.tsx
Normal file
8
web/app/[workspaceSlug]/(pages)/pages/layout.tsx
Normal file
@ -0,0 +1,8 @@
|
||||
export default function WorkspacePagesLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div>
|
||||
<h1>WorkspacePages Layout </h1>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
3
web/app/[workspaceSlug]/(pages)/pages/page.tsx
Normal file
3
web/app/[workspaceSlug]/(pages)/pages/page.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
export default function WorkspacePagesPage() {
|
||||
return <div>WorkspacePagesPage</div>;
|
||||
}
|
@ -7,7 +7,7 @@ import { Breadcrumbs, ContrastIcon } from "@plane/ui";
|
||||
import { BreadcrumbLink } from "@/components/common";
|
||||
// icons
|
||||
|
||||
const WorkspaceActiveCycleHeader = observer(() => (
|
||||
export const WorkspaceActiveCycleHeader = observer(() => (
|
||||
<div className="relative z-10 flex h-[3.75rem] w-full flex-shrink-0 flex-row items-center justify-between gap-x-2 gap-y-4 bg-custom-sidebar-background-100 p-4">
|
||||
<div className="flex w-full flex-grow items-center gap-2 overflow-ellipsis whitespace-nowrap">
|
||||
<div className="flex items-center gap-2">
|
||||
@ -27,5 +27,3 @@ const WorkspaceActiveCycleHeader = observer(() => (
|
||||
</div>
|
||||
</div>
|
||||
));
|
||||
|
||||
export default WorkspaceActiveCycleHeader;
|
13
web/app/[workspaceSlug]/(projects)/active-cycles/layout.tsx
Normal file
13
web/app/[workspaceSlug]/(projects)/active-cycles/layout.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
import { WorkspaceActiveCycleHeader } from "./header";
|
||||
|
||||
export default function WorkspaceActiveCycleLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<WorkspaceActiveCycleHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
@ -20,4 +20,4 @@ const WorkspaceActiveCyclesPage = observer(() => {
|
||||
);
|
||||
});
|
||||
|
||||
export default WorkspaceActiveCyclesPage;
|
||||
export default WorkspaceActiveCyclesPage;
|
@ -14,7 +14,7 @@ import { cn } from "@/helpers/common.helper";
|
||||
// hooks
|
||||
import { useAppTheme } from "@/hooks/store";
|
||||
|
||||
const WorkspaceAnalyticsHeader = observer(() => {
|
||||
export const WorkspaceAnalyticsHeader = observer(() => {
|
||||
const searchParams = useSearchParams();
|
||||
const analytics_tab = searchParams.get("analytics_tab");
|
||||
// store hooks
|
||||
@ -71,5 +71,3 @@ const WorkspaceAnalyticsHeader = observer(() => {
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export default WorkspaceAnalyticsHeader;
|
13
web/app/[workspaceSlug]/(projects)/analytics/layout.tsx
Normal file
13
web/app/[workspaceSlug]/(projects)/analytics/layout.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
import { WorkspaceAnalyticsHeader } from "./header";
|
||||
|
||||
export default function WorkspaceAnalyticsLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<WorkspaceAnalyticsHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
@ -12,7 +12,7 @@ import { EmptyState } from "@/components/empty-state";
|
||||
import { ANALYTICS_TABS } from "@/constants/analytics";
|
||||
import { EmptyStateType } from "@/constants/empty-state";
|
||||
// hooks
|
||||
import { useCommandPalette, useEventTracker, useProject, useWorkspace } from "@/hooks/store";;
|
||||
import { useCommandPalette, useEventTracker, useProject, useWorkspace } from "@/hooks/store";
|
||||
|
||||
const AnalyticsPage = observer(() => {
|
||||
const searchParams = useSearchParams();
|
||||
@ -36,8 +36,9 @@ const AnalyticsPage = observer(() => {
|
||||
<Tab key={tab.key} as={Fragment}>
|
||||
{({ selected }) => (
|
||||
<button
|
||||
className={`text-sm group relative flex items-center gap-1 h-[50px] px-3 cursor-pointer transition-all font-medium outline-none ${selected ? "text-custom-primary-100 " : "hover:text-custom-text-200"
|
||||
}`}
|
||||
className={`text-sm group relative flex items-center gap-1 h-[50px] px-3 cursor-pointer transition-all font-medium outline-none ${
|
||||
selected ? "text-custom-primary-100 " : "hover:text-custom-text-200"
|
||||
}`}
|
||||
>
|
||||
{tab.title}
|
||||
<div
|
||||
@ -71,4 +72,4 @@ const AnalyticsPage = observer(() => {
|
||||
);
|
||||
});
|
||||
|
||||
export default AnalyticsPage;
|
||||
export default AnalyticsPage;
|
@ -15,7 +15,7 @@ import { CHANGELOG_REDIRECTED, GITHUB_REDIRECTED } from "@/constants/event-track
|
||||
// hooks
|
||||
import { useEventTracker } from "@/hooks/store";
|
||||
|
||||
const WorkspaceDashboardHeader = () => {
|
||||
export const WorkspaceDashboardHeader = () => {
|
||||
// hooks
|
||||
const { captureEvent } = useEventTracker();
|
||||
const { resolvedTheme } = useTheme();
|
||||
@ -72,5 +72,3 @@ const WorkspaceDashboardHeader = () => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default WorkspaceDashboardHeader;
|
@ -3,9 +3,9 @@
|
||||
import { CommandPalette } from "@/components/command-palette";
|
||||
import { WorkspaceAuthWrapper } from "@/layouts/auth-layout";
|
||||
import { AuthenticationWrapper } from "@/lib/wrappers";
|
||||
import AppSidebar from "./sidebar";
|
||||
import { AppSidebar } from "./sidebar";
|
||||
|
||||
export default function WorkspaceLayout({ header, children }: { header: React.ReactNode; children: React.ReactNode }) {
|
||||
export default function WorkspaceLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<AuthenticationWrapper>
|
||||
<CommandPalette />
|
||||
@ -13,10 +13,7 @@ export default function WorkspaceLayout({ header, children }: { header: React.Re
|
||||
<div className="relative flex h-screen w-full overflow-hidden">
|
||||
<AppSidebar />
|
||||
<main className="relative flex h-full w-full flex-col overflow-hidden bg-custom-background-100">
|
||||
{header}
|
||||
<div className="h-full w-full overflow-hidden">
|
||||
<div className="relative h-full w-full overflow-x-hidden overflow-y-scroll">{children}</div>
|
||||
</div>
|
||||
{children}
|
||||
</main>
|
||||
</div>
|
||||
</WorkspaceAuthWrapper>
|
28
web/app/[workspaceSlug]/(projects)/page.tsx
Normal file
28
web/app/[workspaceSlug]/(projects)/page.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
// components
|
||||
import { PageHead, AppHeader, ContentWrapper } from "@/components/core";
|
||||
import { WorkspaceDashboardView } from "@/components/page-views";
|
||||
// hooks
|
||||
import { useWorkspace } from "@/hooks/store";
|
||||
// local components
|
||||
import { WorkspaceDashboardHeader } from "./header";
|
||||
|
||||
const WorkspaceDashboardPage = observer(() => {
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
// derived values
|
||||
const pageTitle = currentWorkspace?.name ? `${currentWorkspace?.name} - Home` : undefined;
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<WorkspaceDashboardHeader />} />
|
||||
<ContentWrapper>
|
||||
<PageHead title={pageTitle} />
|
||||
<WorkspaceDashboardView />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export default WorkspaceDashboardPage;
|
@ -17,7 +17,7 @@ type TUserProfileHeader = {
|
||||
type?: string | undefined;
|
||||
};
|
||||
|
||||
const UserProfileHeader: FC<TUserProfileHeader> = observer((props) => {
|
||||
export const UserProfileHeader: FC<TUserProfileHeader> = observer((props) => {
|
||||
const { type = undefined } = props;
|
||||
// router
|
||||
const { workspaceSlug, userId } = useParams();
|
||||
@ -90,5 +90,3 @@ const UserProfileHeader: FC<TUserProfileHeader> = observer((props) => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default UserProfileHeader;
|
@ -0,0 +1,69 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams, usePathname } from "next/navigation";
|
||||
// components
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
import { ProfileSidebar } from "@/components/profile";
|
||||
// constants
|
||||
import { PROFILE_ADMINS_TAB, PROFILE_VIEWER_TAB } from "@/constants/profile";
|
||||
import { EUserWorkspaceRoles } from "@/constants/workspace";
|
||||
// hooks
|
||||
import { useUser } from "@/hooks/store";
|
||||
// local components
|
||||
import { UserProfileHeader } from "./header";
|
||||
import { ProfileIssuesMobileHeader } from "./mobile-header";
|
||||
import { ProfileNavbar } from "./navbar";
|
||||
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
const AUTHORIZED_ROLES = [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER, EUserWorkspaceRoles.VIEWER];
|
||||
|
||||
const UseProfileLayout: React.FC<Props> = observer((props) => {
|
||||
const { children } = props;
|
||||
// router
|
||||
const { workspaceSlug, userId } = useParams();
|
||||
const pathname = usePathname();
|
||||
// store hooks
|
||||
const {
|
||||
membership: { currentWorkspaceRole },
|
||||
} = useUser();
|
||||
// derived values
|
||||
const isAuthorized = currentWorkspaceRole && AUTHORIZED_ROLES.includes(currentWorkspaceRole);
|
||||
const isAuthorizedPath =
|
||||
pathname.includes("assigned") || pathname.includes("created") || pathname.includes("subscribed");
|
||||
const isIssuesTab = pathname.includes("assigned") || pathname.includes("created") || pathname.includes("subscribed");
|
||||
|
||||
const tabsList = isAuthorized ? [...PROFILE_VIEWER_TAB, ...PROFILE_ADMINS_TAB] : PROFILE_VIEWER_TAB;
|
||||
const currentTab = tabsList.find((tab) => pathname === `/${workspaceSlug}/profile/${userId}${tab.selected}`);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Passing the type prop from the current route value as we need the header as top most component.
|
||||
TODO: We are depending on the route path to handle the mobile header type. If the path changes, this logic will break. */}
|
||||
<AppHeader
|
||||
header={<UserProfileHeader type={currentTab?.label} />}
|
||||
mobileHeader={isIssuesTab && <ProfileIssuesMobileHeader />}
|
||||
/>
|
||||
<ContentWrapper>
|
||||
<div className="h-full w-full flex md:overflow-hidden">
|
||||
<div className="flex w-full flex-col md:h-full md:overflow-hidden">
|
||||
<ProfileNavbar isAuthorized={!!isAuthorized} showProfileIssuesFilter={isIssuesTab} />
|
||||
{isAuthorized || !isAuthorizedPath ? (
|
||||
<div className={`w-full overflow-hidden md:h-full`}>{children}</div>
|
||||
) : (
|
||||
<div className="grid h-full w-full place-items-center text-custom-text-200">
|
||||
You do not have the permission to access this page.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<ProfileSidebar />
|
||||
</div>
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export default UseProfileLayout;
|
@ -24,7 +24,7 @@ import { calculateTotalFilters } from "@/helpers/filter.helper";
|
||||
// hooks
|
||||
import { useIssues, useLabel } from "@/hooks/store";
|
||||
|
||||
const ProfileIssuesMobileHeader = observer(() => {
|
||||
export const ProfileIssuesMobileHeader = observer(() => {
|
||||
// router
|
||||
const { workspaceSlug, userId } = useParams();
|
||||
// store hook
|
||||
@ -187,5 +187,3 @@ const ProfileIssuesMobileHeader = observer(() => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default ProfileIssuesMobileHeader;
|
@ -22,7 +22,7 @@ import { UserService } from "@/services/user.service";
|
||||
// services
|
||||
const userService = new UserService();
|
||||
|
||||
const ProfileOverviewPage = () => {
|
||||
export default function ProfileOverviewPage() {
|
||||
const { workspaceSlug, userId } = useParams();
|
||||
|
||||
const { data: userProfile } = useSWR(
|
||||
@ -51,6 +51,4 @@ const ProfileOverviewPage = () => {
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProfileOverviewPage;
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
"use client";
|
||||
|
||||
// components
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
import { ProjectArchivesHeader } from "../header";
|
||||
|
||||
export default function ProjectArchiveCyclesLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectArchivesHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
@ -14,7 +14,7 @@ import { EIssuesStoreType } from "@/constants/issue";
|
||||
import { useIssues, useProject } from "@/hooks/store";
|
||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||
|
||||
const ProjectArchivesHeader: FC = observer(() => {
|
||||
export const ProjectArchivesHeader: FC = observer(() => {
|
||||
// router
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
@ -96,5 +96,3 @@ const ProjectArchivesHeader: FC = observer(() => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default ProjectArchivesHeader;
|
@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { FC } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import useSWR from "swr";
|
||||
@ -17,7 +16,7 @@ import { IssueArchiveService } from "@/services/issue";
|
||||
|
||||
const issueArchiveService = new IssueArchiveService();
|
||||
|
||||
const ProjectArchivedIssueDetailsHeader: FC = observer(() => {
|
||||
export const ProjectArchivedIssueDetailsHeader = observer(() => {
|
||||
// router
|
||||
const { workspaceSlug, projectId, archivedIssueId } = useParams();
|
||||
// store hooks
|
||||
@ -94,5 +93,3 @@ const ProjectArchivedIssueDetailsHeader: FC = observer(() => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default ProjectArchivedIssueDetailsHeader;
|
@ -0,0 +1,14 @@
|
||||
"use client";
|
||||
|
||||
// components
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
import { ProjectArchivedIssueDetailsHeader } from "./header";
|
||||
|
||||
export default function ProjectArchivedIssueDetailLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectArchivedIssueDetailsHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
"use client";
|
||||
|
||||
// components
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
import { ProjectArchivesHeader } from "../../header";
|
||||
|
||||
export default function ProjectArchiveIssuesLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectArchivesHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
"use client";
|
||||
|
||||
// components
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
import { ProjectArchivesHeader } from "../header";
|
||||
|
||||
export default function ProjectArchiveModulesLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectArchivesHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
@ -57,7 +57,7 @@ const CycleDropdownOption: React.FC<{ cycleId: string }> = ({ cycleId }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const CycleIssuesHeader: React.FC = observer(() => {
|
||||
export const CycleIssuesHeader: React.FC = observer(() => {
|
||||
// states
|
||||
const [analyticsModal, setAnalyticsModal] = useState(false);
|
||||
// router
|
||||
@ -208,9 +208,8 @@ const CycleIssuesHeader: React.FC = observer(() => {
|
||||
{issuesCount && issuesCount > 0 ? (
|
||||
<Tooltip
|
||||
isMobile={isMobile}
|
||||
tooltipContent={`There are ${issuesCount} ${
|
||||
issuesCount > 1 ? "issues" : "issue"
|
||||
} in this cycle`}
|
||||
tooltipContent={`There are ${issuesCount} ${issuesCount > 1 ? "issues" : "issue"
|
||||
} in this cycle`}
|
||||
position="bottom"
|
||||
>
|
||||
<span className="flex flex-shrink-0 cursor-default items-center justify-center rounded-xl bg-custom-primary-100/20 px-2 text-center text-xs font-semibold text-custom-primary-100">
|
||||
@ -311,5 +310,3 @@ const CycleIssuesHeader: React.FC = observer(() => {
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export default CycleIssuesHeader;
|
@ -0,0 +1,15 @@
|
||||
"use client";
|
||||
|
||||
// components
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
import { CycleIssuesHeader } from "./header";
|
||||
import { CycleIssuesMobileHeader } from "./mobile-header";
|
||||
|
||||
export default function ProjectCycleIssuesLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<CycleIssuesHeader />} mobileHeader={<CycleIssuesMobileHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
@ -18,7 +18,7 @@ import { calculateTotalFilters } from "@/helpers/filter.helper";
|
||||
// hooks
|
||||
import { useIssues, useCycle, useProjectState, useLabel, useMember, useProject } from "@/hooks/store";
|
||||
|
||||
const CycleIssuesMobileHeader = () => {
|
||||
export const CycleIssuesMobileHeader = () => {
|
||||
const [analyticsModal, setAnalyticsModal] = useState(false);
|
||||
const { getCycleById } = useCycle();
|
||||
const layouts = [
|
||||
@ -204,5 +204,3 @@ const CycleIssuesMobileHeader = () => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default CycleIssuesMobileHeader;
|
@ -13,7 +13,7 @@ import { EUserProjectRoles } from "@/constants/project";
|
||||
// hooks
|
||||
import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store";
|
||||
|
||||
const CyclesHeader: FC = observer(() => {
|
||||
export const CyclesListHeader: FC = observer(() => {
|
||||
// router
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = useParams();
|
||||
@ -74,5 +74,3 @@ const CyclesHeader: FC = observer(() => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default CyclesHeader;
|
@ -0,0 +1,15 @@
|
||||
"use client";
|
||||
|
||||
// components
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
import { CyclesListHeader } from "./header";
|
||||
import { CyclesListMobileHeader } from "./mobile-header";
|
||||
|
||||
export default function ProjectCyclesListLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<CyclesListHeader />} mobileHeader={<CyclesListMobileHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
@ -10,7 +10,7 @@ import { CYCLE_VIEW_LAYOUTS } from "@/constants/cycle";
|
||||
// hooks
|
||||
import { useCycleFilter, useProject } from "@/hooks/store";
|
||||
|
||||
const CyclesListMobileHeader = observer(() => {
|
||||
export const CyclesListMobileHeader = observer(() => {
|
||||
const { currentProjectDetails } = useProject();
|
||||
// hooks
|
||||
const { updateDisplayFilters } = useCycleFilter();
|
||||
@ -50,5 +50,3 @@ const CyclesListMobileHeader = observer(() => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default CyclesListMobileHeader;
|
@ -18,7 +18,7 @@ import { calculateTotalFilters } from "@/helpers/filter.helper";
|
||||
import { useIssues, useLabel, useMember, useProject, useProjectState } from "@/hooks/store";
|
||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||
|
||||
const ProjectDraftIssueHeader: FC = observer(() => {
|
||||
export const ProjectDraftIssueHeader: FC = observer(() => {
|
||||
// router
|
||||
const { workspaceSlug, projectId } = useParams() as { workspaceSlug: string; projectId: string };
|
||||
// store hooks
|
||||
@ -169,5 +169,3 @@ const ProjectDraftIssueHeader: FC = observer(() => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default ProjectDraftIssueHeader;
|
@ -0,0 +1,14 @@
|
||||
"use client";
|
||||
|
||||
// components
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
import { ProjectDraftIssueHeader } from "./header";
|
||||
|
||||
export default function ProjectDraftIssuesLayou({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectDraftIssueHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
@ -12,7 +12,7 @@ import { InboxIssueCreateEditModalRoot } from "@/components/inbox";
|
||||
// hooks
|
||||
import { useProject, useProjectInbox } from "@/hooks/store";
|
||||
|
||||
const ProjectInboxHeader: FC = observer(() => {
|
||||
export const ProjectInboxHeader: FC = observer(() => {
|
||||
// states
|
||||
const [createIssueModal, setCreateIssueModal] = useState(false);
|
||||
// router
|
||||
@ -76,5 +76,3 @@ const ProjectInboxHeader: FC = observer(() => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default ProjectInboxHeader;
|
@ -0,0 +1,14 @@
|
||||
"use client";
|
||||
|
||||
// components
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
import { ProjectInboxHeader } from "./header";
|
||||
|
||||
export default function ProjectInboxIssuesLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectInboxHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { FC } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
import { PanelRight } from "lucide-react";
|
||||
@ -13,7 +12,7 @@ import { cn } from "@/helpers/common.helper";
|
||||
// hooks
|
||||
import { useAppTheme, useIssueDetail, useProject } from "@/hooks/store";
|
||||
|
||||
const ProjectIssueDetailsHeader: FC = observer(() => {
|
||||
export const ProjectIssueDetailsHeader = observer(() => {
|
||||
// router
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, issueId } = useParams();
|
||||
@ -83,5 +82,3 @@ const ProjectIssueDetailsHeader: FC = observer(() => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default ProjectIssueDetailsHeader;
|
@ -0,0 +1,14 @@
|
||||
"use client";
|
||||
|
||||
// components
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
import { ProjectIssueDetailsHeader } from "./header";
|
||||
|
||||
export default function ProjectIssueDetailsLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectIssueDetailsHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
@ -32,7 +32,7 @@ import {
|
||||
import { useIssues } from "@/hooks/store/use-issues";
|
||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||
|
||||
const ProjectIssuesHeader: React.FC = observer(() => {
|
||||
export const ProjectIssuesHeader = observer(() => {
|
||||
// states
|
||||
const [analyticsModal, setAnalyticsModal] = useState(false);
|
||||
// router
|
||||
@ -242,5 +242,3 @@ const ProjectIssuesHeader: React.FC = observer(() => {
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export default ProjectIssuesHeader;
|
@ -0,0 +1,15 @@
|
||||
"use client";
|
||||
|
||||
// components
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
import { ProjectIssuesHeader } from "./header";
|
||||
import { ProjectIssuesMobileHeader } from "./mobile-header";
|
||||
|
||||
export default function ProjectIssuesLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectIssuesHeader />} mobileHeader={<ProjectIssuesMobileHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
@ -19,7 +19,7 @@ import { calculateTotalFilters } from "@/helpers/filter.helper";
|
||||
// hooks
|
||||
import { useIssues, useLabel, useMember, useProject, useProjectState } from "@/hooks/store";
|
||||
|
||||
const ProjectIssuesMobileHeader = observer(() => {
|
||||
export const ProjectIssuesMobileHeader = observer(() => {
|
||||
const layouts = [
|
||||
{ key: "list", title: "List", icon: List },
|
||||
{ key: "kanban", title: "Kanban", icon: Kanban },
|
||||
@ -182,5 +182,3 @@ const ProjectIssuesMobileHeader = observer(() => {
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export default ProjectIssuesMobileHeader;
|
@ -60,7 +60,7 @@ const ModuleDropdownOption: React.FC<{ moduleId: string }> = ({ moduleId }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const ModuleIssuesHeader: React.FC = observer(() => {
|
||||
export const ModuleIssuesHeader: React.FC = observer(() => {
|
||||
// states
|
||||
const [analyticsModal, setAnalyticsModal] = useState(false);
|
||||
// router
|
||||
@ -317,5 +317,3 @@ const ModuleIssuesHeader: React.FC = observer(() => {
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export default ModuleIssuesHeader;
|
@ -0,0 +1,15 @@
|
||||
"use client";
|
||||
|
||||
// components
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
import { ModuleIssuesHeader } from "./header";
|
||||
import { ModuleIssuesMobileHeader } from "./mobile-header";
|
||||
|
||||
export default function ProjectModuleIssuesLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ModuleIssuesHeader />} mobileHeader={<ModuleIssuesMobileHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
@ -19,7 +19,7 @@ import { calculateTotalFilters } from "@/helpers/filter.helper";
|
||||
// hooks
|
||||
import { useIssues, useLabel, useMember, useModule, useProject, useProjectState } from "@/hooks/store";
|
||||
|
||||
const ModuleIssuesMobileHeader = observer(() => {
|
||||
export const ModuleIssuesMobileHeader = observer(() => {
|
||||
const [analyticsModal, setAnalyticsModal] = useState(false);
|
||||
const { currentProjectDetails } = useProject();
|
||||
const { getModuleById } = useModule();
|
||||
@ -185,5 +185,3 @@ const ModuleIssuesMobileHeader = observer(() => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default ModuleIssuesMobileHeader;
|
@ -12,7 +12,7 @@ import { EUserProjectRoles } from "@/constants/project";
|
||||
// hooks
|
||||
import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store";
|
||||
|
||||
const ModulesListHeader: React.FC = observer(() => {
|
||||
export const ModulesListHeader: React.FC = observer(() => {
|
||||
// router
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = useParams();
|
||||
@ -74,5 +74,3 @@ const ModulesListHeader: React.FC = observer(() => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default ModulesListHeader;
|
@ -0,0 +1,15 @@
|
||||
"use client";
|
||||
|
||||
// components
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
import { ModulesListHeader } from "./header";
|
||||
import { ModulesListMobileHeader } from "./mobile-header";
|
||||
|
||||
export default function ProjectModulesListLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ModulesListHeader />} mobileHeader={<ModulesListMobileHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
@ -5,7 +5,7 @@ import { CustomMenu } from "@plane/ui";
|
||||
import { MODULE_VIEW_LAYOUTS } from "@/constants/module";
|
||||
import { useModuleFilter, useProject } from "@/hooks/store";
|
||||
|
||||
const ModulesListMobileHeader = observer(() => {
|
||||
export const ModulesListMobileHeader = observer(() => {
|
||||
const { currentProjectDetails } = useProject();
|
||||
const { updateDisplayFilters } = useModuleFilter();
|
||||
|
||||
@ -38,5 +38,3 @@ const ModulesListMobileHeader = observer(() => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default ModulesListMobileHeader;
|
@ -20,7 +20,7 @@ export interface IPagesHeaderProps {
|
||||
showButton?: boolean;
|
||||
}
|
||||
|
||||
const PageDetailsHeader = observer(() => {
|
||||
export const PageDetailsHeader = observer(() => {
|
||||
// router
|
||||
const { workspaceSlug, pageId } = useParams();
|
||||
// state
|
||||
@ -168,5 +168,3 @@ const PageDetailsHeader = observer(() => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default PageDetailsHeader;
|
@ -0,0 +1,15 @@
|
||||
"use client";
|
||||
|
||||
// component
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
// local components
|
||||
import { PageDetailsHeader } from "./header";
|
||||
|
||||
export default function ProjectPageDetailsLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<PageDetailsHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
@ -13,7 +13,7 @@ import { EUserProjectRoles } from "@/constants/project";
|
||||
// hooks
|
||||
import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store";
|
||||
|
||||
const PagesHeader = observer(() => {
|
||||
export const PagesListHeader = observer(() => {
|
||||
// router
|
||||
const { workspaceSlug } = useParams();
|
||||
const searchParams = useSearchParams();
|
||||
@ -77,5 +77,3 @@ const PagesHeader = observer(() => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default PagesHeader;
|
@ -0,0 +1,16 @@
|
||||
"use client";
|
||||
|
||||
import { ReactNode } from "react";
|
||||
// components
|
||||
import { ContentWrapper, AppHeader } from "@/components/core";
|
||||
// local components
|
||||
import { PagesListHeader } from "./header";
|
||||
|
||||
export default function ProjectPagesListLayout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<PagesListHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
@ -13,7 +13,7 @@ import { EUserProjectRoles, PROJECT_SETTINGS_LINKS } from "@/constants/project";
|
||||
// hooks
|
||||
import { useProject, useUser } from "@/hooks/store";
|
||||
|
||||
const ProjectSettingHeader: FC = observer(() => {
|
||||
export const ProjectSettingHeader: FC = observer(() => {
|
||||
// router
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
@ -82,5 +82,3 @@ const ProjectSettingHeader: FC = observer(() => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default ProjectSettingHeader;
|
@ -0,0 +1,68 @@
|
||||
"use client";
|
||||
|
||||
import { FC, ReactNode } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import Link from "next/link";
|
||||
import { useParams } from "next/navigation";
|
||||
// ui
|
||||
import { Button, LayersIcon } from "@plane/ui";
|
||||
// components
|
||||
import { NotAuthorizedView } from "@/components/auth-screens";
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
// constants
|
||||
import { EUserProjectRoles } from "@/constants/project";
|
||||
// hooks
|
||||
import { useUser } from "@/hooks/store";
|
||||
// local components
|
||||
import { ProjectSettingHeader } from "./header";
|
||||
import { ProjectSettingsSidebar } from "./sidebar";
|
||||
|
||||
export interface IProjectSettingLayout {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
const ProjectSettingLayout: FC<IProjectSettingLayout> = observer((props) => {
|
||||
const { children } = props;
|
||||
// router
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
// store hooks
|
||||
const {
|
||||
membership: { currentProjectRole },
|
||||
} = useUser();
|
||||
|
||||
const restrictViewSettings = currentProjectRole && currentProjectRole <= EUserProjectRoles.VIEWER;
|
||||
|
||||
if (restrictViewSettings) {
|
||||
return (
|
||||
<NotAuthorizedView
|
||||
type="project"
|
||||
actionButton={
|
||||
//TODO: Create a new component called Button Link to handle such scenarios
|
||||
<Link href={`/${workspaceSlug}/projects/${projectId}/issues`}>
|
||||
<Button variant="primary" size="md" prependIcon={<LayersIcon />}>
|
||||
Go to issues
|
||||
</Button>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectSettingHeader />} />
|
||||
<ContentWrapper>
|
||||
<div className="inset-y-0 z-20 flex flex-grow-0 h-full w-full">
|
||||
<div className="w-80 flex-shrink-0 overflow-y-hidden pt-8 sm:hidden hidden md:block lg:block">
|
||||
<ProjectSettingsSidebar />
|
||||
</div>
|
||||
<div className="w-full pl-10 sm:pl-10 md:pl-0 lg:pl-0 overflow-x-hidden overflow-y-scroll vertical-scrollbar scrollbar-md">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export default ProjectSettingLayout;
|
@ -10,7 +10,7 @@ import { EUserProjectRoles, PROJECT_SETTINGS_LINKS } from "@/constants/project";
|
||||
// hooks
|
||||
import { useUser } from "@/hooks/store";
|
||||
|
||||
const ProjectSettingsSidebar = () => {
|
||||
export const ProjectSettingsSidebar = () => {
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
const pathname = usePathname();
|
||||
// mobx store
|
||||
@ -61,5 +61,3 @@ const ProjectSettingsSidebar = () => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectSettingsSidebar;
|
@ -1,4 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import Link from "next/link";
|
||||
@ -29,7 +30,7 @@ import {
|
||||
useUser,
|
||||
} from "@/hooks/store";
|
||||
|
||||
const ProjectViewIssuesHeader: React.FC = observer(() => {
|
||||
export const ProjectViewIssuesHeader: React.FC = observer(() => {
|
||||
// router
|
||||
const { workspaceSlug, projectId, viewId } = useParams();
|
||||
// store hooks
|
||||
@ -262,5 +263,3 @@ const ProjectViewIssuesHeader: React.FC = observer(() => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default ProjectViewIssuesHeader;
|
@ -31,26 +31,24 @@ const ProjectViewIssuesPage = observer(() => {
|
||||
: null
|
||||
);
|
||||
|
||||
if (error) {
|
||||
<EmptyState
|
||||
image={emptyView}
|
||||
title="View does not exist"
|
||||
description="The view you are looking for does not exist or has been deleted."
|
||||
primaryButton={{
|
||||
text: "View other views",
|
||||
onClick: () => router.push(`/${workspaceSlug}/projects/${projectId}/views`),
|
||||
}}
|
||||
/>;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{error ? (
|
||||
<EmptyState
|
||||
image={emptyView}
|
||||
title="View does not exist"
|
||||
description="The view you are looking for does not exist or has been deleted."
|
||||
primaryButton={{
|
||||
text: "View other views",
|
||||
onClick: () => router.push(`/${workspaceSlug}/projects/${projectId}/views`),
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<PageHead title={pageTitle} />
|
||||
<ProjectViewLayoutRoot />
|
||||
</>
|
||||
)}
|
||||
<PageHead title={pageTitle} />
|
||||
<ProjectViewLayoutRoot />
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export default ProjectViewIssuesPage;
|
||||
export default ProjectViewIssuesPage;
|
@ -0,0 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
// local components
|
||||
import { ProjectViewIssuesHeader } from "./[viewId]/header";
|
||||
|
||||
export default function ProjectViewIssuesLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectViewIssuesHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
@ -12,7 +12,7 @@ import { EUserProjectRoles } from "@/constants/project";
|
||||
// hooks
|
||||
import { useCommandPalette, useProject, useUser } from "@/hooks/store";
|
||||
|
||||
const ProjectViewsHeader: React.FC = observer(() => {
|
||||
export const ProjectViewsHeader = observer(() => {
|
||||
// router
|
||||
const { workspaceSlug } = useParams();
|
||||
// store hooks
|
||||
@ -70,5 +70,3 @@ const ProjectViewsHeader: React.FC = observer(() => {
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export default ProjectViewsHeader;
|
@ -0,0 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
// local components
|
||||
import { ProjectViewsHeader } from "./header";
|
||||
|
||||
export default function ProjectViewsListLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectViewsHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { ReactNode } from "react";
|
||||
// layouts
|
||||
import { ProjectAuthWrapper } from "@/layouts/auth-layout";
|
||||
|
||||
const ProjectDetailLayout = ({ children }: { children: ReactNode }) => (
|
||||
<ProjectAuthWrapper>{children}</ProjectAuthWrapper>
|
||||
);
|
||||
|
||||
export default ProjectDetailLayout;
|
@ -20,7 +20,7 @@ import { calculateTotalFilters } from "@/helpers/filter.helper";
|
||||
import { useAppRouter, useCommandPalette, useEventTracker, useMember, useProjectFilter, useUser } from "@/hooks/store";
|
||||
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
|
||||
|
||||
const ProjectsHeader = observer(() => {
|
||||
export const ProjectsListHeader = observer(() => {
|
||||
// states
|
||||
const [isSearchOpen, setIsSearchOpen] = useState(false);
|
||||
// refs
|
||||
@ -183,5 +183,3 @@ const ProjectsHeader = observer(() => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default ProjectsHeader;
|
@ -0,0 +1,17 @@
|
||||
"use client";
|
||||
|
||||
import { ReactNode } from "react";
|
||||
// components
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
// local components
|
||||
import { ProjectsListHeader } from "./header";
|
||||
import { ProjectsListMobileHeader } from "./mobile-header";
|
||||
|
||||
export default function ProjectListLayout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectsListHeader />} mobileHeader={<ProjectsListMobileHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
@ -12,7 +12,7 @@ import { calculateTotalFilters } from "@/helpers/filter.helper";
|
||||
// hooks
|
||||
import { useAppRouter, useMember, useProjectFilter } from "@/hooks/store";
|
||||
|
||||
const ProjectsMobileHeader = observer(() => {
|
||||
export const ProjectsListMobileHeader = observer(() => {
|
||||
const {
|
||||
currentWorkspaceDisplayFilters: displayFilters,
|
||||
currentWorkspaceFilters: filters,
|
||||
@ -87,5 +87,3 @@ const ProjectsMobileHeader = observer(() => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default ProjectsMobileHeader;
|
@ -61,23 +61,23 @@ const ProjectsPage = observer(() => {
|
||||
<div className="flex h-full w-full flex-col">
|
||||
{(calculateTotalFilters(currentWorkspaceFilters ?? {}) !== 0 ||
|
||||
currentWorkspaceAppliedDisplayFilters?.length !== 0) && (
|
||||
<div className="border-b border-custom-border-200 px-5 py-3">
|
||||
<ProjectAppliedFiltersList
|
||||
appliedFilters={currentWorkspaceFilters ?? {}}
|
||||
appliedDisplayFilters={currentWorkspaceAppliedDisplayFilters ?? []}
|
||||
handleClearAllFilters={handleClearAllFilters}
|
||||
handleRemoveFilter={handleRemoveFilter}
|
||||
handleRemoveDisplayFilter={handleRemoveDisplayFilter}
|
||||
filteredProjects={filteredProjectIds?.length ?? 0}
|
||||
totalProjects={totalProjectIds?.length ?? 0}
|
||||
alwaysAllowEditing
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="border-b border-custom-border-200 px-5 py-3">
|
||||
<ProjectAppliedFiltersList
|
||||
appliedFilters={currentWorkspaceFilters ?? {}}
|
||||
appliedDisplayFilters={currentWorkspaceAppliedDisplayFilters ?? []}
|
||||
handleClearAllFilters={handleClearAllFilters}
|
||||
handleRemoveFilter={handleRemoveFilter}
|
||||
handleRemoveDisplayFilter={handleRemoveDisplayFilter}
|
||||
filteredProjects={filteredProjectIds?.length ?? 0}
|
||||
totalProjects={totalProjectIds?.length ?? 0}
|
||||
alwaysAllowEditing
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<ProjectCardList />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export default ProjectsPage;
|
||||
export default ProjectsPage;
|
@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { FC } from "react";
|
||||
import { observer } from "mobx-react";;
|
||||
import { observer } from "mobx-react";
|
||||
import { Settings } from "lucide-react";
|
||||
// ui
|
||||
import { Breadcrumbs } from "@plane/ui";
|
||||
@ -10,7 +10,7 @@ import { BreadcrumbLink } from "@/components/common";
|
||||
// hooks
|
||||
import { useWorkspace } from "@/hooks/store";
|
||||
|
||||
const WorkspaceSettingHeader: FC = observer(() => {
|
||||
export const WorkspaceSettingHeader: FC = observer(() => {
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
|
||||
return (
|
||||
@ -35,5 +35,3 @@ const WorkspaceSettingHeader: FC = observer(() => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default WorkspaceSettingHeader;
|
36
web/app/[workspaceSlug]/(projects)/settings/layout.tsx
Normal file
36
web/app/[workspaceSlug]/(projects)/settings/layout.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
"use client";
|
||||
|
||||
import { ReactNode } from "react";
|
||||
// components
|
||||
import { AppHeader, ContentWrapper } from "@/components/core";
|
||||
// local components
|
||||
import { WorkspaceSettingHeader } from "./header";
|
||||
import { MobileWorkspaceSettingsTabs } from "./mobile-header-tabs";
|
||||
import { WorkspaceSettingsSidebar } from "./sidebar";
|
||||
|
||||
export interface IWorkspaceSettingLayout {
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export default function WorkspaceSettingLayout(props: IWorkspaceSettingLayout) {
|
||||
const { children } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<WorkspaceSettingHeader />} />
|
||||
<ContentWrapper>
|
||||
<div className="inset-y-0 z-20 flex h-full w-full gap-2">
|
||||
<div className="w-80 flex-shrink-0 overflow-y-hidden pt-8 sm:hidden hidden md:block lg:block">
|
||||
<WorkspaceSettingsSidebar />
|
||||
</div>
|
||||
<div className="flex flex-col relative w-full overflow-hidden">
|
||||
<MobileWorkspaceSettingsTabs />
|
||||
<div className="w-full pl-4 md:pl-0 md:py-8 py-2 overflow-x-hidden overflow-y-scroll vertical-scrollbar scrollbar-md">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import { useParams, usePathname, useRouter } from "next/navigation";
|
||||
import { WORKSPACE_SETTINGS_LINKS } from "@/constants/workspace";
|
||||
|
||||
const MobileWorkspaceSettingsTabs = () => {
|
||||
export const MobileWorkspaceSettingsTabs = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = useParams();
|
||||
const pathname = usePathname();
|
||||
@ -9,11 +9,10 @@ const MobileWorkspaceSettingsTabs = () => {
|
||||
<div className="flex-shrink-0 md:hidden sticky inset-0 flex overflow-x-auto bg-custom-background-100 z-10">
|
||||
{WORKSPACE_SETTINGS_LINKS.map((item, index) => (
|
||||
<div
|
||||
className={`${
|
||||
item.highlight(pathname, `/${workspaceSlug}`)
|
||||
className={`${item.highlight(pathname, `/${workspaceSlug}`)
|
||||
? "text-custom-primary-100 text-sm py-2 px-3 whitespace-nowrap flex flex-grow cursor-pointer justify-around border-b border-custom-primary-200"
|
||||
: "text-custom-text-200 flex flex-grow cursor-pointer justify-around border-b border-custom-border-200 text-sm py-2 px-3 whitespace-nowrap"
|
||||
}`}
|
||||
}`}
|
||||
key={index}
|
||||
onClick={() => router.push(`/${workspaceSlug}${item.href}`)}
|
||||
>
|
||||
@ -23,5 +22,3 @@ const MobileWorkspaceSettingsTabs = () => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MobileWorkspaceSettingsTabs;
|
@ -14,7 +14,7 @@ import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
|
||||
|
||||
export interface IAppSidebar { }
|
||||
|
||||
const AppSidebar: FC<IAppSidebar> = observer(() => {
|
||||
export const AppSidebar: FC<IAppSidebar> = observer(() => {
|
||||
// store hooks
|
||||
const { toggleSidebar, sidebarCollapsed } = useAppTheme();
|
||||
// refs
|
||||
@ -48,5 +48,3 @@ const AppSidebar: FC<IAppSidebar> = observer(() => {
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default AppSidebar;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user