Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95cbbbc0f9 |
@@ -14,7 +14,11 @@ import { useAppRail } from "@/hooks/use-app-rail";
|
||||
import { ExtendedAppSidebar } from "./extended-sidebar";
|
||||
import { AppSidebar } from "./sidebar";
|
||||
|
||||
export const ProjectAppSidebar: FC = observer(() => {
|
||||
type Props = {
|
||||
workspaceSlug: string;
|
||||
};
|
||||
|
||||
export const ProjectAppSidebar: FC<Props> = observer(({ workspaceSlug }) => {
|
||||
// store hooks
|
||||
const {
|
||||
sidebarCollapsed,
|
||||
@@ -51,7 +55,7 @@ export const ProjectAppSidebar: FC = observer(() => {
|
||||
togglePeek={toggleSidebarPeek}
|
||||
extendedSidebar={
|
||||
<>
|
||||
<ExtendedAppSidebar />
|
||||
<ExtendedAppSidebar workspaceSlug={workspaceSlug} />
|
||||
</>
|
||||
}
|
||||
isAnyExtendedSidebarExpanded={isAnyExtendedSidebarOpen}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
"use client";
|
||||
|
||||
// components
|
||||
import { Outlet } from "react-router";
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
// local imports
|
||||
import { WorkspaceActiveCycleHeader } from "./header";
|
||||
|
||||
export default function WorkspaceActiveCycleLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function WorkspaceActiveCycleLayout() {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<WorkspaceActiveCycleHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||
// plane web components
|
||||
import { WorkspaceActiveCyclesRoot } from "@/plane-web/components/active-cycles";
|
||||
|
||||
const WorkspaceActiveCyclesPage = observer(() => {
|
||||
function WorkspaceActiveCyclesPage() {
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
// derived values
|
||||
const pageTitle = currentWorkspace?.name ? `${currentWorkspace?.name} - Active Cycles` : undefined;
|
||||
@@ -19,6 +19,6 @@ const WorkspaceActiveCyclesPage = observer(() => {
|
||||
<WorkspaceActiveCyclesRoot />
|
||||
</>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default WorkspaceActiveCyclesPage;
|
||||
export default observer(WorkspaceActiveCyclesPage);
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
"use client";
|
||||
// components
|
||||
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "./+types/layout";
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
import { WorkspaceAnalyticsHeader } from "./header";
|
||||
|
||||
export default function WorkspaceAnalyticsTabLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function WorkspaceAnalyticsTabLayout() {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<WorkspaceAnalyticsHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { EUserPermissions, EUserPermissionsLevel, PROJECT_TRACKER_ELEMENTS } fro
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Tabs } from "@plane/ui";
|
||||
import type { TabItem } from "@plane/ui";
|
||||
import type { Route } from "./+types/page";
|
||||
// components
|
||||
import AnalyticsFilterActions from "@/components/analytics/analytics-filter-actions";
|
||||
import { PageHead } from "@/components/core/page-title";
|
||||
@@ -21,18 +22,11 @@ import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||
import { useUserPermissions } from "@/hooks/store/user";
|
||||
import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path";
|
||||
import { getAnalyticsTabs } from "@/plane-web/components/analytics/tabs";
|
||||
import { AnalyticsWorkspaceProvider } from "@/components/analytics/analytics-context";
|
||||
|
||||
type Props = {
|
||||
params: {
|
||||
tabId: string;
|
||||
workspaceSlug: string;
|
||||
};
|
||||
};
|
||||
|
||||
const AnalyticsPage = observer((props: Props) => {
|
||||
function AnalyticsPage({ params }: Route.ComponentProps) {
|
||||
// props
|
||||
const { params } = props;
|
||||
const { tabId } = params;
|
||||
const { tabId, workspaceSlug } = params;
|
||||
|
||||
// hooks
|
||||
const router = useRouter();
|
||||
@@ -82,18 +76,20 @@ const AnalyticsPage = observer((props: Props) => {
|
||||
<>
|
||||
{workspaceProjectIds.length > 0 || loader === "init-loader" ? (
|
||||
<div className="flex h-full overflow-hidden bg-custom-background-100 justify-between items-center ">
|
||||
<Tabs
|
||||
tabs={tabs}
|
||||
storageKey={`analytics-page-${currentWorkspace?.id}`}
|
||||
defaultTab={defaultTab}
|
||||
size="md"
|
||||
tabListContainerClassName="px-6 py-2 border-b border-custom-border-200 flex items-center justify-between"
|
||||
tabListClassName="my-2 w-auto"
|
||||
tabClassName="px-3"
|
||||
tabPanelClassName="h-full overflow-hidden overflow-y-auto px-2"
|
||||
storeInLocalStorage={false}
|
||||
actions={<AnalyticsFilterActions />}
|
||||
/>
|
||||
<AnalyticsWorkspaceProvider workspaceSlug={workspaceSlug}>
|
||||
<Tabs
|
||||
tabs={tabs}
|
||||
storageKey={`analytics-page-${currentWorkspace?.id}`}
|
||||
defaultTab={defaultTab}
|
||||
size="md"
|
||||
tabListContainerClassName="px-6 py-2 border-b border-custom-border-200 flex items-center justify-between"
|
||||
tabListClassName="my-2 w-auto"
|
||||
tabClassName="px-3"
|
||||
tabPanelClassName="h-full overflow-hidden overflow-y-auto px-2"
|
||||
storeInLocalStorage={false}
|
||||
actions={<AnalyticsFilterActions />}
|
||||
/>
|
||||
</AnalyticsWorkspaceProvider>
|
||||
</div>
|
||||
) : (
|
||||
<DetailedEmptyState
|
||||
@@ -118,6 +114,6 @@ const AnalyticsPage = observer((props: Props) => {
|
||||
)}
|
||||
</>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default AnalyticsPage;
|
||||
export default observer(AnalyticsPage);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
// plane imports
|
||||
import { EProjectFeatureKey } from "@plane/constants";
|
||||
import { Breadcrumbs, Header } from "@plane/ui";
|
||||
@@ -14,30 +13,34 @@ import { useProject } from "@/hooks/store/use-project";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs/common";
|
||||
|
||||
export const ProjectIssueDetailsHeader = observer(() => {
|
||||
type ProjectIssueDetailsHeaderProps = {
|
||||
workspaceSlug: string;
|
||||
workItem: string;
|
||||
};
|
||||
|
||||
export const ProjectIssueDetailsHeader = observer(({ workspaceSlug, workItem }: ProjectIssueDetailsHeaderProps) => {
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
const { workspaceSlug, workItem } = useParams();
|
||||
// store hooks
|
||||
const { getProjectById, loader } = useProject();
|
||||
const {
|
||||
issue: { getIssueById, getIssueIdByIdentifier },
|
||||
} = useIssueDetail();
|
||||
// derived values
|
||||
const issueId = getIssueIdByIdentifier(workItem?.toString());
|
||||
const issueDetails = issueId ? getIssueById(issueId.toString()) : undefined;
|
||||
const issueId = getIssueIdByIdentifier(workItem);
|
||||
const issueDetails = issueId ? getIssueById(issueId) : undefined;
|
||||
const projectId = issueDetails ? issueDetails?.project_id : undefined;
|
||||
const projectDetails = projectId ? getProjectById(projectId?.toString()) : undefined;
|
||||
const projectDetails = projectId ? getProjectById(projectId) : undefined;
|
||||
|
||||
if (!workspaceSlug || !projectId || !issueId) return null;
|
||||
if (!projectId || !issueId) return null;
|
||||
|
||||
return (
|
||||
<Header>
|
||||
<Header.LeftItem>
|
||||
<Breadcrumbs onBack={router.back} isLoading={loader === "init-loader"}>
|
||||
<CommonProjectBreadcrumbs
|
||||
workspaceSlug={workspaceSlug?.toString()}
|
||||
projectId={projectId?.toString()}
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
featureKey={EProjectFeatureKey.WORK_ITEMS}
|
||||
/>
|
||||
<Breadcrumbs.Item
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
"use client";
|
||||
|
||||
// components
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "./+types/layout";
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
import { ProjectIssueDetailsHeader } from "./header";
|
||||
|
||||
export default function ProjectIssueDetailsLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function ProjectIssueDetailsLayout({ params }: Route.ComponentProps) {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectIssueDetailsHeader />} />
|
||||
<ContentWrapper className="overflow-hidden">{children}</ContentWrapper>
|
||||
<AppHeader header={<ProjectIssueDetailsHeader workspaceSlug={params.workspaceSlug} workItem={params.workItem} />} />
|
||||
<ContentWrapper className="overflow-hidden">
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import React, { useEffect } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
import { useTheme } from "next-themes";
|
||||
import useSWR from "swr";
|
||||
// plane imports
|
||||
@@ -21,13 +21,13 @@ import { useProject } from "@/hooks/store/use-project";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import { useWorkItemProperties } from "@/plane-web/hooks/use-issue-properties";
|
||||
import { ProjectAuthWrapper } from "@/plane-web/layouts/project-wrapper";
|
||||
import emptyIssueDark from "@/public/empty-state/search/issues-dark.webp";
|
||||
import emptyIssueLight from "@/public/empty-state/search/issues-light.webp";
|
||||
import emptyIssueDark from "@/app/assets/empty-state/search/issues-dark.webp";
|
||||
import emptyIssueLight from "@/app/assets/empty-state/search/issues-light.webp";
|
||||
|
||||
const IssueDetailsPage = observer(() => {
|
||||
function IssueDetailsPage({ params }: Route.ComponentProps) {
|
||||
const { workspaceSlug, workItem } = params;
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
const { workspaceSlug, workItem } = useParams();
|
||||
// hooks
|
||||
const { resolvedTheme } = useTheme();
|
||||
// store hooks
|
||||
@@ -39,15 +39,12 @@ const IssueDetailsPage = observer(() => {
|
||||
const { getProjectById } = useProject();
|
||||
const { toggleIssueDetailSidebar, issueDetailSidebarCollapsed } = useAppTheme();
|
||||
|
||||
const projectIdentifier = workItem?.toString().split("-")[0];
|
||||
const sequence_id = workItem?.toString().split("-")[1];
|
||||
const [projectIdentifier, sequence_id] = workItem.split("-");
|
||||
|
||||
// fetching issue details
|
||||
const { data, isLoading, error } = useSWR(
|
||||
workspaceSlug && workItem ? `ISSUE_DETAIL_${workspaceSlug}_${projectIdentifier}_${sequence_id}` : null,
|
||||
workspaceSlug && workItem
|
||||
? () => fetchIssueWithIdentifier(workspaceSlug.toString(), projectIdentifier, sequence_id)
|
||||
: null
|
||||
`ISSUE_DETAIL_${workspaceSlug}_${projectIdentifier}_${sequence_id}`,
|
||||
() => fetchIssueWithIdentifier(workspaceSlug.toString(), projectIdentifier, sequence_id)
|
||||
);
|
||||
const issueId = data?.id;
|
||||
const projectId = data?.project_id;
|
||||
@@ -59,7 +56,7 @@ const IssueDetailsPage = observer(() => {
|
||||
|
||||
useWorkItemProperties(
|
||||
projectId,
|
||||
workspaceSlug.toString(),
|
||||
workspaceSlug,
|
||||
issueId,
|
||||
issue?.is_epic ? EIssueServiceType.EPICS : EIssueServiceType.ISSUES
|
||||
);
|
||||
@@ -116,11 +113,11 @@ const IssueDetailsPage = observer(() => {
|
||||
workspaceSlug &&
|
||||
projectId &&
|
||||
issueId && (
|
||||
<ProjectAuthWrapper workspaceSlug={workspaceSlug?.toString()} projectId={projectId?.toString()}>
|
||||
<ProjectAuthWrapper workspaceSlug={workspaceSlug} projectId={projectId}>
|
||||
<IssueDetailRoot
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
projectId={projectId.toString()}
|
||||
issueId={issueId.toString()}
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
issueId={issueId}
|
||||
is_archived={!!issue?.archived_at}
|
||||
/>
|
||||
</ProjectAuthWrapper>
|
||||
@@ -128,6 +125,6 @@ const IssueDetailsPage = observer(() => {
|
||||
)}
|
||||
</>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default IssueDetailsPage;
|
||||
export default observer(IssueDetailsPage);
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
"use client";
|
||||
|
||||
// components
|
||||
import { Outlet } from "react-router";
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
// local imports
|
||||
import { WorkspaceDraftHeader } from "./header";
|
||||
|
||||
export default function WorkspaceDraftLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function WorkspaceDraftLayout() {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<WorkspaceDraftHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,27 +1,18 @@
|
||||
"use client";
|
||||
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
// components
|
||||
import { PageHead } from "@/components/core/page-title";
|
||||
import { WorkspaceDraftIssuesRoot } from "@/components/issues/workspace-draft";
|
||||
|
||||
const WorkspaceDraftPage = () => {
|
||||
// router
|
||||
const { workspaceSlug: routeWorkspaceSlug } = useParams();
|
||||
const pageTitle = "Workspace Draft";
|
||||
export default function WorkspaceDraftPage({ params }: Route.ComponentProps) {
|
||||
const { workspaceSlug } = params;
|
||||
|
||||
// derived values
|
||||
const workspaceSlug = (routeWorkspaceSlug as string) || undefined;
|
||||
|
||||
if (!workspaceSlug) return null;
|
||||
return (
|
||||
<>
|
||||
<PageHead title={pageTitle} />
|
||||
<PageHead title="Workspace Draft" />
|
||||
<div className="relative h-full w-full overflow-hidden overflow-y-auto">
|
||||
<WorkspaceDraftIssuesRoot workspaceSlug={workspaceSlug} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default WorkspaceDraftPage;
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import React, { useMemo, useRef } from "react";
|
||||
import { useMemo, useRef } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
// plane imports
|
||||
import { WORKSPACE_SIDEBAR_DYNAMIC_NAVIGATION_ITEMS_LINKS } from "@plane/constants";
|
||||
import type { EUserWorkspaceRoles } from "@plane/types";
|
||||
@@ -13,17 +12,19 @@ import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||
import { ExtendedSidebarItem } from "@/plane-web/components/workspace/sidebar/extended-sidebar-item";
|
||||
import { ExtendedSidebarWrapper } from "./extended-sidebar-wrapper";
|
||||
|
||||
export const ExtendedAppSidebar = observer(() => {
|
||||
type ExtendedAppSidebarProps = {
|
||||
workspaceSlug: string;
|
||||
};
|
||||
|
||||
export const ExtendedAppSidebar = observer(({ workspaceSlug }: ExtendedAppSidebarProps) => {
|
||||
// refs
|
||||
const extendedSidebarRef = useRef<HTMLDivElement | null>(null);
|
||||
// routers
|
||||
const { workspaceSlug } = useParams();
|
||||
// store hooks
|
||||
const { isExtendedSidebarOpened, toggleExtendedSidebar } = useAppTheme();
|
||||
const { updateSidebarPreference, getNavigationPreferences } = useWorkspace();
|
||||
|
||||
// derived values
|
||||
const currentWorkspaceNavigationPreferences = getNavigationPreferences(workspaceSlug.toString());
|
||||
const currentWorkspaceNavigationPreferences = getNavigationPreferences(workspaceSlug);
|
||||
|
||||
const sortedNavigationItems = useMemo(
|
||||
() =>
|
||||
@@ -107,6 +108,7 @@ export const ExtendedAppSidebar = observer(() => {
|
||||
{sortedNavigationItems.map((item, index) => (
|
||||
<ExtendedSidebarItem
|
||||
key={item.key}
|
||||
workspaceSlug={workspaceSlug}
|
||||
item={item}
|
||||
isLastChild={index === sortedNavigationItems.length - 1}
|
||||
handleOnNavigationItemDrop={handleOnNavigationItemDrop}
|
||||
|
||||
@@ -1,22 +1,25 @@
|
||||
"use client";
|
||||
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "../+types/layout";
|
||||
import { CommandPalette } from "@/components/command-palette";
|
||||
import { AuthenticationWrapper } from "@/lib/wrappers/authentication-wrapper";
|
||||
// plane web components
|
||||
import { WorkspaceAuthWrapper } from "@/plane-web/layouts/workspace-wrapper";
|
||||
import { ProjectAppSidebar } from "./_sidebar";
|
||||
|
||||
export default function WorkspaceLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function WorkspaceLayout({ params }: Route.ComponentProps) {
|
||||
const { workspaceSlug } = params;
|
||||
|
||||
return (
|
||||
<AuthenticationWrapper>
|
||||
<CommandPalette />
|
||||
<CommandPalette workspaceSlug={workspaceSlug} />
|
||||
<WorkspaceAuthWrapper>
|
||||
<div className="relative flex flex-col h-full w-full overflow-hidden rounded-lg border border-custom-border-200">
|
||||
<div id="full-screen-portal" className="inset-0 absolute w-full" />
|
||||
<div className="relative flex size-full overflow-hidden">
|
||||
<ProjectAppSidebar />
|
||||
<ProjectAppSidebar workspaceSlug={workspaceSlug} />
|
||||
<main className="relative flex h-full w-full flex-col overflow-hidden bg-custom-background-100">
|
||||
{children}
|
||||
<Outlet />
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
"use client";
|
||||
|
||||
// components
|
||||
import { Outlet } from "react-router";
|
||||
import { NotificationsSidebarRoot } from "@/components/workspace-notifications/sidebar";
|
||||
|
||||
export default function ProjectInboxIssuesLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function ProjectInboxIssuesLayout() {
|
||||
return (
|
||||
<div className="relative w-full h-full overflow-hidden flex items-center">
|
||||
<NotificationsSidebarRoot />
|
||||
<div className="w-full h-full overflow-hidden overflow-y-auto">{children}</div>
|
||||
<div className="w-full h-full overflow-hidden overflow-y-auto">
|
||||
<Outlet />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
// plane imports
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
// components
|
||||
@@ -10,8 +10,8 @@ import { NotificationsRoot } from "@/components/workspace-notifications";
|
||||
// hooks
|
||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||
|
||||
const WorkspaceDashboardPage = observer(() => {
|
||||
const { workspaceSlug } = useParams();
|
||||
function WorkspaceDashboardPage({ params }: Route.ComponentProps) {
|
||||
const { workspaceSlug } = params;
|
||||
// plane hooks
|
||||
const { t } = useTranslation();
|
||||
// hooks
|
||||
@@ -24,9 +24,9 @@ const WorkspaceDashboardPage = observer(() => {
|
||||
return (
|
||||
<>
|
||||
<PageHead title={pageTitle} />
|
||||
<NotificationsRoot workspaceSlug={workspaceSlug?.toString()} />
|
||||
<NotificationsRoot workspaceSlug={workspaceSlug} />
|
||||
</>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export default WorkspaceDashboardPage;
|
||||
export default observer(WorkspaceDashboardPage);
|
||||
|
||||
+10
-6
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
// components
|
||||
import { PageHead } from "@/components/core/page-title";
|
||||
import { ProfileIssuesPage } from "@/components/profile/profile-issues";
|
||||
@@ -12,10 +12,16 @@ const ProfilePageHeader = {
|
||||
subscribed: "Profile - Subscribed",
|
||||
};
|
||||
|
||||
const ProfileIssuesTypePage = () => {
|
||||
const { profileViewId } = useParams() as { profileViewId: "assigned" | "subscribed" | "created" | undefined };
|
||||
function isValidProfileViewId(viewId: string): viewId is keyof typeof ProfilePageHeader {
|
||||
return viewId in ProfilePageHeader;
|
||||
}
|
||||
|
||||
if (!profileViewId) return null;
|
||||
export default function ProfileIssuesTypePage({ params }: Route.ComponentProps) {
|
||||
const { profileViewId } = params;
|
||||
|
||||
if (!isValidProfileViewId(profileViewId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const header = ProfilePageHeader[profileViewId];
|
||||
|
||||
@@ -26,5 +32,3 @@ const ProfileIssuesTypePage = () => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProfileIssuesTypePage;
|
||||
|
||||
@@ -15,7 +15,7 @@ import { useUserPermissions } from "@/hooks/store/user";
|
||||
|
||||
const PER_PAGE = 100;
|
||||
|
||||
const ProfileActivityPage = observer(() => {
|
||||
function ProfileActivityPage() {
|
||||
// states
|
||||
const [pageCount, setPageCount] = useState(1);
|
||||
const [totalPages, setTotalPages] = useState(0);
|
||||
@@ -69,6 +69,6 @@ const ProfileActivityPage = observer(() => {
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default ProfileActivityPage;
|
||||
export default observer(ProfileActivityPage);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams, usePathname } from "next/navigation";
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "./+types/layout";
|
||||
import { usePathname } from "next/navigation";
|
||||
import useSWR from "swr";
|
||||
// components
|
||||
import { PROFILE_VIEWER_TAB, PROFILE_ADMINS_TAB, EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||
@@ -22,19 +24,11 @@ import { ProfileNavbar } from "./navbar";
|
||||
|
||||
const userService = new UserService();
|
||||
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
const UseProfileLayout: React.FC<Props> = observer((props) => {
|
||||
const { children } = props;
|
||||
// router
|
||||
const { workspaceSlug, userId } = useParams();
|
||||
function UseProfileLayout({ params }: Route.ComponentProps) {
|
||||
const { workspaceSlug, userId } = params;
|
||||
const pathname = usePathname();
|
||||
// store hooks
|
||||
const { allowPermissions } = useUserPermissions();
|
||||
const { t } = useTranslation();
|
||||
// derived values
|
||||
const isAuthorized = allowPermissions(
|
||||
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
|
||||
EUserPermissionsLevel.WORKSPACE
|
||||
@@ -43,13 +37,9 @@ const UseProfileLayout: React.FC<Props> = observer((props) => {
|
||||
const windowSize = useSize();
|
||||
const isSmallerScreen = windowSize[0] >= 768;
|
||||
|
||||
const { data: userProjectsData } = useSWR(
|
||||
workspaceSlug && userId ? USER_PROFILE_PROJECT_SEGREGATION(workspaceSlug.toString(), userId.toString()) : null,
|
||||
workspaceSlug && userId
|
||||
? () => userService.getUserProfileProjectsSegregation(workspaceSlug.toString(), userId.toString())
|
||||
: null
|
||||
const { data: userProjectsData } = useSWR(USER_PROFILE_PROJECT_SEGREGATION(workspaceSlug, userId), () =>
|
||||
userService.getUserProfileProjectsSegregation(workspaceSlug, userId)
|
||||
);
|
||||
// derived values
|
||||
const isAuthorizedPath =
|
||||
pathname.includes("assigned") || pathname.includes("created") || pathname.includes("subscribed");
|
||||
const isIssuesTab = pathname.includes("assigned") || pathname.includes("created") || pathname.includes("subscribed");
|
||||
@@ -78,7 +68,9 @@ const UseProfileLayout: React.FC<Props> = observer((props) => {
|
||||
<div className="flex w-full flex-col md:h-full md:overflow-hidden">
|
||||
<ProfileNavbar isAuthorized={!!isAuthorized} />
|
||||
{isAuthorized || !isAuthorizedPath ? (
|
||||
<div className={`w-full overflow-hidden h-full`}>{children}</div>
|
||||
<div className={`w-full overflow-hidden h-full`}>
|
||||
<Outlet />
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid h-full w-full place-items-center text-custom-text-200">
|
||||
{t("you_do_not_have_the_permission_to_access_this_page")}
|
||||
@@ -93,6 +85,7 @@ const UseProfileLayout: React.FC<Props> = observer((props) => {
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default UseProfileLayout;
|
||||
|
||||
export default observer(UseProfileLayout);
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
import useSWR from "swr";
|
||||
// plane imports
|
||||
import { GROUP_CHOICES } from "@plane/constants";
|
||||
@@ -20,13 +20,13 @@ import { USER_PROFILE_DATA } from "@/constants/fetch-keys";
|
||||
import { UserService } from "@/services/user.service";
|
||||
const userService = new UserService();
|
||||
|
||||
export default function ProfileOverviewPage() {
|
||||
const { workspaceSlug, userId } = useParams();
|
||||
export default function ProfileOverviewPage({ params }: Route.ComponentProps) {
|
||||
const { workspaceSlug, userId } = params;
|
||||
|
||||
const { t } = useTranslation();
|
||||
const { data: userProfile } = useSWR(
|
||||
workspaceSlug && userId ? USER_PROFILE_DATA(workspaceSlug.toString(), userId.toString()) : null,
|
||||
workspaceSlug && userId ? () => userService.getUserProfileData(workspaceSlug.toString(), userId.toString()) : null
|
||||
USER_PROFILE_DATA(workspaceSlug, userId),
|
||||
() => userService.getUserProfileData(workspaceSlug, userId)
|
||||
);
|
||||
|
||||
const stateDistribution: IUserStateDistribution[] = Object.keys(GROUP_CHOICES).map((key) => {
|
||||
|
||||
+11
-5
@@ -1,15 +1,21 @@
|
||||
"use client";
|
||||
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "./+types/layout";
|
||||
// components
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
import { ProjectArchivesHeader } from "../header";
|
||||
|
||||
export default function ProjectArchiveCyclesLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function ProjectArchiveCyclesLayout({ params }: Route.ComponentProps) {
|
||||
const { workspaceSlug, projectId } = params;
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectArchivesHeader activeTab="cycles" />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<AppHeader
|
||||
header={<ProjectArchivesHeader activeTab="cycles" workspaceSlug={workspaceSlug} projectId={projectId} />}
|
||||
/>
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
+5
-5
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
// components
|
||||
import { PageHead } from "@/components/core/page-title";
|
||||
import { ArchivedCycleLayoutRoot } from "@/components/cycles/archived-cycles";
|
||||
@@ -9,9 +9,9 @@ import { ArchivedCyclesHeader } from "@/components/cycles/archived-cycles/header
|
||||
// hooks
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
|
||||
const ProjectArchivedCyclesPage = observer(() => {
|
||||
function ProjectArchivedCyclesPage({ params }: Route.ComponentProps) {
|
||||
// router
|
||||
const { projectId } = useParams();
|
||||
const { projectId } = params;
|
||||
// store hooks
|
||||
const { getProjectById } = useProject();
|
||||
// derived values
|
||||
@@ -27,6 +27,6 @@ const ProjectArchivedCyclesPage = observer(() => {
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default ProjectArchivedCyclesPage;
|
||||
export default observer(ProjectArchivedCyclesPage);
|
||||
|
||||
+6
-7
@@ -1,8 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import type { FC } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import { ArchiveIcon, CycleIcon, ModuleIcon, WorkItemsIcon } from "@plane/propel/icons";
|
||||
import { Tooltip } from "@plane/propel/tooltip";
|
||||
import { EIssuesStoreType } from "@plane/types";
|
||||
@@ -20,13 +18,15 @@ import { ProjectBreadcrumb } from "@/plane-web/components/breadcrumbs/project";
|
||||
|
||||
type TProps = {
|
||||
activeTab: "issues" | "cycles" | "modules";
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
const PROJECT_ARCHIVES_BREADCRUMB_LIST: {
|
||||
[key: string]: {
|
||||
label: string;
|
||||
href: string;
|
||||
icon: React.FC<React.SVGAttributes<SVGElement> & { className?: string }>;
|
||||
icon: React.FC<React.ComponentProps<"svg">>;
|
||||
};
|
||||
} = {
|
||||
issues: {
|
||||
@@ -46,11 +46,10 @@ const PROJECT_ARCHIVES_BREADCRUMB_LIST: {
|
||||
},
|
||||
};
|
||||
|
||||
export const ProjectArchivesHeader: FC<TProps> = observer((props: TProps) => {
|
||||
const { activeTab } = props;
|
||||
export const ProjectArchivesHeader: React.FC<TProps> = observer((props) => {
|
||||
const { activeTab, workspaceSlug, projectId } = props;
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
// store hooks
|
||||
const {
|
||||
issues: { getGroupIssueCount },
|
||||
@@ -69,7 +68,7 @@ export const ProjectArchivesHeader: FC<TProps> = observer((props: TProps) => {
|
||||
<Header.LeftItem>
|
||||
<div className="flex items-center gap-2.5">
|
||||
<Breadcrumbs onBack={router.back} isLoading={loader === "init-loader"}>
|
||||
<ProjectBreadcrumb workspaceSlug={workspaceSlug?.toString()} projectId={projectId?.toString()} />
|
||||
<ProjectBreadcrumb workspaceSlug={workspaceSlug} projectId={projectId} />
|
||||
<Breadcrumbs.Item
|
||||
component={
|
||||
<BreadcrumbLink
|
||||
|
||||
+14
-20
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
import useSWR from "swr";
|
||||
// ui
|
||||
import { Loader } from "@plane/ui";
|
||||
@@ -13,9 +13,9 @@ import { IssueDetailRoot } from "@/components/issues/issue-detail";
|
||||
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
|
||||
const ArchivedIssueDetailsPage = observer(() => {
|
||||
function ArchivedIssueDetailsPage({ params }: Route.ComponentProps) {
|
||||
// router
|
||||
const { workspaceSlug, projectId, archivedIssueId } = useParams();
|
||||
const { workspaceSlug, projectId, archivedIssueId } = params;
|
||||
// states
|
||||
// hooks
|
||||
const {
|
||||
@@ -26,16 +26,12 @@ const ArchivedIssueDetailsPage = observer(() => {
|
||||
const { getProjectById } = useProject();
|
||||
|
||||
const { isLoading } = useSWR(
|
||||
workspaceSlug && projectId && archivedIssueId
|
||||
? `ARCHIVED_ISSUE_DETAIL_${workspaceSlug}_${projectId}_${archivedIssueId}`
|
||||
: null,
|
||||
workspaceSlug && projectId && archivedIssueId
|
||||
? () => fetchIssue(workspaceSlug.toString(), projectId.toString(), archivedIssueId.toString())
|
||||
: null
|
||||
`ARCHIVED_ISSUE_DETAIL_${workspaceSlug}_${projectId}_${archivedIssueId}`,
|
||||
() => fetchIssue(workspaceSlug, projectId, archivedIssueId)
|
||||
);
|
||||
|
||||
// derived values
|
||||
const issue = archivedIssueId ? getIssueById(archivedIssueId.toString()) : undefined;
|
||||
const issue = getIssueById(archivedIssueId);
|
||||
const project = issue ? getProjectById(issue?.project_id ?? "") : undefined;
|
||||
const pageTitle = project && issue ? `${project?.identifier}-${issue?.sequence_id} ${issue?.name}` : undefined;
|
||||
|
||||
@@ -64,19 +60,17 @@ const ArchivedIssueDetailsPage = observer(() => {
|
||||
) : (
|
||||
<div className="flex h-full overflow-hidden">
|
||||
<div className="h-full w-full space-y-3 divide-y-2 divide-custom-border-200 overflow-y-auto">
|
||||
{workspaceSlug && projectId && archivedIssueId && (
|
||||
<IssueDetailRoot
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
projectId={projectId.toString()}
|
||||
issueId={archivedIssueId.toString()}
|
||||
is_archived
|
||||
/>
|
||||
)}
|
||||
<IssueDetailRoot
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
issueId={archivedIssueId}
|
||||
is_archived
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default ArchivedIssueDetailsPage;
|
||||
export default observer(ArchivedIssueDetailsPage);
|
||||
|
||||
+11
-12
@@ -1,7 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import useSWR from "swr";
|
||||
// ui
|
||||
import { ArchiveIcon, WorkItemsIcon } from "@plane/propel/icons";
|
||||
@@ -20,16 +19,20 @@ import { IssueService } from "@/services/issue";
|
||||
|
||||
const issueService = new IssueService();
|
||||
|
||||
export const ProjectArchivedIssueDetailsHeader = observer(() => {
|
||||
// router
|
||||
const { workspaceSlug, projectId, archivedIssueId } = useParams();
|
||||
type ProjectArchivedIssueDetailsHeaderProps = {
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
archivedIssueId: string;
|
||||
};
|
||||
|
||||
export const ProjectArchivedIssueDetailsHeader = observer(({ workspaceSlug, projectId, archivedIssueId }: ProjectArchivedIssueDetailsHeaderProps) => {
|
||||
// store hooks
|
||||
const { currentProjectDetails, loader } = useProject();
|
||||
|
||||
const { data: issueDetails } = useSWR(
|
||||
workspaceSlug && projectId && archivedIssueId ? ISSUE_DETAILS(archivedIssueId.toString()) : null,
|
||||
workspaceSlug && projectId && archivedIssueId ? ISSUE_DETAILS(archivedIssueId) : null,
|
||||
workspaceSlug && projectId && archivedIssueId
|
||||
? () => issueService.retrieve(workspaceSlug.toString(), projectId.toString(), archivedIssueId.toString())
|
||||
? () => issueService.retrieve(workspaceSlug, projectId, archivedIssueId)
|
||||
: null
|
||||
);
|
||||
|
||||
@@ -37,7 +40,7 @@ export const ProjectArchivedIssueDetailsHeader = observer(() => {
|
||||
<Header>
|
||||
<Header.LeftItem>
|
||||
<Breadcrumbs isLoading={loader === "init-loader"}>
|
||||
<ProjectBreadcrumb workspaceSlug={workspaceSlug?.toString()} projectId={projectId?.toString()} />
|
||||
<ProjectBreadcrumb workspaceSlug={workspaceSlug} projectId={projectId} />
|
||||
<Breadcrumbs.Item
|
||||
component={
|
||||
<BreadcrumbLink
|
||||
@@ -70,11 +73,7 @@ export const ProjectArchivedIssueDetailsHeader = observer(() => {
|
||||
</Breadcrumbs>
|
||||
</Header.LeftItem>
|
||||
<Header.RightItem>
|
||||
<IssueDetailQuickActions
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
projectId={projectId.toString()}
|
||||
issueId={archivedIssueId.toString()}
|
||||
/>
|
||||
<IssueDetailQuickActions workspaceSlug={workspaceSlug} projectId={projectId} issueId={archivedIssueId} />
|
||||
</Header.RightItem>
|
||||
</Header>
|
||||
);
|
||||
|
||||
+17
-3
@@ -1,15 +1,29 @@
|
||||
"use client";
|
||||
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "./+types/layout";
|
||||
// components
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
import { ProjectArchivedIssueDetailsHeader } from "./header";
|
||||
|
||||
export default function ProjectArchivedIssueDetailLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function ProjectArchivedIssueDetailLayout({ params }: Route.ComponentProps) {
|
||||
const { workspaceSlug, projectId, archivedIssueId } = params;
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectArchivedIssueDetailsHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<AppHeader
|
||||
header={
|
||||
<ProjectArchivedIssueDetailsHeader
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
archivedIssueId={archivedIssueId}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
+11
-3
@@ -1,15 +1,23 @@
|
||||
"use client";
|
||||
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "./+types/layout";
|
||||
// components
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
import { ProjectArchivesHeader } from "../../header";
|
||||
|
||||
export default function ProjectArchiveIssuesLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function ProjectArchiveIssuesLayout({ params }: Route.ComponentProps) {
|
||||
const { workspaceSlug, projectId } = params;
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectArchivesHeader activeTab="issues" />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<AppHeader
|
||||
header={<ProjectArchivesHeader activeTab="issues" workspaceSlug={workspaceSlug} projectId={projectId} />}
|
||||
/>
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
+6
-6
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
// components
|
||||
import { PageHead } from "@/components/core/page-title";
|
||||
import { ArchivedIssuesHeader } from "@/components/issues/archived-issues-header";
|
||||
@@ -9,13 +9,13 @@ import { ArchivedIssueLayoutRoot } from "@/components/issues/issue-layouts/roots
|
||||
// hooks
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
|
||||
const ProjectArchivedIssuesPage = observer(() => {
|
||||
function ProjectArchivedIssuesPage({ params }: Route.ComponentProps) {
|
||||
// router
|
||||
const { projectId } = useParams();
|
||||
const { projectId } = params;
|
||||
// store hooks
|
||||
const { getProjectById } = useProject();
|
||||
// derived values
|
||||
const project = projectId ? getProjectById(projectId.toString()) : undefined;
|
||||
const project = getProjectById(projectId);
|
||||
const pageTitle = project?.name && `${project?.name} - Archived work items`;
|
||||
|
||||
return (
|
||||
@@ -27,6 +27,6 @@ const ProjectArchivedIssuesPage = observer(() => {
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default ProjectArchivedIssuesPage;
|
||||
export default observer(ProjectArchivedIssuesPage);
|
||||
|
||||
+11
-3
@@ -1,15 +1,23 @@
|
||||
"use client";
|
||||
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "./+types/layout";
|
||||
// components
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
import { ProjectArchivesHeader } from "../header";
|
||||
|
||||
export default function ProjectArchiveModulesLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function ProjectArchiveModulesLayout({ params }: Route.ComponentProps) {
|
||||
const { workspaceSlug, projectId } = params;
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectArchivesHeader activeTab="modules" />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<AppHeader
|
||||
header={<ProjectArchivesHeader activeTab="modules" workspaceSlug={workspaceSlug} projectId={projectId} />}
|
||||
/>
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
+6
-6
@@ -1,20 +1,20 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
// components
|
||||
import { PageHead } from "@/components/core/page-title";
|
||||
import { ArchivedModuleLayoutRoot, ArchivedModulesHeader } from "@/components/modules";
|
||||
// hooks
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
|
||||
const ProjectArchivedModulesPage = observer(() => {
|
||||
function ProjectArchivedModulesPage({ params }: Route.ComponentProps) {
|
||||
// router
|
||||
const { projectId } = useParams();
|
||||
const { projectId } = params;
|
||||
// store hooks
|
||||
const { getProjectById } = useProject();
|
||||
// derived values
|
||||
const project = projectId ? getProjectById(projectId.toString()) : undefined;
|
||||
const project = getProjectById(projectId);
|
||||
const pageTitle = project?.name && `${project?.name} - Archived modules`;
|
||||
|
||||
return (
|
||||
@@ -26,6 +26,6 @@ const ProjectArchivedModulesPage = observer(() => {
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default ProjectArchivedModulesPage;
|
||||
export default observer(ProjectArchivedModulesPage);
|
||||
|
||||
+14
-14
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
// plane imports
|
||||
import { cn } from "@plane/utils";
|
||||
// components
|
||||
@@ -16,12 +16,12 @@ import { useProject } from "@/hooks/store/use-project";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import useLocalStorage from "@/hooks/use-local-storage";
|
||||
// assets
|
||||
import emptyCycle from "@/public/empty-state/cycle.svg";
|
||||
import emptyCycle from "@/app/assets/empty-state/cycle.svg";
|
||||
|
||||
const CycleDetailPage = observer(() => {
|
||||
function CycleDetailPage({ params }: Route.ComponentProps) {
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
const { workspaceSlug, projectId, cycleId } = useParams();
|
||||
const { workspaceSlug, projectId, cycleId } = params;
|
||||
// store hooks
|
||||
const { getCycleById, loader } = useCycle();
|
||||
const { getProjectById } = useProject();
|
||||
@@ -30,14 +30,14 @@ const CycleDetailPage = observer(() => {
|
||||
const { setValue, storedValue } = useLocalStorage("cycle_sidebar_collapsed", false);
|
||||
|
||||
useCyclesDetails({
|
||||
workspaceSlug: workspaceSlug?.toString(),
|
||||
projectId: projectId.toString(),
|
||||
cycleId: cycleId.toString(),
|
||||
workspaceSlug,
|
||||
projectId,
|
||||
cycleId,
|
||||
});
|
||||
// derived values
|
||||
const isSidebarCollapsed = storedValue ? (storedValue === true ? true : false) : false;
|
||||
const cycle = cycleId ? getCycleById(cycleId.toString()) : undefined;
|
||||
const project = projectId ? getProjectById(projectId.toString()) : undefined;
|
||||
const cycle = getCycleById(cycleId);
|
||||
const project = getProjectById(projectId);
|
||||
const pageTitle = project?.name && cycle?.name ? `${project?.name} - ${cycle?.name}` : undefined;
|
||||
|
||||
/**
|
||||
@@ -78,9 +78,9 @@ const CycleDetailPage = observer(() => {
|
||||
>
|
||||
<CycleDetailsSidebar
|
||||
handleClose={toggleSidebar}
|
||||
cycleId={cycleId.toString()}
|
||||
projectId={projectId.toString()}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
cycleId={cycleId}
|
||||
projectId={projectId}
|
||||
workspaceSlug={workspaceSlug}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -89,6 +89,6 @@ const CycleDetailPage = observer(() => {
|
||||
)}
|
||||
</>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default CycleDetailPage;
|
||||
export default observer(CycleDetailPage);
|
||||
|
||||
+5
-2
@@ -1,16 +1,19 @@
|
||||
"use client";
|
||||
|
||||
import { Outlet } from "react-router";
|
||||
// components
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
import { CycleIssuesHeader } from "./header";
|
||||
import { CycleIssuesMobileHeader } from "./mobile-header";
|
||||
|
||||
export default function ProjectCycleIssuesLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function ProjectCycleIssuesLayout() {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<CycleIssuesHeader />} mobileHeader={<CycleIssuesMobileHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
+6
-5
@@ -2,7 +2,6 @@
|
||||
|
||||
import type { FC } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
// ui
|
||||
import { EProjectFeatureKey, EUserPermissions, EUserPermissionsLevel, CYCLE_TRACKER_ELEMENTS } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
@@ -17,12 +16,14 @@ import { useUserPermissions } from "@/hooks/store/user";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
// plane web
|
||||
import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs/common";
|
||||
// constants
|
||||
|
||||
export const CyclesListHeader: FC = observer(() => {
|
||||
type Props = {
|
||||
workspaceSlug: string;
|
||||
};
|
||||
|
||||
export const CyclesListHeader: FC<Props> = observer(({ workspaceSlug }) => {
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
const { workspaceSlug } = useParams();
|
||||
|
||||
// store hooks
|
||||
const { toggleCreateCycleModal } = useCommandPalette();
|
||||
@@ -40,7 +41,7 @@ export const CyclesListHeader: FC = observer(() => {
|
||||
<Header.LeftItem>
|
||||
<Breadcrumbs onBack={router.back} isLoading={loader === "init-loader"}>
|
||||
<CommonProjectBreadcrumbs
|
||||
workspaceSlug={workspaceSlug?.toString()}
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={currentProjectDetails?.id ?? ""}
|
||||
featureKey={EProjectFeatureKey.CYCLES}
|
||||
isLast
|
||||
|
||||
+9
-5
@@ -1,16 +1,20 @@
|
||||
"use client";
|
||||
|
||||
// components
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "../../../+types/layout";
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
import { CyclesListHeader } from "./header";
|
||||
import { CyclesListMobileHeader } from "./mobile-header";
|
||||
|
||||
export default function ProjectCyclesListLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function ProjectCyclesListLayout({ params }: Route.ComponentProps) {
|
||||
const { workspaceSlug } = params;
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<CyclesListHeader />} mobileHeader={<CyclesListMobileHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<AppHeader header={<CyclesListHeader workspaceSlug={workspaceSlug} />} />
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
+3
-3
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
// plane imports
|
||||
import { EUserPermissionsLevel, CYCLE_TRACKER_ELEMENTS } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
@@ -26,7 +26,7 @@ import { useUserPermissions } from "@/hooks/store/user";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path";
|
||||
|
||||
const ProjectCyclesPage = observer(() => {
|
||||
const ProjectCyclesPage: React.FC<Route.ComponentProps> = observer(({ params }) => {
|
||||
// states
|
||||
const [createModal, setCreateModal] = useState(false);
|
||||
// store hooks
|
||||
@@ -34,7 +34,7 @@ const ProjectCyclesPage = observer(() => {
|
||||
const { getProjectById, currentProjectDetails } = useProject();
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
const { workspaceSlug, projectId } = params;
|
||||
// plane hooks
|
||||
const { t } = useTranslation();
|
||||
// cycle filters hook
|
||||
|
||||
+6
-3
@@ -1,15 +1,18 @@
|
||||
"use client";
|
||||
|
||||
// components
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "./+types/layout";
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
import { ProjectInboxHeader } from "@/plane-web/components/projects/settings/intake/header";
|
||||
|
||||
export default function ProjectInboxIssuesLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function ProjectInboxIssuesLayout() {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectInboxHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
+4
-3
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams, useSearchParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
// plane imports
|
||||
import { EUserPermissionsLevel } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
@@ -15,10 +16,10 @@ import { useUserPermissions } from "@/hooks/store/user";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path";
|
||||
|
||||
const ProjectInboxPage = observer(() => {
|
||||
const ProjectInboxPage: React.FC<Route.ComponentProps> = observer(({ params }) => {
|
||||
/// router
|
||||
const router = useAppRouter();
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
const { workspaceSlug, projectId } = params;
|
||||
const searchParams = useSearchParams();
|
||||
const navigationTab = searchParams.get("currentTab");
|
||||
const inboxIssueId = searchParams.get("inboxIssueId");
|
||||
|
||||
+5
-5
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
import { useTheme } from "next-themes";
|
||||
import useSWR from "swr";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
@@ -12,17 +12,17 @@ import { LogoSpinner } from "@/components/common/logo-spinner";
|
||||
// hooks
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
// assets
|
||||
import emptyIssueDark from "@/public/empty-state/search/issues-dark.webp";
|
||||
import emptyIssueLight from "@/public/empty-state/search/issues-light.webp";
|
||||
import emptyIssueDark from "@/app/assets/empty-state/search/issues-dark.webp";
|
||||
import emptyIssueLight from "@/app/assets/empty-state/search/issues-light.webp";
|
||||
// services
|
||||
import { IssueService } from "@/services/issue/issue.service";
|
||||
|
||||
const issueService = new IssueService();
|
||||
|
||||
const IssueDetailsPage = observer(() => {
|
||||
const IssueDetailsPage: React.FC<Route.ComponentProps> = observer(({ params }) => {
|
||||
const router = useAppRouter();
|
||||
const { t } = useTranslation();
|
||||
const { workspaceSlug, projectId, issueId } = useParams();
|
||||
const { workspaceSlug, projectId, issueId } = params;
|
||||
const { resolvedTheme } = useTheme();
|
||||
|
||||
const { data, isLoading, error } = useSWR(
|
||||
|
||||
+6
-4
@@ -1,16 +1,18 @@
|
||||
"use client";
|
||||
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "../../../+types/layout";
|
||||
// components
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
import { ProjectIssuesHeader } from "./header";
|
||||
import { ProjectIssuesMobileHeader } from "./mobile-header";
|
||||
|
||||
export default function ProjectIssuesLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function ProjectIssuesLayout() {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectIssuesHeader />} mobileHeader={<ProjectIssuesMobileHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
+3
-3
@@ -2,7 +2,7 @@
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import Head from "next/head";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
// i18n
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
// components
|
||||
@@ -11,8 +11,8 @@ import { ProjectLayoutRoot } from "@/components/issues/issue-layouts/roots/proje
|
||||
// hooks
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
|
||||
const ProjectIssuesPage = observer(() => {
|
||||
const { projectId } = useParams();
|
||||
const ProjectIssuesPage: React.FC<Route.ComponentProps> = observer(({ params }) => {
|
||||
const { projectId } = params;
|
||||
// i18n
|
||||
const { t } = useTranslation();
|
||||
// store
|
||||
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
import useSWR from "swr";
|
||||
// components
|
||||
import { cn } from "@plane/utils";
|
||||
@@ -16,12 +16,12 @@ import { useProject } from "@/hooks/store/use-project";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import useLocalStorage from "@/hooks/use-local-storage";
|
||||
// assets
|
||||
import emptyModule from "@/public/empty-state/module.svg";
|
||||
import emptyModule from "@/app/assets/empty-state/module.svg";
|
||||
|
||||
const ModuleIssuesPage = observer(() => {
|
||||
const ModuleIssuesPage: React.FC<Route.ComponentProps> = observer(({ params }) => {
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
const { workspaceSlug, projectId, moduleId } = useParams();
|
||||
const { workspaceSlug, projectId, moduleId } = params;
|
||||
// store hooks
|
||||
const { fetchModuleDetails, getModuleById } = useModule();
|
||||
const { getProjectById } = useProject();
|
||||
|
||||
+15
-15
@@ -2,7 +2,6 @@
|
||||
|
||||
import { useCallback, useRef, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
// icons
|
||||
import { ChartNoAxesColumn, PanelRight, SlidersHorizontal } from "lucide-react";
|
||||
// plane imports
|
||||
@@ -45,15 +44,19 @@ import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||
// plane web
|
||||
import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs/common";
|
||||
|
||||
export const ModuleIssuesHeader: React.FC = observer(() => {
|
||||
type Props = {
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
moduleId: string;
|
||||
};
|
||||
|
||||
export const ModuleIssuesHeader: React.FC<Props> = observer(({ workspaceSlug, projectId, moduleId }) => {
|
||||
// refs
|
||||
const parentRef = useRef<HTMLDivElement>(null);
|
||||
// states
|
||||
const [analyticsModal, setAnalyticsModal] = useState(false);
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
const { workspaceSlug, projectId, moduleId: routerModuleId } = useParams();
|
||||
const moduleId = routerModuleId ? routerModuleId.toString() : undefined;
|
||||
// hooks
|
||||
const { isMobile } = usePlatformOS();
|
||||
// store hooks
|
||||
@@ -84,24 +87,21 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
|
||||
|
||||
const handleLayoutChange = useCallback(
|
||||
(layout: EIssueLayoutTypes) => {
|
||||
if (!projectId) return;
|
||||
updateFilters(projectId.toString(), EIssueFilterType.DISPLAY_FILTERS, { layout: layout });
|
||||
updateFilters(projectId, EIssueFilterType.DISPLAY_FILTERS, { layout: layout });
|
||||
},
|
||||
[projectId, updateFilters]
|
||||
);
|
||||
|
||||
const handleDisplayFilters = useCallback(
|
||||
(updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => {
|
||||
if (!projectId) return;
|
||||
updateFilters(projectId.toString(), EIssueFilterType.DISPLAY_FILTERS, updatedDisplayFilter);
|
||||
updateFilters(projectId, EIssueFilterType.DISPLAY_FILTERS, updatedDisplayFilter);
|
||||
},
|
||||
[projectId, updateFilters]
|
||||
);
|
||||
|
||||
const handleDisplayProperties = useCallback(
|
||||
(property: Partial<IIssueDisplayProperties>) => {
|
||||
if (!projectId) return;
|
||||
updateFilters(projectId.toString(), EIssueFilterType.DISPLAY_PROPERTIES, property);
|
||||
updateFilters(projectId, EIssueFilterType.DISPLAY_PROPERTIES, property);
|
||||
},
|
||||
[projectId, updateFilters]
|
||||
);
|
||||
@@ -131,14 +131,14 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
|
||||
<div className="flex items-center gap-2">
|
||||
<Breadcrumbs onBack={router.back} isLoading={loader === "init-loader"}>
|
||||
<CommonProjectBreadcrumbs
|
||||
workspaceSlug={workspaceSlug?.toString() ?? ""}
|
||||
projectId={projectId?.toString() ?? ""}
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
featureKey={EProjectFeatureKey.MODULES}
|
||||
/>
|
||||
<Breadcrumbs.Item
|
||||
component={
|
||||
<BreadcrumbNavigationSearchDropdown
|
||||
selectedItem={moduleId?.toString() ?? ""}
|
||||
selectedItem={moduleId}
|
||||
navigationItems={switcherOptions}
|
||||
onChange={(value: string) => {
|
||||
router.push(`/${workspaceSlug}/projects/${projectId}/modules/${value}`);
|
||||
@@ -252,8 +252,8 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
|
||||
<ModuleQuickActions
|
||||
parentRef={parentRef}
|
||||
moduleId={moduleId}
|
||||
projectId={projectId.toString()}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
projectId={projectId}
|
||||
workspaceSlug={workspaceSlug}
|
||||
customClassName="flex-shrink-0 flex items-center justify-center bg-custom-background-80/70 rounded size-[26px]"
|
||||
/>
|
||||
)}
|
||||
|
||||
+14
-5
@@ -1,16 +1,25 @@
|
||||
"use client";
|
||||
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "./+types/layout";
|
||||
// components
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
import { ModuleIssuesHeader } from "./header";
|
||||
import { ModuleIssuesMobileHeader } from "./mobile-header";
|
||||
|
||||
export default function ProjectModuleIssuesLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function ProjectModuleIssuesLayout({ params }: Route.ComponentProps) {
|
||||
const { workspaceSlug, projectId, moduleId } = params;
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ModuleIssuesHeader />} mobileHeader={<ModuleIssuesMobileHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<AppHeader
|
||||
header={<ModuleIssuesHeader workspaceSlug={workspaceSlug} projectId={projectId} moduleId={moduleId} />}
|
||||
mobileHeader={
|
||||
<ModuleIssuesMobileHeader workspaceSlug={workspaceSlug} projectId={projectId} moduleId={moduleId} />
|
||||
}
|
||||
/>
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
+8
-12
@@ -2,7 +2,6 @@
|
||||
|
||||
import { useCallback, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
// icons
|
||||
import { Calendar, ChevronDown, Kanban, List } from "lucide-react";
|
||||
// plane imports
|
||||
@@ -26,13 +25,13 @@ const SUPPORTED_LAYOUTS = [
|
||||
{ key: "calendar", i18n_title: "issue.layouts.calendar", icon: Calendar },
|
||||
];
|
||||
|
||||
export const ModuleIssuesMobileHeader = observer(() => {
|
||||
// router
|
||||
const { workspaceSlug, projectId, moduleId } = useParams() as {
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
moduleId: string;
|
||||
};
|
||||
type Props = {
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
moduleId: string;
|
||||
};
|
||||
|
||||
export const ModuleIssuesMobileHeader = observer(({ workspaceSlug, projectId, moduleId }: Props) => {
|
||||
// states
|
||||
const [analyticsModal, setAnalyticsModal] = useState(false);
|
||||
// plane hooks
|
||||
@@ -45,11 +44,10 @@ export const ModuleIssuesMobileHeader = observer(() => {
|
||||
} = useIssues(EIssuesStoreType.MODULE);
|
||||
// derived values
|
||||
const activeLayout = issueFilters?.displayFilters?.layout;
|
||||
const moduleDetails = moduleId ? getModuleById(moduleId.toString()) : undefined;
|
||||
const moduleDetails = getModuleById(moduleId);
|
||||
|
||||
const handleLayoutChange = useCallback(
|
||||
(layout: EIssueLayoutTypes) => {
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
updateFilters(workspaceSlug, projectId, EIssueFilterType.DISPLAY_FILTERS, { layout: layout }, moduleId);
|
||||
},
|
||||
[workspaceSlug, projectId, moduleId, updateFilters]
|
||||
@@ -57,7 +55,6 @@ export const ModuleIssuesMobileHeader = observer(() => {
|
||||
|
||||
const handleDisplayFilters = useCallback(
|
||||
(updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => {
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
updateFilters(workspaceSlug, projectId, EIssueFilterType.DISPLAY_FILTERS, updatedDisplayFilter, moduleId);
|
||||
},
|
||||
[workspaceSlug, projectId, moduleId, updateFilters]
|
||||
@@ -65,7 +62,6 @@ export const ModuleIssuesMobileHeader = observer(() => {
|
||||
|
||||
const handleDisplayProperties = useCallback(
|
||||
(property: Partial<IIssueDisplayProperties>) => {
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
updateFilters(workspaceSlug, projectId, EIssueFilterType.DISPLAY_PROPERTIES, property, moduleId);
|
||||
},
|
||||
[workspaceSlug, projectId, moduleId, updateFilters]
|
||||
|
||||
+8
-5
@@ -1,7 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
// plane imports
|
||||
import { EProjectFeatureKey, EUserPermissions, EUserPermissionsLevel, MODULE_TRACKER_ELEMENTS } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
@@ -19,10 +18,14 @@ import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs/common";
|
||||
// constants
|
||||
|
||||
export const ModulesListHeader: React.FC = observer(() => {
|
||||
type Props = {
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export const ModulesListHeader: React.FC<Props> = observer(({ workspaceSlug, projectId }) => {
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
const { workspaceSlug, projectId } = useParams() as { workspaceSlug: string; projectId: string };
|
||||
// store hooks
|
||||
const { toggleCreateModuleModal } = useCommandPalette();
|
||||
const { allowPermissions } = useUserPermissions();
|
||||
@@ -43,8 +46,8 @@ export const ModulesListHeader: React.FC = observer(() => {
|
||||
<div>
|
||||
<Breadcrumbs onBack={router.back} isLoading={loader === "init-loader"}>
|
||||
<CommonProjectBreadcrumbs
|
||||
workspaceSlug={workspaceSlug?.toString() ?? ""}
|
||||
projectId={projectId?.toString() ?? ""}
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
featureKey={EProjectFeatureKey.MODULES}
|
||||
isLast
|
||||
/>
|
||||
|
||||
+12
-5
@@ -1,16 +1,23 @@
|
||||
"use client";
|
||||
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "../../../+types/layout";
|
||||
// components
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
import { ModulesListHeader } from "./header";
|
||||
import { ModulesListMobileHeader } from "./mobile-header";
|
||||
|
||||
export default function ProjectModulesListLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function ProjectModulesListLayout({ params }: Route.ComponentProps) {
|
||||
const { workspaceSlug, projectId } = params;
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ModulesListHeader />} mobileHeader={<ModulesListMobileHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<AppHeader
|
||||
header={<ModulesListHeader workspaceSlug={workspaceSlug} projectId={projectId} />}
|
||||
mobileHeader={<ModulesListMobileHeader workspaceSlug={workspaceSlug} projectId={projectId} />}
|
||||
/>
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
+6
-1
@@ -9,7 +9,12 @@ import { ModuleLayoutIcon } from "@/components/modules";
|
||||
import { useModuleFilter } from "@/hooks/store/use-module-filter";
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
|
||||
export const ModulesListMobileHeader = observer(() => {
|
||||
type Props = {
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export const ModulesListMobileHeader = observer(({ workspaceSlug, projectId }: Props) => {
|
||||
const { currentProjectDetails } = useProject();
|
||||
const { updateDisplayFilters } = useModuleFilter();
|
||||
const { t } = useTranslation();
|
||||
|
||||
+3
-3
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useCallback } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
// types
|
||||
import { EUserPermissionsLevel } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
@@ -21,10 +21,10 @@ import { useUserPermissions } from "@/hooks/store/user";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path";
|
||||
|
||||
const ProjectModulesPage = observer(() => {
|
||||
const ProjectModulesPage: React.FC<Route.ComponentProps> = observer(({ params }) => {
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
const { workspaceSlug, projectId } = params;
|
||||
// plane hooks
|
||||
const { t } = useTranslation();
|
||||
// store
|
||||
|
||||
+3
-3
@@ -3,7 +3,7 @@
|
||||
import { useCallback, useEffect, useMemo } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import Link from "next/link";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
import useSWR from "swr";
|
||||
// plane types
|
||||
import { getButtonStyling } from "@plane/propel/button";
|
||||
@@ -35,10 +35,10 @@ const projectPageVersionService = new ProjectPageVersionService();
|
||||
|
||||
const storeType = EPageStoreType.PROJECT;
|
||||
|
||||
const PageDetailsPage = observer(() => {
|
||||
const PageDetailsPage: React.FC<Route.ComponentProps> = observer(({ params }) => {
|
||||
const { workspaceSlug, projectId, pageId } = params;
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
const { workspaceSlug, projectId, pageId } = useParams();
|
||||
// store hooks
|
||||
const { createPage, fetchPageDetails } = usePageStore(storeType);
|
||||
const page = usePage({
|
||||
|
||||
+12
-7
@@ -28,19 +28,24 @@ export interface IPagesHeaderProps {
|
||||
|
||||
const storeType = EPageStoreType.PROJECT;
|
||||
|
||||
export const PageDetailsHeader = observer(() => {
|
||||
type Props = {
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
pageId: string;
|
||||
};
|
||||
|
||||
export const PageDetailsHeader = observer(({ workspaceSlug, projectId, pageId }: Props) => {
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
const { workspaceSlug, pageId, projectId } = useParams();
|
||||
// store hooks
|
||||
const { loader } = useProject();
|
||||
const { getPageById, getCurrentProjectPageIds } = usePageStore(storeType);
|
||||
const page = usePage({
|
||||
pageId: pageId?.toString() ?? "",
|
||||
pageId: pageId,
|
||||
storeType,
|
||||
});
|
||||
// derived values
|
||||
const projectPageIds = getCurrentProjectPageIds(projectId?.toString());
|
||||
const projectPageIds = getCurrentProjectPageIds(projectId);
|
||||
|
||||
const switcherOptions = projectPageIds
|
||||
.map((id) => {
|
||||
@@ -67,15 +72,15 @@ export const PageDetailsHeader = observer(() => {
|
||||
<div>
|
||||
<Breadcrumbs isLoading={loader === "init-loader"}>
|
||||
<CommonProjectBreadcrumbs
|
||||
workspaceSlug={workspaceSlug?.toString()}
|
||||
projectId={projectId?.toString()}
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
featureKey={EProjectFeatureKey.PAGES}
|
||||
/>
|
||||
|
||||
<Breadcrumbs.Item
|
||||
component={
|
||||
<BreadcrumbNavigationSearchDropdown
|
||||
selectedItem={pageId?.toString() ?? ""}
|
||||
selectedItem={pageId}
|
||||
navigationItems={switcherOptions}
|
||||
onChange={(value: string) => {
|
||||
router.push(`/${workspaceSlug}/projects/${projectId}/pages/${value}`);
|
||||
|
||||
+10
-8
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "./+types/layout";
|
||||
// component
|
||||
import { useParams } from "next/navigation";
|
||||
// import { useParams } from "react-router";
|
||||
import useSWR from "swr";
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
@@ -10,18 +10,20 @@ import { EPageStoreType, usePageStore } from "@/plane-web/hooks/store";
|
||||
// local components
|
||||
import { PageDetailsHeader } from "./header";
|
||||
|
||||
export default function ProjectPageDetailsLayout({ children }: { children: React.ReactNode }) {
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
export default function ProjectPageDetailsLayout({ params }: Route.ComponentProps) {
|
||||
const { workspaceSlug, projectId, pageId } = params;
|
||||
const { fetchPagesList } = usePageStore(EPageStoreType.PROJECT);
|
||||
// fetching pages list
|
||||
useSWR(
|
||||
workspaceSlug && projectId ? `PROJECT_PAGES_${projectId}` : null,
|
||||
workspaceSlug && projectId ? () => fetchPagesList(workspaceSlug.toString(), projectId.toString()) : null
|
||||
workspaceSlug && projectId ? () => fetchPagesList(workspaceSlug, projectId) : null
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<PageDetailsHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<AppHeader header={<PageDetailsHeader workspaceSlug={workspaceSlug} projectId={projectId} pageId={pageId} />} />
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
+10
-6
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams, useRouter, useSearchParams } from "next/navigation";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
// constants
|
||||
import {
|
||||
EPageAccess,
|
||||
@@ -25,12 +25,16 @@ import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs/com
|
||||
// plane web hooks
|
||||
import { EPageStoreType, usePageStore } from "@/plane-web/hooks/store";
|
||||
|
||||
export const PagesListHeader = observer(() => {
|
||||
type Props = {
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export const PagesListHeader = observer(({ workspaceSlug, projectId }: Props) => {
|
||||
// states
|
||||
const [isCreatingPage, setIsCreatingPage] = useState(false);
|
||||
// router
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = useParams();
|
||||
const searchParams = useSearchParams();
|
||||
const pageType = searchParams.get("type");
|
||||
// store hooks
|
||||
@@ -53,7 +57,7 @@ export const PagesListHeader = observer(() => {
|
||||
state: "SUCCESS",
|
||||
},
|
||||
});
|
||||
const pageId = `/${workspaceSlug}/projects/${currentProjectDetails?.id}/pages/${res?.id}`;
|
||||
const pageId = `/${workspaceSlug}/projects/${projectId}/pages/${res?.id}`;
|
||||
router.push(pageId);
|
||||
})
|
||||
.catch((err) => {
|
||||
@@ -77,8 +81,8 @@ export const PagesListHeader = observer(() => {
|
||||
<Header.LeftItem>
|
||||
<Breadcrumbs isLoading={loader === "init-loader"}>
|
||||
<CommonProjectBreadcrumbs
|
||||
workspaceSlug={workspaceSlug?.toString() ?? ""}
|
||||
projectId={currentProjectDetails?.id?.toString() ?? ""}
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
featureKey={EProjectFeatureKey.PAGES}
|
||||
isLast
|
||||
/>
|
||||
|
||||
+9
-6
@@ -1,17 +1,20 @@
|
||||
"use client";
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "../../../+types/layout";
|
||||
// components
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
// local components
|
||||
import { PagesListHeader } from "./header";
|
||||
|
||||
export default function ProjectPagesListLayout({ children }: { children: ReactNode }) {
|
||||
export default function ProjectPagesListLayout({ params }: Route.ComponentProps) {
|
||||
const { workspaceSlug, projectId } = params;
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<PagesListHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<AppHeader header={<PagesListHeader workspaceSlug={workspaceSlug} projectId={projectId} />} />
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
+4
-3
@@ -1,7 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams, useSearchParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
// plane imports
|
||||
import { EUserPermissionsLevel } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
@@ -20,12 +21,12 @@ import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path";
|
||||
// plane web hooks
|
||||
import { EPageStoreType } from "@/plane-web/hooks/store";
|
||||
|
||||
const ProjectPagesPage = observer(() => {
|
||||
const ProjectPagesPage: React.FC<Route.ComponentProps> = observer(({ params }) => {
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const type = searchParams.get("type");
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
const { workspaceSlug, projectId } = params;
|
||||
// plane hooks
|
||||
const { t } = useTranslation();
|
||||
// store hooks
|
||||
|
||||
+16
-34
@@ -2,7 +2,6 @@
|
||||
|
||||
import { useCallback, useRef } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import { Lock } from "lucide-react";
|
||||
// plane constants
|
||||
import {
|
||||
@@ -37,13 +36,17 @@ import { useUserPermissions } from "@/hooks/store/user";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs/common";
|
||||
|
||||
export const ProjectViewIssuesHeader: React.FC = observer(() => {
|
||||
type Props = {
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
viewId: string;
|
||||
};
|
||||
|
||||
export const ProjectViewIssuesHeader: React.FC<Props> = observer(({ workspaceSlug, projectId, viewId }) => {
|
||||
// refs
|
||||
const parentRef = useRef(null);
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
const { workspaceSlug, projectId, viewId: routerViewId } = useParams();
|
||||
const viewId = routerViewId ? routerViewId.toString() : undefined;
|
||||
// store hooks
|
||||
const {
|
||||
issuesFilter: { issueFilters, updateFilters },
|
||||
@@ -58,47 +61,26 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
|
||||
|
||||
const handleLayoutChange = useCallback(
|
||||
(layout: EIssueLayoutTypes) => {
|
||||
if (!workspaceSlug || !projectId || !viewId) return;
|
||||
updateFilters(
|
||||
workspaceSlug.toString(),
|
||||
projectId.toString(),
|
||||
EIssueFilterType.DISPLAY_FILTERS,
|
||||
{ layout: layout },
|
||||
viewId.toString()
|
||||
);
|
||||
updateFilters(workspaceSlug, projectId, EIssueFilterType.DISPLAY_FILTERS, { layout: layout }, viewId);
|
||||
},
|
||||
[workspaceSlug, projectId, viewId, updateFilters]
|
||||
);
|
||||
|
||||
const handleDisplayFilters = useCallback(
|
||||
(updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => {
|
||||
if (!workspaceSlug || !projectId || !viewId) return;
|
||||
updateFilters(
|
||||
workspaceSlug.toString(),
|
||||
projectId.toString(),
|
||||
EIssueFilterType.DISPLAY_FILTERS,
|
||||
updatedDisplayFilter,
|
||||
viewId.toString()
|
||||
);
|
||||
updateFilters(workspaceSlug, projectId, EIssueFilterType.DISPLAY_FILTERS, updatedDisplayFilter, viewId);
|
||||
},
|
||||
[workspaceSlug, projectId, viewId, updateFilters]
|
||||
);
|
||||
|
||||
const handleDisplayProperties = useCallback(
|
||||
(property: Partial<IIssueDisplayProperties>) => {
|
||||
if (!workspaceSlug || !projectId || !viewId) return;
|
||||
updateFilters(
|
||||
workspaceSlug.toString(),
|
||||
projectId.toString(),
|
||||
EIssueFilterType.DISPLAY_PROPERTIES,
|
||||
property,
|
||||
viewId.toString()
|
||||
);
|
||||
updateFilters(workspaceSlug, projectId, EIssueFilterType.DISPLAY_PROPERTIES, property, viewId);
|
||||
},
|
||||
[workspaceSlug, projectId, viewId, updateFilters]
|
||||
);
|
||||
|
||||
const viewDetails = viewId ? getViewById(viewId.toString()) : null;
|
||||
const viewDetails = getViewById(viewId);
|
||||
|
||||
const canUserCreateIssue = allowPermissions(
|
||||
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
|
||||
@@ -124,15 +106,15 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
|
||||
<Header.LeftItem>
|
||||
<Breadcrumbs isLoading={loader === "init-loader"}>
|
||||
<CommonProjectBreadcrumbs
|
||||
workspaceSlug={workspaceSlug?.toString() ?? ""}
|
||||
projectId={projectId?.toString() ?? ""}
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
featureKey={EProjectFeatureKey.VIEWS}
|
||||
/>
|
||||
|
||||
<Breadcrumbs.Item
|
||||
component={
|
||||
<BreadcrumbNavigationSearchDropdown
|
||||
selectedItem={viewId?.toString() ?? ""}
|
||||
selectedItem={viewId}
|
||||
navigationItems={switcherOptions}
|
||||
onChange={(value: string) => {
|
||||
router.push(`/${workspaceSlug}/projects/${projectId}/views/${value}`);
|
||||
@@ -208,9 +190,9 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
|
||||
<ViewQuickActions
|
||||
parentRef={parentRef}
|
||||
customClassName="flex-shrink-0 flex items-center justify-center size-[26px] bg-custom-background-80/70 rounded"
|
||||
projectId={projectId.toString()}
|
||||
projectId={projectId}
|
||||
view={viewDetails}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
workspaceSlug={workspaceSlug}
|
||||
/>
|
||||
</div>
|
||||
</Header.RightItem>
|
||||
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
import useSWR from "swr";
|
||||
// components
|
||||
import { EmptyState } from "@/components/common/empty-state";
|
||||
@@ -12,12 +12,12 @@ import { useProject } from "@/hooks/store/use-project";
|
||||
import { useProjectView } from "@/hooks/store/use-project-view";
|
||||
// assets
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import emptyView from "@/public/empty-state/view.svg";
|
||||
import emptyView from "@/app/assets/empty-state/view.svg";
|
||||
|
||||
const ProjectViewIssuesPage = observer(() => {
|
||||
const ProjectViewIssuesPage: React.FC<Route.ComponentProps> = observer(({ params }) => {
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
const { workspaceSlug, projectId, viewId } = useParams();
|
||||
const { workspaceSlug, projectId, viewId } = params;
|
||||
// store hooks
|
||||
const { fetchViewDetails, getViewById } = useProjectView();
|
||||
const { getProjectById } = useProject();
|
||||
|
||||
+11
-5
@@ -1,15 +1,21 @@
|
||||
"use client";
|
||||
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "./+types/layout";
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
// local components
|
||||
import { ProjectViewIssuesHeader } from "./[viewId]/header";
|
||||
|
||||
export default function ProjectViewIssuesLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function ProjectViewIssuesLayout({ params }: Route.ComponentProps) {
|
||||
const { workspaceSlug, projectId, viewId } = params;
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectViewIssuesHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<AppHeader
|
||||
header={<ProjectViewIssuesHeader workspaceSlug={workspaceSlug} projectId={projectId} viewId={viewId} />}
|
||||
/>
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
+8
-5
@@ -1,7 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
// ui
|
||||
import { EProjectFeatureKey, PROJECT_VIEW_TRACKER_ELEMENTS } from "@plane/constants";
|
||||
import { Button } from "@plane/propel/button";
|
||||
@@ -14,8 +13,12 @@ import { useProject } from "@/hooks/store/use-project";
|
||||
// plane web
|
||||
import { CommonProjectBreadcrumbs } from "@/plane-web/components/breadcrumbs/common";
|
||||
|
||||
export const ProjectViewsHeader = observer(() => {
|
||||
const { workspaceSlug, projectId } = useParams() as { workspaceSlug: string; projectId: string };
|
||||
type Props = {
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export const ProjectViewsHeader = observer(({ workspaceSlug, projectId }: Props) => {
|
||||
// store hooks
|
||||
const { toggleCreateViewModal } = useCommandPalette();
|
||||
const { loader } = useProject();
|
||||
@@ -26,8 +29,8 @@ export const ProjectViewsHeader = observer(() => {
|
||||
<Header.LeftItem>
|
||||
<Breadcrumbs isLoading={loader === "init-loader"}>
|
||||
<CommonProjectBreadcrumbs
|
||||
workspaceSlug={workspaceSlug?.toString() ?? ""}
|
||||
projectId={projectId?.toString() ?? ""}
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
featureKey={EProjectFeatureKey.VIEWS}
|
||||
isLast
|
||||
/>
|
||||
|
||||
+12
-5
@@ -1,16 +1,23 @@
|
||||
"use client";
|
||||
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "../../../+types/layout";
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
// local components
|
||||
import { ProjectViewsHeader } from "./header";
|
||||
import { ViewMobileHeader } from "./mobile-header";
|
||||
|
||||
export default function ProjectViewsListLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function ProjectViewsListLayout({ params }: Route.ComponentProps) {
|
||||
const { workspaceSlug, projectId } = params;
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectViewsHeader />} mobileHeader={<ViewMobileHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<AppHeader
|
||||
header={<ProjectViewsHeader workspaceSlug={workspaceSlug} projectId={projectId} />}
|
||||
mobileHeader={<ViewMobileHeader workspaceSlug={workspaceSlug} projectId={projectId} />}
|
||||
/>
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
+6
-1
@@ -12,7 +12,12 @@ import { ViewOrderByDropdown } from "@/components/views/filters/order-by";
|
||||
import { useMember } from "@/hooks/store/use-member";
|
||||
import { useProjectView } from "@/hooks/store/use-project-view";
|
||||
|
||||
export const ViewMobileHeader = observer(() => {
|
||||
type Props = {
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export const ViewMobileHeader = observer(({ workspaceSlug, projectId }: Props) => {
|
||||
// store hooks
|
||||
const { filters, updateFilters } = useProjectView();
|
||||
const {
|
||||
|
||||
+3
-3
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useCallback } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
// components
|
||||
import { EUserPermissionsLevel } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
@@ -23,10 +23,10 @@ import { useUserPermissions } from "@/hooks/store/user";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path";
|
||||
|
||||
const ProjectViewsPage = observer(() => {
|
||||
const ProjectViewsPage: React.FC<Route.ComponentProps> = observer(({ params }) => {
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
const { workspaceSlug, projectId } = params;
|
||||
// plane hooks
|
||||
const { t } = useTranslation();
|
||||
// store
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
"use client";
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
// components
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "../+types/layout";
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
// local components
|
||||
import { ProjectsListHeader } from "@/plane-web/components/projects/header";
|
||||
import { ProjectsListMobileHeader } from "@/plane-web/components/projects/mobile-header";
|
||||
export default function ProjectListLayout({ children }: { children: ReactNode }) {
|
||||
|
||||
export default function ProjectListLayout() {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectsListHeader />} mobileHeader={<ProjectsListMobileHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
import { useParams } from "next/navigation";
|
||||
// plane web layouts
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "./+types/layout";
|
||||
import { ProjectAuthWrapper } from "@/plane-web/layouts/project-wrapper";
|
||||
|
||||
const ProjectDetailLayout = ({ children }: { children: ReactNode }) => {
|
||||
// router
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
const ProjectDetailLayout: React.FC<Route.ComponentProps> = ({ params }) => {
|
||||
const { workspaceSlug, projectId } = params;
|
||||
return (
|
||||
<ProjectAuthWrapper workspaceSlug={workspaceSlug?.toString()} projectId={projectId?.toString()}>
|
||||
{children}
|
||||
<ProjectAuthWrapper workspaceSlug={workspaceSlug!} projectId={projectId!}>
|
||||
<Outlet />
|
||||
</ProjectAuthWrapper>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
"use client";
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
// components
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "./+types/layout";
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
// local components
|
||||
import { ProjectsListHeader } from "@/plane-web/components/projects/header";
|
||||
import { ProjectsListMobileHeader } from "@/plane-web/components/projects/mobile-header";
|
||||
export default function ProjectListLayout({ children }: { children: ReactNode }) {
|
||||
|
||||
export default function ProjectListLayout() {
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<ProjectsListHeader />} mobileHeader={<ProjectsListMobileHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ import { useTranslation } from "@plane/i18n";
|
||||
// helpers
|
||||
import { captureElementAndEvent } from "@/helpers/event-tracker.helper";
|
||||
// public imports
|
||||
import githubBlackImage from "@/public/logos/github-black.png";
|
||||
import githubWhiteImage from "@/public/logos/github-white.png";
|
||||
import githubBlackImage from "@/app/assets/logos/github-black.png";
|
||||
import githubWhiteImage from "@/app/assets/logos/github-white.png";
|
||||
|
||||
export const StarUsOnGitHubLink = () => {
|
||||
// plane hooks
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
// plane imports
|
||||
import { Button } from "@plane/propel/button";
|
||||
import { RecentStickyIcon } from "@plane/propel/icons";
|
||||
@@ -13,11 +12,14 @@ import { useStickyOperations } from "@/components/stickies/sticky/use-operations
|
||||
// hooks
|
||||
import { useSticky } from "@/hooks/use-stickies";
|
||||
|
||||
export const WorkspaceStickyHeader = observer(() => {
|
||||
const { workspaceSlug } = useParams();
|
||||
type Props = {
|
||||
workspaceSlug: string;
|
||||
};
|
||||
|
||||
export const WorkspaceStickyHeader = observer(({ workspaceSlug }: Props) => {
|
||||
// hooks
|
||||
const { creatingSticky, toggleShowNewSticky } = useSticky();
|
||||
const { stickyOperations } = useStickyOperations({ workspaceSlug: workspaceSlug?.toString() });
|
||||
const { stickyOperations } = useStickyOperations({ workspaceSlug });
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
"use client";
|
||||
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "../+types/layout";
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
import { WorkspaceStickyHeader } from "./header";
|
||||
|
||||
export default function WorkspaceStickiesLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function WorkspaceStickiesLayout({ params }: Route.ComponentProps) {
|
||||
const { workspaceSlug } = params;
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<WorkspaceStickyHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<AppHeader header={<WorkspaceStickyHeader workspaceSlug={workspaceSlug} />} />
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
+3
-3
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
// plane imports
|
||||
import { DEFAULT_GLOBAL_VIEWS_LIST } from "@plane/constants";
|
||||
// components
|
||||
@@ -11,9 +11,9 @@ import { AllIssueLayoutRoot } from "@/components/issues/issue-layouts/roots/all-
|
||||
// hooks
|
||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||
|
||||
const GlobalViewIssuesPage = observer(() => {
|
||||
const GlobalViewIssuesPage: React.FC<Route.ComponentProps> = observer(({ params }) => {
|
||||
// router
|
||||
const { globalViewId } = useParams();
|
||||
const { globalViewId } = params;
|
||||
// store hooks
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
// states
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
// plane imports
|
||||
import {
|
||||
EIssueFilterType,
|
||||
@@ -30,13 +29,16 @@ import { useIssues } from "@/hooks/store/use-issues";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import { GlobalViewLayoutSelection } from "@/plane-web/components/views/helper";
|
||||
|
||||
export const GlobalIssuesHeader = observer(() => {
|
||||
type Props = {
|
||||
workspaceSlug: string;
|
||||
globalViewId?: string;
|
||||
};
|
||||
|
||||
export const GlobalIssuesHeader = observer(({ workspaceSlug, globalViewId }: Props) => {
|
||||
// states
|
||||
const [createViewModal, setCreateViewModal] = useState(false);
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
const { workspaceSlug, globalViewId: routerGlobalViewId } = useParams();
|
||||
const globalViewId = routerGlobalViewId ? routerGlobalViewId.toString() : undefined;
|
||||
// store hooks
|
||||
const {
|
||||
issuesFilter: { filters, updateFilters },
|
||||
@@ -44,43 +46,31 @@ export const GlobalIssuesHeader = observer(() => {
|
||||
const { getViewDetailsById, currentWorkspaceViews } = useGlobalView();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const issueFilters = globalViewId ? filters[globalViewId.toString()] : undefined;
|
||||
const issueFilters = globalViewId ? filters[globalViewId] : undefined;
|
||||
|
||||
const activeLayout = issueFilters?.displayFilters?.layout;
|
||||
const viewDetails = globalViewId ? getViewDetailsById(globalViewId) : undefined;
|
||||
|
||||
const handleDisplayFilters = useCallback(
|
||||
(updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => {
|
||||
if (!workspaceSlug || !globalViewId) return;
|
||||
updateFilters(
|
||||
workspaceSlug.toString(),
|
||||
undefined,
|
||||
EIssueFilterType.DISPLAY_FILTERS,
|
||||
updatedDisplayFilter,
|
||||
globalViewId
|
||||
);
|
||||
if (!globalViewId) return;
|
||||
updateFilters(workspaceSlug, undefined, EIssueFilterType.DISPLAY_FILTERS, updatedDisplayFilter, globalViewId);
|
||||
},
|
||||
[workspaceSlug, updateFilters, globalViewId]
|
||||
);
|
||||
|
||||
const handleDisplayProperties = useCallback(
|
||||
(property: Partial<IIssueDisplayProperties>) => {
|
||||
if (!workspaceSlug || !globalViewId) return;
|
||||
updateFilters(workspaceSlug.toString(), undefined, EIssueFilterType.DISPLAY_PROPERTIES, property, globalViewId);
|
||||
if (!globalViewId) return;
|
||||
updateFilters(workspaceSlug, undefined, EIssueFilterType.DISPLAY_PROPERTIES, property, globalViewId);
|
||||
},
|
||||
[workspaceSlug, updateFilters, globalViewId]
|
||||
);
|
||||
|
||||
const handleLayoutChange = useCallback(
|
||||
(layout: EIssueLayoutTypes) => {
|
||||
if (!workspaceSlug || !globalViewId) return;
|
||||
updateFilters(
|
||||
workspaceSlug.toString(),
|
||||
undefined,
|
||||
EIssueFilterType.DISPLAY_FILTERS,
|
||||
{ layout: layout },
|
||||
globalViewId
|
||||
);
|
||||
if (!globalViewId) return;
|
||||
updateFilters(workspaceSlug, undefined, EIssueFilterType.DISPLAY_FILTERS, { layout: layout }, globalViewId);
|
||||
},
|
||||
[workspaceSlug, updateFilters, globalViewId]
|
||||
);
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
"use client";
|
||||
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "../+types/layout";
|
||||
import { AppHeader } from "@/components/core/app-header";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
import { GlobalIssuesHeader } from "./header";
|
||||
|
||||
export default function GlobalIssuesLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function GlobalIssuesLayout({ params }: Route.ComponentProps) {
|
||||
const { workspaceSlug, globalViewId } = params;
|
||||
|
||||
return (
|
||||
<>
|
||||
<AppHeader header={<GlobalIssuesHeader />} />
|
||||
<ContentWrapper>{children}</ContentWrapper>
|
||||
<AppHeader header={<GlobalIssuesHeader workspaceSlug={workspaceSlug} globalViewId={globalViewId} />} />
|
||||
<ContentWrapper>
|
||||
<Outlet />
|
||||
</ContentWrapper>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,23 +1,28 @@
|
||||
"use client";
|
||||
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "../+types/layout";
|
||||
import { CommandPalette } from "@/components/command-palette";
|
||||
import { ContentWrapper } from "@/components/core/content-wrapper";
|
||||
import { SettingsHeader } from "@/components/settings/header";
|
||||
import { AuthenticationWrapper } from "@/lib/wrappers/authentication-wrapper";
|
||||
import { WorkspaceAuthWrapper } from "@/plane-web/layouts/workspace-wrapper";
|
||||
|
||||
export default function SettingsLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function SettingsLayout({ params }: Route.ComponentProps) {
|
||||
const { workspaceSlug } = params;
|
||||
return (
|
||||
<AuthenticationWrapper>
|
||||
<WorkspaceAuthWrapper>
|
||||
<CommandPalette />
|
||||
<CommandPalette workspaceSlug={workspaceSlug} />
|
||||
<div className="relative flex h-full w-full overflow-hidden rounded-lg border border-custom-border-200">
|
||||
<main className="relative flex h-full w-full flex-col overflow-hidden bg-custom-background-100">
|
||||
{/* Header */}
|
||||
<SettingsHeader />
|
||||
{/* Content */}
|
||||
<ContentWrapper className="p-page-x md:flex w-full">
|
||||
<div className="w-full h-full overflow-hidden">{children}</div>
|
||||
<div className="w-full h-full overflow-hidden">
|
||||
<Outlet />
|
||||
</div>
|
||||
</ContentWrapper>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
import useSWR from "swr";
|
||||
// components
|
||||
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||
@@ -20,9 +20,9 @@ import { IntegrationService } from "@/services/integrations";
|
||||
|
||||
const integrationService = new IntegrationService();
|
||||
|
||||
const WorkspaceIntegrationsPage = observer(() => {
|
||||
const WorkspaceIntegrationsPage: React.FC<Route.ComponentProps> = observer(({ params }) => {
|
||||
// router
|
||||
const { workspaceSlug } = useParams();
|
||||
const { workspaceSlug } = params;
|
||||
// store hooks
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
const { allowPermissions } = useUserPermissions();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import type { FC, ReactNode } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import type { Route } from "./+types/layout";
|
||||
// constants
|
||||
import { WORKSPACE_SETTINGS_ACCESS } from "@plane/constants";
|
||||
import type { EUserWorkspaceRoles } from "@plane/types";
|
||||
@@ -15,19 +16,17 @@ import { useUserPermissions } from "@/hooks/store/user";
|
||||
// local components
|
||||
import { WorkspaceSettingsSidebar } from "./sidebar";
|
||||
|
||||
export interface IWorkspaceSettingLayout {
|
||||
children: ReactNode;
|
||||
}
|
||||
type Props = Route.ComponentProps & { children: ReactNode };
|
||||
|
||||
const WorkspaceSettingLayout: FC<IWorkspaceSettingLayout> = observer((props) => {
|
||||
const { children } = props;
|
||||
const WorkspaceSettingLayout: FC<Props> = observer(({ children, params }) => {
|
||||
const { workspaceSlug } = params;
|
||||
// store hooks
|
||||
const { workspaceUserInfo, getWorkspaceRoleByWorkspaceSlug } = useUserPermissions();
|
||||
// next hooks
|
||||
const pathname = usePathname();
|
||||
// derived values
|
||||
const { workspaceSlug, accessKey } = pathnameToAccessKey(pathname);
|
||||
const userWorkspaceRole = getWorkspaceRoleByWorkspaceSlug(workspaceSlug.toString());
|
||||
const { accessKey } = pathnameToAccessKey(pathname);
|
||||
const userWorkspaceRole = getWorkspaceRoleByWorkspaceSlug(workspaceSlug);
|
||||
|
||||
let isAuthorized: boolean | string = false;
|
||||
if (pathname && workspaceSlug && userWorkspaceRole) {
|
||||
@@ -37,7 +36,7 @@ const WorkspaceSettingLayout: FC<IWorkspaceSettingLayout> = observer((props) =>
|
||||
return (
|
||||
<>
|
||||
<SettingsMobileNav
|
||||
hamburgerContent={WorkspaceSettingsSidebar}
|
||||
hamburgerContent={(props) => <WorkspaceSettingsSidebar {...props} workspaceSlug={workspaceSlug} />}
|
||||
activePath={getWorkspaceActivePath(pathname) || ""}
|
||||
/>
|
||||
<div className="inset-y-0 flex flex-row w-full h-full">
|
||||
@@ -45,7 +44,7 @@ const WorkspaceSettingLayout: FC<IWorkspaceSettingLayout> = observer((props) =>
|
||||
<NotAuthorizedView section="settings" className="h-auto" />
|
||||
) : (
|
||||
<div className="relative flex h-full w-full">
|
||||
<div className="hidden md:block">{<WorkspaceSettingsSidebar />}</div>
|
||||
<div className="hidden md:block">{<WorkspaceSettingsSidebar workspaceSlug={workspaceSlug} />}</div>
|
||||
<div className="w-full h-full overflow-y-scroll md:pt-page-y">{children}</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
import { useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import { Search } from "lucide-react";
|
||||
import type { Route } from "./+types/page";
|
||||
// types
|
||||
import {
|
||||
EUserPermissions,
|
||||
@@ -33,12 +33,11 @@ import { useUserPermissions } from "@/hooks/store/user";
|
||||
import { BillingActionsButton } from "@/plane-web/components/workspace/billing/billing-actions-button";
|
||||
import { SendWorkspaceInvitationModal } from "@/plane-web/components/workspace/members/invite-modal";
|
||||
|
||||
const WorkspaceMembersSettingsPage = observer(() => {
|
||||
const WorkspaceMembersSettingsPage = observer(({ params }: Route.ComponentProps) => {
|
||||
// states
|
||||
const [inviteModal, setInviteModal] = useState(false);
|
||||
const [searchQuery, setSearchQuery] = useState<string>("");
|
||||
// router
|
||||
const { workspaceSlug } = useParams();
|
||||
const { workspaceSlug } = params;
|
||||
// store hooks
|
||||
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
|
||||
const {
|
||||
@@ -116,6 +115,7 @@ const WorkspaceMembersSettingsPage = observer(() => {
|
||||
isOpen={inviteModal}
|
||||
onClose={() => setInviteModal(false)}
|
||||
onSubmit={handleWorkspaceInvite}
|
||||
workspaceSlug={workspaceSlug}
|
||||
/>
|
||||
<section
|
||||
className={cn("w-full h-full", {
|
||||
|
||||
+8
-5
@@ -1,5 +1,5 @@
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams, usePathname } from "next/navigation";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { WORKSPACE_SETTINGS_LINKS, EUserPermissionsLevel } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
// hooks
|
||||
@@ -8,9 +8,12 @@ import { useAppRouter } from "@/hooks/use-app-router";
|
||||
// plane web helpers
|
||||
import { shouldRenderSettingLink } from "@/plane-web/helpers/workspace.helper";
|
||||
|
||||
export const MobileWorkspaceSettingsTabs = observer(() => {
|
||||
type Props = {
|
||||
workspaceSlug: string;
|
||||
};
|
||||
|
||||
export const MobileWorkspaceSettingsTabs = observer(({ workspaceSlug }: Props) => {
|
||||
const router = useAppRouter();
|
||||
const { workspaceSlug } = useParams();
|
||||
const pathname = usePathname();
|
||||
const { t } = useTranslation();
|
||||
// mobx store
|
||||
@@ -20,8 +23,8 @@ export const MobileWorkspaceSettingsTabs = observer(() => {
|
||||
<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) =>
|
||||
shouldRenderSettingLink(workspaceSlug.toString(), item.key) &&
|
||||
allowPermissions(item.access, EUserPermissionsLevel.WORKSPACE, workspaceSlug.toString()) && (
|
||||
shouldRenderSettingLink(workspaceSlug, item.key) &&
|
||||
allowPermissions(item.access, EUserPermissionsLevel.WORKSPACE, workspaceSlug) && (
|
||||
<div
|
||||
className={`${
|
||||
item.highlight(pathname, `/${workspaceSlug}`)
|
||||
|
||||
@@ -37,13 +37,14 @@ export const WorkspaceActionIcons = ({
|
||||
|
||||
type TWorkspaceSettingsSidebarProps = {
|
||||
isMobile?: boolean;
|
||||
workspaceSlug: string;
|
||||
};
|
||||
|
||||
export const WorkspaceSettingsSidebar = (props: TWorkspaceSettingsSidebarProps) => {
|
||||
const { isMobile = false } = props;
|
||||
const { isMobile = false, workspaceSlug } = props;
|
||||
// router
|
||||
const pathname = usePathname();
|
||||
const { workspaceSlug } = useParams(); // store hooks
|
||||
// store hooks
|
||||
const { allowPermissions } = useUserPermissions();
|
||||
const isAdmin = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.WORKSPACE);
|
||||
|
||||
@@ -55,7 +56,7 @@ export const WorkspaceSettingsSidebar = (props: TWorkspaceSettingsSidebarProps)
|
||||
isAdmin || ![WORKSPACE_SETTINGS_CATEGORY.FEATURES, WORKSPACE_SETTINGS_CATEGORY.DEVELOPER].includes(category)
|
||||
)}
|
||||
groupedSettings={GROUPED_WORKSPACE_SETTINGS}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
workspaceSlug={workspaceSlug}
|
||||
isActive={(data: { href: string }) =>
|
||||
data.href === "/settings"
|
||||
? pathname === `/${workspaceSlug}${data.href}/`
|
||||
@@ -63,8 +64,8 @@ export const WorkspaceSettingsSidebar = (props: TWorkspaceSettingsSidebarProps)
|
||||
}
|
||||
shouldRender={(data: { key: string; access?: EUserWorkspaceRoles[] | undefined }) =>
|
||||
data.access
|
||||
? shouldRenderSettingLink(workspaceSlug.toString(), data.key) &&
|
||||
allowPermissions(data.access, EUserPermissionsLevel.WORKSPACE, workspaceSlug.toString())
|
||||
? shouldRenderSettingLink(workspaceSlug, data.key) &&
|
||||
allowPermissions(data.access, EUserPermissionsLevel.WORKSPACE, workspaceSlug)
|
||||
: false
|
||||
}
|
||||
actionIcons={WorkspaceActionIcons}
|
||||
|
||||
+3
-3
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
import useSWR from "swr";
|
||||
import { EUserPermissions, EUserPermissionsLevel, WORKSPACE_SETTINGS_TRACKER_EVENTS } from "@plane/constants";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
@@ -19,11 +19,11 @@ import { useWebhook } from "@/hooks/store/use-webhook";
|
||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||
import { useUserPermissions } from "@/hooks/store/user";
|
||||
|
||||
const WebhookDetailsPage = observer(() => {
|
||||
const WebhookDetailsPage: React.FC<Route.ComponentProps> = observer(({ params }) => {
|
||||
// states
|
||||
const [deleteWebhookModal, setDeleteWebhookModal] = useState(false);
|
||||
// router
|
||||
const { workspaceSlug, webhookId } = useParams();
|
||||
const { workspaceSlug, webhookId } = params;
|
||||
// mobx store
|
||||
const { currentWebhook, fetchWebhookById, updateWebhook } = useWebhook();
|
||||
const { currentWorkspace } = useWorkspace();
|
||||
|
||||
+3
-3
@@ -2,7 +2,7 @@
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
import useSWR from "swr";
|
||||
// plane imports
|
||||
import { EUserPermissions, EUserPermissionsLevel, WORKSPACE_SETTINGS_TRACKER_ELEMENTS } from "@plane/constants";
|
||||
@@ -22,11 +22,11 @@ import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||
import { useUserPermissions } from "@/hooks/store/user";
|
||||
import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path";
|
||||
|
||||
const WebhooksListPage = observer(() => {
|
||||
const WebhooksListPage: React.FC<Route.ComponentProps> = observer(({ params }) => {
|
||||
// states
|
||||
const [showCreateWebhookModal, setShowCreateWebhookModal] = useState(false);
|
||||
// router
|
||||
const { workspaceSlug } = useParams();
|
||||
const { workspaceSlug } = params;
|
||||
// plane hooks
|
||||
const { t } = useTranslation();
|
||||
// mobx store
|
||||
|
||||
+5
-7
@@ -2,7 +2,7 @@
|
||||
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
@@ -20,11 +20,9 @@ import { useUserPermissions } from "@/hooks/store/user";
|
||||
// plane web imports
|
||||
import { CustomAutomationsRoot } from "@/plane-web/components/automations/root";
|
||||
|
||||
const AutomationSettingsPage = observer(() => {
|
||||
// router
|
||||
const { workspaceSlug: workspaceSlugParam, projectId: projectIdParam } = useParams();
|
||||
const workspaceSlug = workspaceSlugParam?.toString();
|
||||
const projectId = projectIdParam?.toString();
|
||||
const AutomationSettingsPage: React.FC<Route.ComponentProps> = observer(({ params }) => {
|
||||
// router params
|
||||
const { workspaceSlug, projectId } = params;
|
||||
// store hooks
|
||||
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
|
||||
const { currentProjectDetails: projectDetails, updateProject } = useProject();
|
||||
@@ -64,7 +62,7 @@ const AutomationSettingsPage = observer(() => {
|
||||
<AutoArchiveAutomation handleChange={handleChange} />
|
||||
<AutoCloseAutomation handleChange={handleChange} />
|
||||
</section>
|
||||
<CustomAutomationsRoot projectId={projectId} workspaceSlug={workspaceSlug} />
|
||||
{projectId && workspaceSlug && <CustomAutomationsRoot projectId={projectId} workspaceSlug={workspaceSlug} />}
|
||||
</SettingsContentWrapper>
|
||||
);
|
||||
});
|
||||
|
||||
+11
-7
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
// plane imports
|
||||
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
@@ -19,9 +19,9 @@ import { useUserPermissions } from "@/hooks/store/user";
|
||||
import { ProjectTeamspaceList } from "@/plane-web/components/projects/teamspaces/teamspace-list";
|
||||
import { getProjectSettingsPageLabelI18nKey } from "@/plane-web/helpers/project-settings";
|
||||
|
||||
const MembersSettingsPage = observer(() => {
|
||||
// router
|
||||
const { workspaceSlug: routerWorkspaceSlug, projectId: routerProjectId } = useParams();
|
||||
const MembersSettingsPage: React.FC<Route.ComponentProps> = observer(({ params }) => {
|
||||
// router params
|
||||
const { workspaceSlug: routerWorkspaceSlug, projectId: routerProjectId } = params;
|
||||
// plane hooks
|
||||
const { t } = useTranslation();
|
||||
// store hooks
|
||||
@@ -46,9 +46,13 @@ const MembersSettingsPage = observer(() => {
|
||||
<SettingsContentWrapper size="lg">
|
||||
<PageHead title={pageTitle} />
|
||||
<SettingsHeading title={t(getProjectSettingsPageLabelI18nKey("members", "common.members"))} />
|
||||
<ProjectSettingsMemberDefaults projectId={projectId} workspaceSlug={workspaceSlug} />
|
||||
<ProjectTeamspaceList projectId={projectId} workspaceSlug={workspaceSlug} />
|
||||
<ProjectMemberList projectId={projectId} workspaceSlug={workspaceSlug} />
|
||||
{projectId && workspaceSlug && (
|
||||
<>
|
||||
<ProjectSettingsMemberDefaults projectId={projectId} workspaceSlug={workspaceSlug} />
|
||||
<ProjectTeamspaceList projectId={projectId} workspaceSlug={workspaceSlug} />
|
||||
<ProjectMemberList projectId={projectId} workspaceSlug={workspaceSlug} />
|
||||
</>
|
||||
)}
|
||||
</SettingsContentWrapper>
|
||||
);
|
||||
});
|
||||
|
||||
+10
-15
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
import useSWR from "swr";
|
||||
// plane imports
|
||||
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||
@@ -19,12 +19,12 @@ import { SettingsContentWrapper } from "@/components/settings/content-wrapper";
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
import { useUserPermissions } from "@/hooks/store/user";
|
||||
|
||||
const ProjectSettingsPage = observer(() => {
|
||||
const ProjectSettingsPage: React.FC<Route.ComponentProps> = observer(({ params }) => {
|
||||
// states
|
||||
const [selectProject, setSelectedProject] = useState<string | null>(null);
|
||||
const [archiveProject, setArchiveProject] = useState<boolean>(false);
|
||||
// router
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
// router params
|
||||
const { workspaceSlug, projectId } = params;
|
||||
// store hooks
|
||||
const { currentProjectDetails, fetchProjectDetails } = useProject();
|
||||
const { allowPermissions } = useUserPermissions();
|
||||
@@ -33,15 +33,10 @@ const ProjectSettingsPage = observer(() => {
|
||||
// TODO: removed this API if not necessary
|
||||
const { isLoading } = useSWR(
|
||||
workspaceSlug && projectId ? `PROJECT_DETAILS_${projectId}` : null,
|
||||
workspaceSlug && projectId ? () => fetchProjectDetails(workspaceSlug.toString(), projectId.toString()) : null
|
||||
workspaceSlug && projectId ? () => fetchProjectDetails(workspaceSlug, projectId) : null
|
||||
);
|
||||
// derived values
|
||||
const isAdmin = allowPermissions(
|
||||
[EUserPermissions.ADMIN],
|
||||
EUserPermissionsLevel.PROJECT,
|
||||
workspaceSlug.toString(),
|
||||
projectId.toString()
|
||||
);
|
||||
const isAdmin = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.PROJECT, workspaceSlug, projectId);
|
||||
|
||||
const pageTitle = currentProjectDetails?.name ? `${currentProjectDetails?.name} - General Settings` : undefined;
|
||||
|
||||
@@ -51,8 +46,8 @@ const ProjectSettingsPage = observer(() => {
|
||||
{currentProjectDetails && workspaceSlug && projectId && (
|
||||
<>
|
||||
<ArchiveRestoreProjectModal
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
projectId={projectId.toString()}
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
isOpen={archiveProject}
|
||||
onClose={() => setArchiveProject(false)}
|
||||
archive
|
||||
@@ -69,8 +64,8 @@ const ProjectSettingsPage = observer(() => {
|
||||
{currentProjectDetails && workspaceSlug && projectId && !isLoading ? (
|
||||
<ProjectDetailsForm
|
||||
project={currentProjectDetails}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
projectId={projectId.toString()}
|
||||
workspaceSlug={workspaceSlug}
|
||||
projectId={projectId}
|
||||
isAdmin={isAdmin}
|
||||
/>
|
||||
) : (
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
"use client";
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams, usePathname } from "next/navigation";
|
||||
import { usePathname } from "next/navigation";
|
||||
import type { Route } from "./+types/layout";
|
||||
import type { PropsWithChildren } from "react";
|
||||
// components
|
||||
import { getProjectActivePath } from "@/components/settings/helper";
|
||||
import { SettingsMobileNav } from "@/components/settings/mobile";
|
||||
@@ -12,16 +13,11 @@ import { useProject } from "@/hooks/store/use-project";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import { ProjectAuthWrapper } from "@/plane-web/layouts/project-wrapper";
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
const ProjectSettingsLayout = observer((props: Props) => {
|
||||
const { children } = props;
|
||||
const ProjectSettingsLayout: React.FC<PropsWithChildren<Route.ComponentProps>> = observer(({ children, params }) => {
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
const pathname = usePathname();
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
const { workspaceSlug, projectId } = params;
|
||||
const { joinedProjectIds } = useProject();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -34,7 +30,7 @@ const ProjectSettingsLayout = observer((props: Props) => {
|
||||
return (
|
||||
<>
|
||||
<SettingsMobileNav hamburgerContent={ProjectSettingsSidebar} activePath={getProjectActivePath(pathname) || ""} />
|
||||
<ProjectAuthWrapper workspaceSlug={workspaceSlug?.toString()} projectId={projectId?.toString()}>
|
||||
<ProjectAuthWrapper workspaceSlug={workspaceSlug!} projectId={projectId!}>
|
||||
<div className="relative flex h-full w-full">
|
||||
<div className="hidden md:block">{projectId && <ProjectSettingsSidebar />}</div>
|
||||
<div className="w-full h-full overflow-y-scroll md:pt-page-y">{children}</div>
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
"use client";
|
||||
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "../+types/layout";
|
||||
import { AppRailProvider } from "@/hooks/context/app-rail-context";
|
||||
import { WorkspaceContentWrapper } from "@/plane-web/components/workspace/content-wrapper";
|
||||
|
||||
export default function WorkspaceLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function WorkspaceLayout() {
|
||||
return (
|
||||
<AppRailProvider>
|
||||
<WorkspaceContentWrapper>{children}</WorkspaceContentWrapper>
|
||||
<WorkspaceContentWrapper>
|
||||
<Outlet />
|
||||
</WorkspaceContentWrapper>
|
||||
</AppRailProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Forgot Password - Plane",
|
||||
};
|
||||
|
||||
export default function ForgotPasswordLayout({ children }: { children: React.ReactNode }) {
|
||||
return children;
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import type { Route } from "./+types/page";
|
||||
|
||||
export const meta: Route.MetaFunction = () => [{ title: "Forgot Password - Plane" }];
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
// components
|
||||
import { ForgotPasswordForm } from "@/components/account/auth-forms/forgot-password";
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Reset Password - Plane",
|
||||
};
|
||||
|
||||
export default function ResetPasswordLayout({ children }: { children: React.ReactNode }) {
|
||||
return children;
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import type { Route } from "./+types/page";
|
||||
|
||||
export const meta: Route.MetaFunction = () => [{ title: "Reset Password - Plane" }];
|
||||
|
||||
// plane imports
|
||||
import { EAuthModes } from "@plane/constants";
|
||||
// components
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Set Password - Plane",
|
||||
};
|
||||
|
||||
export default function SetPasswordLayout({ children }: { children: React.ReactNode }) {
|
||||
return children;
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import type { Route } from "./+types/page";
|
||||
|
||||
export const meta: Route.MetaFunction = () => [{ title: "Set Password - Plane" }];
|
||||
|
||||
// plane imports
|
||||
import { EAuthModes } from "@plane/constants";
|
||||
// components
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Workspace",
|
||||
};
|
||||
|
||||
export default function CreateWorkspaceLayout({ children }: { children: React.ReactNode }) {
|
||||
return children;
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import type { Route } from "./+types/page";
|
||||
|
||||
export const meta: Route.MetaFunction = () => [{ title: "Create Workspace" }];
|
||||
|
||||
import { useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import Image from "next/image";
|
||||
@@ -19,7 +23,7 @@ import { AuthenticationWrapper } from "@/lib/wrappers/authentication-wrapper";
|
||||
// plane web helpers
|
||||
import { getIsWorkspaceCreationDisabled } from "@/plane-web/helpers/instance.helper";
|
||||
// images
|
||||
import WorkspaceCreationDisabled from "@/public/workspace/workspace-creation-disabled.png";
|
||||
import WorkspaceCreationDisabled from "@/app/assets/workspace/workspace-creation-disabled.png";
|
||||
|
||||
const CreateWorkspacePage = observer(() => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
export default function InstallationProviderLayout({ children }: { children: React.ReactNode }) {
|
||||
return children;
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect } from "react";
|
||||
import { useParams, useSearchParams } from "next/navigation";
|
||||
import type { Route } from "./+types/page";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
// ui
|
||||
import { LogoSpinner } from "@/components/common/logo-spinner";
|
||||
// services
|
||||
@@ -10,9 +11,9 @@ import { AppInstallationService } from "@/services/app_installation.service";
|
||||
// services
|
||||
const appInstallationService = new AppInstallationService();
|
||||
|
||||
export default function AppPostInstallation() {
|
||||
export default function AppPostInstallation({ params }: Route.ComponentProps) {
|
||||
// params
|
||||
const { provider } = useParams();
|
||||
const { provider } = params;
|
||||
// query params
|
||||
const searchParams = useSearchParams();
|
||||
const installation_id = searchParams.get("installation_id");
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Invitations",
|
||||
};
|
||||
|
||||
export default function InvitationsLayout({ children }: { children: React.ReactNode }) {
|
||||
return children;
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import type { Route } from "./+types/page";
|
||||
|
||||
export const meta: Route.MetaFunction = () => [{ title: "Invitations" }];
|
||||
|
||||
import React, { useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import Link from "next/link";
|
||||
@@ -30,7 +34,7 @@ import { AuthenticationWrapper } from "@/lib/wrappers/authentication-wrapper";
|
||||
// plane web services
|
||||
import { WorkspaceService } from "@/plane-web/services";
|
||||
// images
|
||||
import emptyInvitation from "@/public/empty-state/invitation.svg";
|
||||
import emptyInvitation from "@/app/assets/empty-state/invitation.svg";
|
||||
|
||||
const workspaceService = new WorkspaceService();
|
||||
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
// https://nextjs.org/docs/app/api-reference/functions/generate-metadata#link-relpreload
|
||||
export const usePreloadResources = () => {
|
||||
useEffect(() => {
|
||||
const preloadItem = (url: string) => {
|
||||
ReactDOM.preload(url, { as: "fetch", crossOrigin: "use-credentials" });
|
||||
try {
|
||||
const link = document.createElement("link");
|
||||
link.rel = "preload";
|
||||
// as="fetch" isn't fully typed across all TS DOM lib versions, so set via attribute
|
||||
link.setAttribute("as", "fetch");
|
||||
link.href = url;
|
||||
link.crossOrigin = "use-credentials" as any;
|
||||
document.head.appendChild(link);
|
||||
} catch (e) {
|
||||
// no-op fallback
|
||||
}
|
||||
};
|
||||
|
||||
const urls = [
|
||||
|
||||
@@ -1,31 +1,15 @@
|
||||
import type { Metadata, Viewport } from "next";
|
||||
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "./+types/layout";
|
||||
import { PreloadResources } from "./layout.preload";
|
||||
|
||||
// styles
|
||||
import "@/styles/command-pallette.css";
|
||||
import "@/styles/emoji.css";
|
||||
import "@plane/propel/styles/react-day-picker";
|
||||
import "@plane/propel/styles/react-day-picker.css";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
robots: {
|
||||
index: false,
|
||||
follow: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const viewport: Viewport = {
|
||||
minimumScale: 1,
|
||||
initialScale: 1,
|
||||
width: "device-width",
|
||||
viewportFit: "cover",
|
||||
};
|
||||
|
||||
export default function AppLayout({ children }: { children: React.ReactNode }) {
|
||||
export default function AppLayout() {
|
||||
return (
|
||||
<>
|
||||
<PreloadResources />
|
||||
{children}
|
||||
<Outlet />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Onboarding",
|
||||
};
|
||||
|
||||
export default function OnboardingLayout({ children }: { children: React.ReactNode }) {
|
||||
return children;
|
||||
}
|
||||
@@ -8,13 +8,10 @@ import { AuthenticationWrapper } from "@/lib/wrappers/authentication-wrapper";
|
||||
// layout
|
||||
import { ProfileLayoutSidebar } from "./sidebar";
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export default function ProfileSettingsLayout(props: Props) {
|
||||
const { children } = props;
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "../+types/layout";
|
||||
|
||||
export default function ProfileSettingsLayout() {
|
||||
return (
|
||||
<>
|
||||
<CommandPalette />
|
||||
@@ -22,7 +19,9 @@ export default function ProfileSettingsLayout(props: Props) {
|
||||
<div className="relative flex h-full w-full overflow-hidden rounded-lg border border-custom-border-200">
|
||||
<ProfileLayoutSidebar />
|
||||
<main className="relative flex h-full w-full flex-col overflow-hidden bg-custom-background-100">
|
||||
<div className="h-full w-full overflow-hidden">{children}</div>
|
||||
<div className="h-full w-full overflow-hidden">
|
||||
<Outlet />
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</AuthenticationWrapper>
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Sign up - Plane",
|
||||
robots: {
|
||||
index: true,
|
||||
follow: false,
|
||||
},
|
||||
};
|
||||
|
||||
export default function SignUpLayout({ children }: { children: React.ReactNode }) {
|
||||
return children;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Workspace Invitations",
|
||||
};
|
||||
|
||||
export default function WorkspaceInvitationsLayout({ children }: { children: React.ReactNode }) {
|
||||
return children;
|
||||
}
|
||||
@@ -1,19 +1,6 @@
|
||||
import type { Metadata, Viewport } from "next";
|
||||
import { Outlet } from "react-router";
|
||||
import type { Route } from "./+types/layout";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
robots: {
|
||||
index: true,
|
||||
follow: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const viewport: Viewport = {
|
||||
minimumScale: 1,
|
||||
initialScale: 1,
|
||||
width: "device-width",
|
||||
viewportFit: "cover",
|
||||
};
|
||||
|
||||
export default function HomeLayout({ children }: { children: React.ReactNode }) {
|
||||
return <>{children}</>;
|
||||
export default function HomeLayout() {
|
||||
return <Outlet />;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user