feat: init
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
|
||||
import type { IProject } from "@plane/types";
|
||||
// ui
|
||||
// components
|
||||
import { NotAuthorizedView } from "@/components/auth-screens/not-authorized-view";
|
||||
import { AutoArchiveAutomation, AutoCloseAutomation } from "@/components/automation";
|
||||
import { PageHead } from "@/components/core/page-title";
|
||||
// hooks
|
||||
import { SettingsContentWrapper } from "@/components/settings/content-wrapper";
|
||||
import { SettingsHeading } from "@/components/settings/heading";
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
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();
|
||||
// store hooks
|
||||
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
|
||||
const { currentProjectDetails: projectDetails, updateProject } = useProject();
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
// derived values
|
||||
const canPerformProjectAdminActions = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.PROJECT);
|
||||
|
||||
const handleChange = async (formData: Partial<IProject>) => {
|
||||
if (!workspaceSlug || !projectId || !projectDetails) return;
|
||||
|
||||
await updateProject(workspaceSlug.toString(), projectId.toString(), formData).catch(() => {
|
||||
setToast({
|
||||
type: TOAST_TYPE.ERROR,
|
||||
title: "Error!",
|
||||
message: "Something went wrong. Please try again.",
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// derived values
|
||||
const pageTitle = projectDetails?.name ? `${projectDetails?.name} - Automations` : undefined;
|
||||
|
||||
if (workspaceUserInfo && !canPerformProjectAdminActions) {
|
||||
return <NotAuthorizedView section="settings" isProjectView className="h-auto" />;
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingsContentWrapper size="lg">
|
||||
<PageHead title={pageTitle} />
|
||||
<section className={`w-full ${canPerformProjectAdminActions ? "" : "opacity-60"}`}>
|
||||
<SettingsHeading
|
||||
title={t("project_settings.automations.heading")}
|
||||
description={t("project_settings.automations.description")}
|
||||
/>
|
||||
<AutoArchiveAutomation handleChange={handleChange} />
|
||||
<AutoCloseAutomation handleChange={handleChange} />
|
||||
</section>
|
||||
<CustomAutomationsRoot projectId={projectId} workspaceSlug={workspaceSlug} />
|
||||
</SettingsContentWrapper>
|
||||
);
|
||||
});
|
||||
|
||||
export default AutomationSettingsPage;
|
||||
@@ -0,0 +1,45 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
// components
|
||||
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||
import { NotAuthorizedView } from "@/components/auth-screens/not-authorized-view";
|
||||
import { PageHead } from "@/components/core/page-title";
|
||||
import { EstimateRoot } from "@/components/estimates";
|
||||
// hooks
|
||||
import { SettingsContentWrapper } from "@/components/settings/content-wrapper";
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
import { useUserPermissions } from "@/hooks/store/user";
|
||||
|
||||
const EstimatesSettingsPage = observer(() => {
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
// store
|
||||
const { currentProjectDetails } = useProject();
|
||||
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
|
||||
|
||||
// derived values
|
||||
const pageTitle = currentProjectDetails?.name ? `${currentProjectDetails?.name} - Estimates` : undefined;
|
||||
const canPerformProjectAdminActions = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.PROJECT);
|
||||
|
||||
if (!workspaceSlug || !projectId) return <></>;
|
||||
|
||||
if (workspaceUserInfo && !canPerformProjectAdminActions) {
|
||||
return <NotAuthorizedView section="settings" isProjectView className="h-auto" />;
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingsContentWrapper>
|
||||
<PageHead title={pageTitle} />
|
||||
<div className={`w-full ${canPerformProjectAdminActions ? "" : "pointer-events-none opacity-60"}`}>
|
||||
<EstimateRoot
|
||||
workspaceSlug={workspaceSlug?.toString()}
|
||||
projectId={projectId?.toString()}
|
||||
isAdmin={canPerformProjectAdminActions}
|
||||
/>
|
||||
</div>
|
||||
</SettingsContentWrapper>
|
||||
);
|
||||
});
|
||||
|
||||
export default EstimatesSettingsPage;
|
||||
@@ -0,0 +1,45 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
// components
|
||||
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||
import { NotAuthorizedView } from "@/components/auth-screens/not-authorized-view";
|
||||
import { PageHead } from "@/components/core/page-title";
|
||||
import { SettingsContentWrapper } from "@/components/settings/content-wrapper";
|
||||
// hooks
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
import { useUserPermissions } from "@/hooks/store/user";
|
||||
import { ProjectFeaturesList } from "@/plane-web/components/projects/settings/features-list";
|
||||
|
||||
const FeaturesSettingsPage = observer(() => {
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
// store
|
||||
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
|
||||
|
||||
const { currentProjectDetails } = useProject();
|
||||
// derived values
|
||||
const pageTitle = currentProjectDetails?.name ? `${currentProjectDetails?.name} - Features` : undefined;
|
||||
const canPerformProjectAdminActions = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.PROJECT);
|
||||
|
||||
if (!workspaceSlug || !projectId) return null;
|
||||
|
||||
if (workspaceUserInfo && !canPerformProjectAdminActions) {
|
||||
return <NotAuthorizedView section="settings" isProjectView className="h-auto" />;
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingsContentWrapper>
|
||||
<PageHead title={pageTitle} />
|
||||
<section className={`w-full ${canPerformProjectAdminActions ? "" : "opacity-60"}`}>
|
||||
<ProjectFeaturesList
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
projectId={projectId.toString()}
|
||||
isAdmin={canPerformProjectAdminActions}
|
||||
/>
|
||||
</section>
|
||||
</SettingsContentWrapper>
|
||||
);
|
||||
});
|
||||
|
||||
export default FeaturesSettingsPage;
|
||||
@@ -0,0 +1,59 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef } from "react";
|
||||
import { combine } from "@atlaskit/pragmatic-drag-and-drop/combine";
|
||||
import { autoScrollForElements } from "@atlaskit/pragmatic-drag-and-drop-auto-scroll/element";
|
||||
import { observer } from "mobx-react";
|
||||
// components
|
||||
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||
import { NotAuthorizedView } from "@/components/auth-screens/not-authorized-view";
|
||||
import { PageHead } from "@/components/core/page-title";
|
||||
import { ProjectSettingsLabelList } from "@/components/labels";
|
||||
// hooks
|
||||
import { SettingsContentWrapper } from "@/components/settings/content-wrapper";
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
import { useUserPermissions } from "@/hooks/store/user";
|
||||
|
||||
const LabelsSettingsPage = observer(() => {
|
||||
// store hooks
|
||||
const { currentProjectDetails } = useProject();
|
||||
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
|
||||
|
||||
const pageTitle = currentProjectDetails?.name ? `${currentProjectDetails?.name} - Labels` : undefined;
|
||||
|
||||
const scrollableContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
// derived values
|
||||
const canPerformProjectMemberActions = allowPermissions(
|
||||
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
|
||||
EUserPermissionsLevel.PROJECT
|
||||
);
|
||||
|
||||
// Enable Auto Scroll for Labels list
|
||||
useEffect(() => {
|
||||
const element = scrollableContainerRef.current;
|
||||
|
||||
if (!element) return;
|
||||
|
||||
return combine(
|
||||
autoScrollForElements({
|
||||
element,
|
||||
})
|
||||
);
|
||||
}, []);
|
||||
|
||||
if (workspaceUserInfo && !canPerformProjectMemberActions) {
|
||||
return <NotAuthorizedView section="settings" isProjectView className="h-auto" />;
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingsContentWrapper>
|
||||
<PageHead title={pageTitle} />
|
||||
<div ref={scrollableContainerRef} className="h-full w-full gap-10">
|
||||
<ProjectSettingsLabelList />
|
||||
</div>
|
||||
</SettingsContentWrapper>
|
||||
);
|
||||
});
|
||||
|
||||
export default LabelsSettingsPage;
|
||||
@@ -0,0 +1,56 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
// plane imports
|
||||
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
// components
|
||||
import { NotAuthorizedView } from "@/components/auth-screens/not-authorized-view";
|
||||
import { PageHead } from "@/components/core/page-title";
|
||||
// hooks
|
||||
import { ProjectMemberList } from "@/components/project/member-list";
|
||||
import { ProjectSettingsMemberDefaults } from "@/components/project/project-settings-member-defaults";
|
||||
import { SettingsContentWrapper } from "@/components/settings/content-wrapper";
|
||||
import { SettingsHeading } from "@/components/settings/heading";
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
import { useUserPermissions } from "@/hooks/store/user";
|
||||
// plane web imports
|
||||
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();
|
||||
// plane hooks
|
||||
const { t } = useTranslation();
|
||||
// store hooks
|
||||
const { currentProjectDetails } = useProject();
|
||||
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
|
||||
// derived values
|
||||
const projectId = routerProjectId?.toString();
|
||||
const workspaceSlug = routerWorkspaceSlug?.toString();
|
||||
const pageTitle = currentProjectDetails?.name ? `${currentProjectDetails?.name} - Members` : undefined;
|
||||
const isProjectMemberOrAdmin = allowPermissions(
|
||||
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
|
||||
EUserPermissionsLevel.PROJECT
|
||||
);
|
||||
const isWorkspaceAdmin = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.WORKSPACE);
|
||||
const canPerformProjectMemberActions = isProjectMemberOrAdmin || isWorkspaceAdmin;
|
||||
|
||||
if (workspaceUserInfo && !canPerformProjectMemberActions) {
|
||||
return <NotAuthorizedView section="settings" isProjectView className="h-auto" />;
|
||||
}
|
||||
|
||||
return (
|
||||
<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} />
|
||||
</SettingsContentWrapper>
|
||||
);
|
||||
});
|
||||
|
||||
export default MembersSettingsPage;
|
||||
@@ -0,0 +1,97 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import useSWR from "swr";
|
||||
// plane imports
|
||||
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||
// components
|
||||
import { PageHead } from "@/components/core/page-title";
|
||||
import { DeleteProjectModal } from "@/components/project/delete-project-modal";
|
||||
import { ProjectDetailsForm } from "@/components/project/form";
|
||||
import { ProjectDetailsFormLoader } from "@/components/project/form-loader";
|
||||
import { ArchiveRestoreProjectModal } from "@/components/project/settings/archive-project/archive-restore-modal";
|
||||
import { ArchiveProjectSelection } from "@/components/project/settings/archive-project/selection";
|
||||
import { DeleteProjectSection } from "@/components/project/settings/delete-project-section";
|
||||
import { SettingsContentWrapper } from "@/components/settings/content-wrapper";
|
||||
// hooks
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
import { useUserPermissions } from "@/hooks/store/user";
|
||||
|
||||
const ProjectSettingsPage = observer(() => {
|
||||
// states
|
||||
const [selectProject, setSelectedProject] = useState<string | null>(null);
|
||||
const [archiveProject, setArchiveProject] = useState<boolean>(false);
|
||||
// router
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
// store hooks
|
||||
const { currentProjectDetails, fetchProjectDetails } = useProject();
|
||||
const { allowPermissions } = useUserPermissions();
|
||||
|
||||
// api call to fetch project details
|
||||
// TODO: removed this API if not necessary
|
||||
const { isLoading } = useSWR(
|
||||
workspaceSlug && projectId ? `PROJECT_DETAILS_${projectId}` : null,
|
||||
workspaceSlug && projectId ? () => fetchProjectDetails(workspaceSlug.toString(), projectId.toString()) : null
|
||||
);
|
||||
// derived values
|
||||
const isAdmin = allowPermissions(
|
||||
[EUserPermissions.ADMIN],
|
||||
EUserPermissionsLevel.PROJECT,
|
||||
workspaceSlug.toString(),
|
||||
projectId.toString()
|
||||
);
|
||||
|
||||
const pageTitle = currentProjectDetails?.name ? `${currentProjectDetails?.name} - General Settings` : undefined;
|
||||
|
||||
return (
|
||||
<SettingsContentWrapper>
|
||||
<PageHead title={pageTitle} />
|
||||
{currentProjectDetails && workspaceSlug && projectId && (
|
||||
<>
|
||||
<ArchiveRestoreProjectModal
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
projectId={projectId.toString()}
|
||||
isOpen={archiveProject}
|
||||
onClose={() => setArchiveProject(false)}
|
||||
archive
|
||||
/>
|
||||
<DeleteProjectModal
|
||||
project={currentProjectDetails}
|
||||
isOpen={Boolean(selectProject)}
|
||||
onClose={() => setSelectedProject(null)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className={`w-full ${isAdmin ? "" : "opacity-60"}`}>
|
||||
{currentProjectDetails && workspaceSlug && projectId && !isLoading ? (
|
||||
<ProjectDetailsForm
|
||||
project={currentProjectDetails}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
projectId={projectId.toString()}
|
||||
isAdmin={isAdmin}
|
||||
/>
|
||||
) : (
|
||||
<ProjectDetailsFormLoader />
|
||||
)}
|
||||
|
||||
{isAdmin && currentProjectDetails && (
|
||||
<>
|
||||
<ArchiveProjectSelection
|
||||
projectDetails={currentProjectDetails}
|
||||
handleArchive={() => setArchiveProject(true)}
|
||||
/>
|
||||
<DeleteProjectSection
|
||||
projectDetails={currentProjectDetails}
|
||||
handleDelete={() => setSelectedProject(currentProjectDetails.id ?? null)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</SettingsContentWrapper>
|
||||
);
|
||||
});
|
||||
|
||||
export default ProjectSettingsPage;
|
||||
@@ -0,0 +1,53 @@
|
||||
"use client";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
// components
|
||||
import { NotAuthorizedView } from "@/components/auth-screens/not-authorized-view";
|
||||
import { PageHead } from "@/components/core/page-title";
|
||||
import { ProjectStateRoot } from "@/components/project-states";
|
||||
// hook
|
||||
import { SettingsContentWrapper } from "@/components/settings/content-wrapper";
|
||||
import { SettingsHeading } from "@/components/settings/heading";
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
import { useUserPermissions } from "@/hooks/store/user";
|
||||
|
||||
const StatesSettingsPage = observer(() => {
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
// store
|
||||
const { currentProjectDetails } = useProject();
|
||||
const { workspaceUserInfo, allowPermissions } = useUserPermissions();
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
// derived values
|
||||
const pageTitle = currentProjectDetails?.name ? `${currentProjectDetails?.name} - States` : undefined;
|
||||
// derived values
|
||||
const canPerformProjectMemberActions = allowPermissions(
|
||||
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
|
||||
EUserPermissionsLevel.PROJECT
|
||||
);
|
||||
|
||||
if (workspaceUserInfo && !canPerformProjectMemberActions) {
|
||||
return <NotAuthorizedView section="settings" isProjectView className="h-auto" />;
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingsContentWrapper>
|
||||
<PageHead title={pageTitle} />
|
||||
<div className="w-full">
|
||||
<SettingsHeading
|
||||
title={t("project_settings.states.heading")}
|
||||
description={t("project_settings.states.description")}
|
||||
/>
|
||||
{workspaceSlug && projectId && (
|
||||
<ProjectStateRoot workspaceSlug={workspaceSlug.toString()} projectId={projectId.toString()} />
|
||||
)}
|
||||
</div>
|
||||
</SettingsContentWrapper>
|
||||
);
|
||||
});
|
||||
|
||||
export default StatesSettingsPage;
|
||||
@@ -0,0 +1,47 @@
|
||||
"use client";
|
||||
|
||||
import type { ReactNode } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams, usePathname } from "next/navigation";
|
||||
// components
|
||||
import { getProjectActivePath } from "@/components/settings/helper";
|
||||
import { SettingsMobileNav } from "@/components/settings/mobile";
|
||||
import { ProjectSettingsSidebar } from "@/components/settings/project/sidebar";
|
||||
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;
|
||||
// router
|
||||
const router = useAppRouter();
|
||||
const pathname = usePathname();
|
||||
const { workspaceSlug, projectId } = useParams();
|
||||
const { joinedProjectIds } = useProject();
|
||||
|
||||
useEffect(() => {
|
||||
if (projectId) return;
|
||||
if (joinedProjectIds.length > 0) {
|
||||
router.push(`/${workspaceSlug}/settings/projects/${joinedProjectIds[0]}`);
|
||||
}
|
||||
}, [joinedProjectIds, router, workspaceSlug, projectId]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsMobileNav hamburgerContent={ProjectSettingsSidebar} activePath={getProjectActivePath(pathname) || ""} />
|
||||
<ProjectAuthWrapper workspaceSlug={workspaceSlug?.toString()} projectId={projectId?.toString()}>
|
||||
<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>
|
||||
</div>
|
||||
</ProjectAuthWrapper>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
export default ProjectSettingsLayout;
|
||||
@@ -0,0 +1,43 @@
|
||||
"use client";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useTheme } from "next-themes";
|
||||
import { PROJECT_TRACKER_ELEMENTS } from "@plane/constants";
|
||||
import { Button, getButtonStyling } from "@plane/propel/button";
|
||||
import { cn } from "@plane/utils";
|
||||
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
||||
|
||||
const ProjectSettingsPage = () => {
|
||||
// store hooks
|
||||
const { resolvedTheme } = useTheme();
|
||||
const { toggleCreateProjectModal } = useCommandPalette();
|
||||
// derived values
|
||||
const resolvedPath =
|
||||
resolvedTheme === "dark"
|
||||
? "/empty-state/project-settings/no-projects-dark.png"
|
||||
: "/empty-state/project-settings/no-projects-light.png";
|
||||
return (
|
||||
<div className="flex flex-col gap-4 items-center justify-center h-full max-w-[480px] mx-auto">
|
||||
<Image src={resolvedPath} alt="No projects yet" width={384} height={250} />
|
||||
<div className="text-lg font-semibold text-custom-text-350">No projects yet</div>
|
||||
<div className="text-sm text-custom-text-350 text-center">
|
||||
Projects act as the foundation for goal-driven work. They let you manage your teams, tasks, and everything you
|
||||
need to get things done.
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Link href="https://plane.so/" target="_blank" className={cn(getButtonStyling("neutral-primary", "sm"))}>
|
||||
Learn more about projects
|
||||
</Link>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => toggleCreateProjectModal(true)}
|
||||
data-ph-element={PROJECT_TRACKER_ELEMENTS.EMPTY_STATE_CREATE_PROJECT_BUTTON}
|
||||
>
|
||||
Start your first project
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectSettingsPage;
|
||||
Reference in New Issue
Block a user