diff --git a/admin/app/ai/form.tsx b/admin/app/(all)/(dashboard)/ai/form.tsx
similarity index 99%
rename from admin/app/ai/form.tsx
rename to admin/app/(all)/(dashboard)/ai/form.tsx
index 47ab9480eaf..8b7d036ad2f 100644
--- a/admin/app/ai/form.tsx
+++ b/admin/app/(all)/(dashboard)/ai/form.tsx
@@ -5,7 +5,7 @@ import { Lightbulb } from "lucide-react";
import { IFormattedInstanceConfiguration, TInstanceAIConfigurationKeys } from "@plane/types";
import { Button, TOAST_TYPE, setToast } from "@plane/ui";
// components
-import { ControllerInput, TControllerInputFormField } from "@/components/common";
+import { ControllerInput, TControllerInputFormField } from "@/components/common/controller-input";
// hooks
import { useInstance } from "@/hooks/store";
diff --git a/admin/app/ai/layout.tsx b/admin/app/(all)/(dashboard)/ai/layout.tsx
similarity index 53%
rename from admin/app/ai/layout.tsx
rename to admin/app/(all)/(dashboard)/ai/layout.tsx
index d461a626aa2..42f3796496f 100644
--- a/admin/app/ai/layout.tsx
+++ b/admin/app/(all)/(dashboard)/ai/layout.tsx
@@ -1,11 +1,10 @@
import { ReactNode } from "react";
import { Metadata } from "next";
-import { AdminLayout } from "@/layouts/admin-layout";
export const metadata: Metadata = {
- title: "Artificial Intelligence Settings - Plane Web",
+ title: "Artificial Intelligence Settings - God Mode",
};
export default function AILayout({ children }: { children: ReactNode }) {
- return {children};
+ return <>{children}>;
}
diff --git a/admin/app/ai/page.tsx b/admin/app/(all)/(dashboard)/ai/page.tsx
similarity index 100%
rename from admin/app/ai/page.tsx
rename to admin/app/(all)/(dashboard)/ai/page.tsx
diff --git a/admin/app/authentication/github/form.tsx b/admin/app/(all)/(dashboard)/authentication/github/form.tsx
similarity index 95%
rename from admin/app/authentication/github/form.tsx
rename to admin/app/(all)/(dashboard)/authentication/github/form.tsx
index 0c6d81ae6af..6e5f2a90387 100644
--- a/admin/app/authentication/github/form.tsx
+++ b/admin/app/(all)/(dashboard)/authentication/github/form.tsx
@@ -10,14 +10,10 @@ import { IFormattedInstanceConfiguration, TInstanceGithubAuthenticationConfigura
import { Button, TOAST_TYPE, getButtonStyling, setToast } from "@plane/ui";
import { cn } from "@plane/utils";
// components
-import {
- CodeBlock,
- ConfirmDiscardModal,
- ControllerInput,
- CopyField,
- TControllerInputFormField,
- TCopyField,
-} from "@/components/common";
+import { CodeBlock } from "@/components/common/code-block";
+import { ConfirmDiscardModal } from "@/components/common/confirm-discard-modal";
+import { ControllerInput, TControllerInputFormField } from "@/components/common/controller-input";
+import { CopyField, TCopyField } from "@/components/common/copy-field";
// hooks
import { useInstance } from "@/hooks/store";
diff --git a/admin/app/(all)/(dashboard)/authentication/github/layout.tsx b/admin/app/(all)/(dashboard)/authentication/github/layout.tsx
new file mode 100644
index 00000000000..373f9340aff
--- /dev/null
+++ b/admin/app/(all)/(dashboard)/authentication/github/layout.tsx
@@ -0,0 +1,10 @@
+import { ReactNode } from "react";
+import { Metadata } from "next";
+
+export const metadata: Metadata = {
+ title: "GitHub Authentication - God Mode",
+};
+
+export default function GitHubAuthenticationLayout({ children }: { children: ReactNode }) {
+ return <>{children}>;
+}
diff --git a/admin/app/authentication/github/page.tsx b/admin/app/(all)/(dashboard)/authentication/github/page.tsx
similarity index 90%
rename from admin/app/authentication/github/page.tsx
rename to admin/app/(all)/(dashboard)/authentication/github/page.tsx
index 986a5ebd24e..75cb84e4afd 100644
--- a/admin/app/authentication/github/page.tsx
+++ b/admin/app/(all)/(dashboard)/authentication/github/page.tsx
@@ -9,8 +9,7 @@ import useSWR from "swr";
import { Loader, ToggleSwitch, setPromiseToast } from "@plane/ui";
import { resolveGeneralTheme } from "@plane/utils";
// components
-import { AuthenticationMethodCard } from "@/components/authentication";
-import { PageHeader } from "@/components/common";
+import { AuthenticationMethodCard } from "@/components/authentication/authentication-method-card";
// hooks
import { useInstance } from "@/hooks/store";
// icons
@@ -61,9 +60,11 @@ const InstanceGithubAuthenticationPage = observer(() => {
setIsSubmitting(false);
});
};
+
+ const isGithubEnabled = enableGithubConfig === "1";
+
return (
<>
-
{
}
config={
{
- Boolean(parseInt(enableGithubConfig)) === true
- ? updateConfig("IS_GITHUB_ENABLED", "0")
- : updateConfig("IS_GITHUB_ENABLED", "1");
+ updateConfig("IS_GITHUB_ENABLED", isGithubEnabled ? "0" : "1");
}}
size="sm"
disabled={isSubmitting || !formattedConfig}
diff --git a/admin/app/authentication/gitlab/form.tsx b/admin/app/(all)/(dashboard)/authentication/gitlab/form.tsx
similarity index 95%
rename from admin/app/authentication/gitlab/form.tsx
rename to admin/app/(all)/(dashboard)/authentication/gitlab/form.tsx
index f64158744a4..888b2533c2c 100644
--- a/admin/app/authentication/gitlab/form.tsx
+++ b/admin/app/(all)/(dashboard)/authentication/gitlab/form.tsx
@@ -8,14 +8,10 @@ import { IFormattedInstanceConfiguration, TInstanceGitlabAuthenticationConfigura
import { Button, TOAST_TYPE, getButtonStyling, setToast } from "@plane/ui";
import { cn } from "@plane/utils";
// components
-import {
- CodeBlock,
- ConfirmDiscardModal,
- ControllerInput,
- CopyField,
- TControllerInputFormField,
- TCopyField,
-} from "@/components/common";
+import { CodeBlock } from "@/components/common/code-block";
+import { ConfirmDiscardModal } from "@/components/common/confirm-discard-modal";
+import { ControllerInput, TControllerInputFormField } from "@/components/common/controller-input";
+import { CopyField, TCopyField } from "@/components/common/copy-field";
// hooks
import { useInstance } from "@/hooks/store";
diff --git a/admin/app/(all)/(dashboard)/authentication/gitlab/layout.tsx b/admin/app/(all)/(dashboard)/authentication/gitlab/layout.tsx
new file mode 100644
index 00000000000..fc89e9752fb
--- /dev/null
+++ b/admin/app/(all)/(dashboard)/authentication/gitlab/layout.tsx
@@ -0,0 +1,10 @@
+import { ReactNode } from "react";
+import { Metadata } from "next";
+
+export const metadata: Metadata = {
+ title: "GitLab Authentication - God Mode",
+};
+
+export default function GitlabAuthenticationLayout({ children }: { children: ReactNode }) {
+ return <>{children}>;
+}
diff --git a/admin/app/authentication/gitlab/page.tsx b/admin/app/(all)/(dashboard)/authentication/gitlab/page.tsx
similarity index 96%
rename from admin/app/authentication/gitlab/page.tsx
rename to admin/app/(all)/(dashboard)/authentication/gitlab/page.tsx
index 7a4d8248ef2..cdcfcd61bbc 100644
--- a/admin/app/authentication/gitlab/page.tsx
+++ b/admin/app/(all)/(dashboard)/authentication/gitlab/page.tsx
@@ -6,8 +6,7 @@ import Image from "next/image";
import useSWR from "swr";
import { Loader, ToggleSwitch, setPromiseToast } from "@plane/ui";
// components
-import { AuthenticationMethodCard } from "@/components/authentication";
-import { PageHeader } from "@/components/common";
+import { AuthenticationMethodCard } from "@/components/authentication/authentication-method-card";
// hooks
import { useInstance } from "@/hooks/store";
// icons
@@ -57,7 +56,6 @@ const InstanceGitlabAuthenticationPage = observer(() => {
};
return (
<>
-
{children}>;
+}
diff --git a/admin/app/authentication/google/page.tsx b/admin/app/(all)/(dashboard)/authentication/google/page.tsx
similarity index 96%
rename from admin/app/authentication/google/page.tsx
rename to admin/app/(all)/(dashboard)/authentication/google/page.tsx
index 992c7a8a7a1..6ac4ea09b9b 100644
--- a/admin/app/authentication/google/page.tsx
+++ b/admin/app/(all)/(dashboard)/authentication/google/page.tsx
@@ -6,8 +6,7 @@ import Image from "next/image";
import useSWR from "swr";
import { Loader, ToggleSwitch, setPromiseToast } from "@plane/ui";
// components
-import { AuthenticationMethodCard } from "@/components/authentication";
-import { PageHeader } from "@/components/common";
+import { AuthenticationMethodCard } from "@/components/authentication/authentication-method-card";
// hooks
import { useInstance } from "@/hooks/store";
// icons
@@ -57,7 +56,6 @@ const InstanceGoogleAuthenticationPage = observer(() => {
};
return (
<>
-
{children};
+ return <>{children}>;
}
diff --git a/admin/app/authentication/page.tsx b/admin/app/(all)/(dashboard)/authentication/page.tsx
similarity index 100%
rename from admin/app/authentication/page.tsx
rename to admin/app/(all)/(dashboard)/authentication/page.tsx
diff --git a/admin/app/email/email-config-form.tsx b/admin/app/(all)/(dashboard)/email/email-config-form.tsx
similarity index 99%
rename from admin/app/email/email-config-form.tsx
rename to admin/app/(all)/(dashboard)/email/email-config-form.tsx
index 73a1af17442..de7f33f5d82 100644
--- a/admin/app/email/email-config-form.tsx
+++ b/admin/app/(all)/(dashboard)/email/email-config-form.tsx
@@ -7,7 +7,7 @@ import { IFormattedInstanceConfiguration, TInstanceEmailConfigurationKeys } from
// ui
import { Button, CustomSelect, TOAST_TYPE, setToast } from "@plane/ui";
// components
-import { ControllerInput, TControllerInputFormField } from "@/components/common";
+import { ControllerInput, TControllerInputFormField } from "@/components/common/controller-input";
// hooks
import { useInstance } from "@/hooks/store";
// local components
diff --git a/admin/app/email/layout.tsx b/admin/app/(all)/(dashboard)/email/layout.tsx
similarity index 62%
rename from admin/app/email/layout.tsx
rename to admin/app/(all)/(dashboard)/email/layout.tsx
index 2084af1ea41..cb321295107 100644
--- a/admin/app/email/layout.tsx
+++ b/admin/app/(all)/(dashboard)/email/layout.tsx
@@ -1,15 +1,14 @@
import { ReactNode } from "react";
import { Metadata } from "next";
-import { AdminLayout } from "@/layouts/admin-layout";
interface EmailLayoutProps {
children: ReactNode;
}
export const metadata: Metadata = {
- title: "Email Settings - Plane Web",
+ title: "Email Settings - God Mode",
};
export default function EmailLayout({ children }: EmailLayoutProps) {
- return {children};
+ return <>{children}>;
}
diff --git a/admin/app/email/page.tsx b/admin/app/(all)/(dashboard)/email/page.tsx
similarity index 100%
rename from admin/app/email/page.tsx
rename to admin/app/(all)/(dashboard)/email/page.tsx
diff --git a/admin/app/email/test-email-modal.tsx b/admin/app/(all)/(dashboard)/email/test-email-modal.tsx
similarity index 100%
rename from admin/app/email/test-email-modal.tsx
rename to admin/app/(all)/(dashboard)/email/test-email-modal.tsx
diff --git a/admin/app/general/form.tsx b/admin/app/(all)/(dashboard)/general/form.tsx
similarity index 98%
rename from admin/app/general/form.tsx
rename to admin/app/(all)/(dashboard)/general/form.tsx
index 4fbd7053561..0700c4d0d5f 100644
--- a/admin/app/general/form.tsx
+++ b/admin/app/(all)/(dashboard)/general/form.tsx
@@ -8,7 +8,7 @@ import { IInstance, IInstanceAdmin } from "@plane/types";
// ui
import { Button, Input, TOAST_TYPE, ToggleSwitch, setToast } from "@plane/ui";
// components
-import { ControllerInput } from "@/components/common";
+import { ControllerInput } from "@/components/common/controller-input";
import { useInstance } from "@/hooks/store";
import { IntercomConfig } from "./intercom";
// hooks
diff --git a/admin/app/general/intercom.tsx b/admin/app/(all)/(dashboard)/general/intercom.tsx
similarity index 100%
rename from admin/app/general/intercom.tsx
rename to admin/app/(all)/(dashboard)/general/intercom.tsx
diff --git a/admin/app/general/layout.tsx b/admin/app/(all)/(dashboard)/general/layout.tsx
similarity index 57%
rename from admin/app/general/layout.tsx
rename to admin/app/(all)/(dashboard)/general/layout.tsx
index 374257daade..af300051052 100644
--- a/admin/app/general/layout.tsx
+++ b/admin/app/(all)/(dashboard)/general/layout.tsx
@@ -1,11 +1,10 @@
import { ReactNode } from "react";
import { Metadata } from "next";
-import { AdminLayout } from "@/layouts/admin-layout";
export const metadata: Metadata = {
- title: "General Settings - Plane Web",
+ title: "General Settings - God Mode",
};
export default function GeneralLayout({ children }: { children: ReactNode }) {
- return {children};
+ return <>{children}>;
}
diff --git a/admin/app/general/page.tsx b/admin/app/(all)/(dashboard)/general/page.tsx
similarity index 100%
rename from admin/app/general/page.tsx
rename to admin/app/(all)/(dashboard)/general/page.tsx
diff --git a/admin/core/components/auth-header.tsx b/admin/app/(all)/(dashboard)/header.tsx
similarity index 77%
rename from admin/core/components/auth-header.tsx
rename to admin/app/(all)/(dashboard)/header.tsx
index b97dd7c9eae..92bf1021034 100644
--- a/admin/core/components/auth-header.tsx
+++ b/admin/app/(all)/(dashboard)/header.tsx
@@ -3,16 +3,27 @@
import { FC } from "react";
import { observer } from "mobx-react";
import { usePathname } from "next/navigation";
-// mobx
-// ui
-import { Settings } from "lucide-react";
+import { Menu, Settings } from "lucide-react";
// icons
import { Breadcrumbs } from "@plane/ui";
// components
-import { SidebarHamburgerToggle } from "@/components/admin-sidebar";
-import { BreadcrumbLink } from "@/components/common";
+import { BreadcrumbLink } from "@/components/common/breadcrumb-link";
+// hooks
+import { useTheme } from "@/hooks/store";
-export const InstanceHeader: FC = observer(() => {
+export const HamburgerToggle: FC = observer(() => {
+ const { isSidebarCollapsed, toggleSidebar } = useTheme();
+ return (
+ toggleSidebar(!isSidebarCollapsed)}
+ >
+
+
+ );
+});
+
+export const AdminHeader: FC = observer(() => {
const pathName = usePathname();
const getHeaderTitle = (pathName: string) => {
@@ -63,7 +74,7 @@ export const InstanceHeader: FC = observer(() => {
return (
-
+
{breadcrumbItems.length >= 0 && (
diff --git a/admin/app/image/form.tsx b/admin/app/(all)/(dashboard)/image/form.tsx
similarity index 97%
rename from admin/app/image/form.tsx
rename to admin/app/(all)/(dashboard)/image/form.tsx
index 61d2875edaa..be77983ec91 100644
--- a/admin/app/image/form.tsx
+++ b/admin/app/(all)/(dashboard)/image/form.tsx
@@ -4,7 +4,7 @@ import { useForm } from "react-hook-form";
import { IFormattedInstanceConfiguration, TInstanceImageConfigurationKeys } from "@plane/types";
import { Button, TOAST_TYPE, setToast } from "@plane/ui";
// components
-import { ControllerInput } from "@/components/common";
+import { ControllerInput } from "@/components/common/controller-input";
// hooks
import { useInstance } from "@/hooks/store";
diff --git a/admin/app/image/layout.tsx b/admin/app/(all)/(dashboard)/image/layout.tsx
similarity index 62%
rename from admin/app/image/layout.tsx
rename to admin/app/(all)/(dashboard)/image/layout.tsx
index 32233e07837..7ec0ff54b7c 100644
--- a/admin/app/image/layout.tsx
+++ b/admin/app/(all)/(dashboard)/image/layout.tsx
@@ -1,15 +1,14 @@
import { ReactNode } from "react";
import { Metadata } from "next";
-import { AdminLayout } from "@/layouts/admin-layout";
interface ImageLayoutProps {
children: ReactNode;
}
export const metadata: Metadata = {
- title: "Images Settings - Plane Web",
+ title: "Images Settings - God Mode",
};
export default function ImageLayout({ children }: ImageLayoutProps) {
- return {children};
+ return <>{children}>;
}
diff --git a/admin/app/image/page.tsx b/admin/app/(all)/(dashboard)/image/page.tsx
similarity index 100%
rename from admin/app/image/page.tsx
rename to admin/app/(all)/(dashboard)/image/page.tsx
diff --git a/admin/core/layouts/admin-layout.tsx b/admin/app/(all)/(dashboard)/layout.tsx
similarity index 52%
rename from admin/core/layouts/admin-layout.tsx
rename to admin/app/(all)/(dashboard)/layout.tsx
index 88f71aa3c4a..17962378375 100644
--- a/admin/core/layouts/admin-layout.tsx
+++ b/admin/app/(all)/(dashboard)/layout.tsx
@@ -1,20 +1,22 @@
"use client";
+
import { FC, ReactNode, useEffect } from "react";
import { observer } from "mobx-react";
import { useRouter } from "next/navigation";
// components
-import { InstanceSidebar } from "@/components/admin-sidebar";
-import { InstanceHeader } from "@/components/auth-header";
-import { LogoSpinner } from "@/components/common";
+import { LogoSpinner } from "@/components/common/logo-spinner";
import { NewUserPopup } from "@/components/new-user-popup";
// hooks
import { useUser } from "@/hooks/store";
+// local components
+import { AdminHeader } from "./header";
+import { AdminSidebar } from "./sidebar";
type TAdminLayout = {
children: ReactNode;
};
-export const AdminLayout: FC = observer((props) => {
+const AdminLayout: FC = (props) => {
const { children } = props;
// router
const router = useRouter();
@@ -35,14 +37,20 @@ export const AdminLayout: FC = observer((props) => {
);
}
- return (
-
- );
-});
+ if (isUserLoggedIn) {
+ return (
+
+ );
+ }
+
+ return <>>;
+};
+
+export default observer(AdminLayout);
diff --git a/admin/core/components/admin-sidebar/sidebar-dropdown.tsx b/admin/app/(all)/(dashboard)/sidebar-dropdown.tsx
similarity index 99%
rename from admin/core/components/admin-sidebar/sidebar-dropdown.tsx
rename to admin/app/(all)/(dashboard)/sidebar-dropdown.tsx
index 0cde7f5519d..cdce94f0117 100644
--- a/admin/core/components/admin-sidebar/sidebar-dropdown.tsx
+++ b/admin/app/(all)/(dashboard)/sidebar-dropdown.tsx
@@ -16,7 +16,7 @@ import { useTheme, useUser } from "@/hooks/store";
// service initialization
const authService = new AuthService();
-export const SidebarDropdown = observer(() => {
+export const AdminSidebarDropdown = observer(() => {
// store hooks
const { isSidebarCollapsed } = useTheme();
const { currentUser, signOut } = useUser();
diff --git a/admin/core/components/admin-sidebar/help-section.tsx b/admin/app/(all)/(dashboard)/sidebar-help-section.tsx
similarity index 98%
rename from admin/core/components/admin-sidebar/help-section.tsx
rename to admin/app/(all)/(dashboard)/sidebar-help-section.tsx
index d776477497b..cedc735a91e 100644
--- a/admin/core/components/admin-sidebar/help-section.tsx
+++ b/admin/app/(all)/(dashboard)/sidebar-help-section.tsx
@@ -33,7 +33,7 @@ const helpOptions = [
},
];
-export const HelpSection: FC = observer(() => {
+export const AdminSidebarHelpSection: FC = observer(() => {
// states
const [isNeedHelpOpen, setIsNeedHelpOpen] = useState(false);
// store
diff --git a/admin/core/components/admin-sidebar/sidebar-menu.tsx b/admin/app/(all)/(dashboard)/sidebar-menu.tsx
similarity index 98%
rename from admin/core/components/admin-sidebar/sidebar-menu.tsx
rename to admin/app/(all)/(dashboard)/sidebar-menu.tsx
index 618551ae65c..e536a51454f 100644
--- a/admin/core/components/admin-sidebar/sidebar-menu.tsx
+++ b/admin/app/(all)/(dashboard)/sidebar-menu.tsx
@@ -49,7 +49,7 @@ const INSTANCE_ADMIN_LINKS = [
},
];
-export const SidebarMenu = observer(() => {
+export const AdminSidebarMenu = observer(() => {
// store hooks
const { isSidebarCollapsed, toggleSidebar } = useTheme();
// router
diff --git a/admin/core/components/admin-sidebar/root.tsx b/admin/app/(all)/(dashboard)/sidebar.tsx
similarity index 81%
rename from admin/core/components/admin-sidebar/root.tsx
rename to admin/app/(all)/(dashboard)/sidebar.tsx
index 05dde0d8ab1..09dab86eef2 100644
--- a/admin/core/components/admin-sidebar/root.tsx
+++ b/admin/app/(all)/(dashboard)/sidebar.tsx
@@ -4,12 +4,14 @@ import { FC, useEffect, useRef } from "react";
import { observer } from "mobx-react";
// plane helpers
import { useOutsideClickDetector } from "@plane/hooks";
-// components
-import { HelpSection, SidebarMenu, SidebarDropdown } from "@/components/admin-sidebar";
// hooks
import { useTheme } from "@/hooks/store";
+// components
+import { AdminSidebarDropdown } from "./sidebar-dropdown";
+import { AdminSidebarHelpSection } from "./sidebar-help-section";
+import { AdminSidebarMenu } from "./sidebar-menu";
-export const InstanceSidebar: FC = observer(() => {
+export const AdminSidebar: FC = observer(() => {
// store
const { isSidebarCollapsed, toggleSidebar } = useTheme();
@@ -47,9 +49,9 @@ export const InstanceSidebar: FC = observer(() => {
`}
>
);
diff --git a/admin/app/workspace/create/form.tsx b/admin/app/(all)/(dashboard)/workspace/create/form.tsx
similarity index 100%
rename from admin/app/workspace/create/form.tsx
rename to admin/app/(all)/(dashboard)/workspace/create/form.tsx
diff --git a/admin/app/workspace/create/page.tsx b/admin/app/(all)/(dashboard)/workspace/create/page.tsx
similarity index 100%
rename from admin/app/workspace/create/page.tsx
rename to admin/app/(all)/(dashboard)/workspace/create/page.tsx
diff --git a/admin/app/workspace/layout.tsx b/admin/app/(all)/(dashboard)/workspace/layout.tsx
similarity index 56%
rename from admin/app/workspace/layout.tsx
rename to admin/app/(all)/(dashboard)/workspace/layout.tsx
index 9f2a63c67d5..78b0f3c4036 100644
--- a/admin/app/workspace/layout.tsx
+++ b/admin/app/(all)/(dashboard)/workspace/layout.tsx
@@ -1,12 +1,10 @@
import { ReactNode } from "react";
import { Metadata } from "next";
-// layouts
-import { AdminLayout } from "@/layouts/admin-layout";
export const metadata: Metadata = {
- title: "Workspace Management - Plane Web",
+ title: "Workspace Management - God Mode",
};
export default function WorkspaceManagementLayout({ children }: { children: ReactNode }) {
- return
{children};
+ return <>{children}>;
}
diff --git a/admin/app/workspace/page.tsx b/admin/app/(all)/(dashboard)/workspace/page.tsx
similarity index 98%
rename from admin/app/workspace/page.tsx
rename to admin/app/(all)/(dashboard)/workspace/page.tsx
index 3ca34b69e39..b8f79db04a6 100644
--- a/admin/app/workspace/page.tsx
+++ b/admin/app/(all)/(dashboard)/workspace/page.tsx
@@ -10,7 +10,7 @@ import { TInstanceConfigurationKeys } from "@plane/types";
import { Button, getButtonStyling, Loader, setPromiseToast, ToggleSwitch } from "@plane/ui";
import { cn } from "@plane/utils";
// components
-import { WorkspaceListItem } from "@/components/workspace";
+import { WorkspaceListItem } from "@/components/workspace/list-item";
// hooks
import { useInstance, useWorkspace } from "@/hooks/store";
diff --git a/admin/core/components/authentication/auth-banner.tsx b/admin/app/(all)/(home)/auth-banner.tsx
similarity index 100%
rename from admin/core/components/authentication/auth-banner.tsx
rename to admin/app/(all)/(home)/auth-banner.tsx
diff --git a/admin/core/lib/auth-helpers.tsx b/admin/app/(all)/(home)/auth-helpers.tsx
similarity index 93%
rename from admin/core/lib/auth-helpers.tsx
rename to admin/app/(all)/(home)/auth-helpers.tsx
index f9882b5e512..7613548b969 100644
--- a/admin/core/lib/auth-helpers.tsx
+++ b/admin/app/(all)/(home)/auth-helpers.tsx
@@ -7,13 +7,11 @@ import { SUPPORT_EMAIL, EAdminAuthErrorCodes, TAdminAuthErrorInfo } from "@plane
import { TGetBaseAuthenticationModeProps, TInstanceAuthenticationModes } from "@plane/types";
import { resolveGeneralTheme } from "@plane/utils";
// components
-import {
- EmailCodesConfiguration,
- GithubConfiguration,
- GitlabConfiguration,
- GoogleConfiguration,
- PasswordLoginConfiguration,
-} from "@/components/authentication";
+import { EmailCodesConfiguration } from "@/components/authentication/email-config-switch";
+import { GithubConfiguration } from "@/components/authentication/github-config";
+import { GitlabConfiguration } from "@/components/authentication/gitlab-config";
+import { GoogleConfiguration } from "@/components/authentication/google-config";
+import { PasswordLoginConfiguration } from "@/components/authentication/password-config-switch";
// images
import githubLightModeImage from "@/public/logos/github-black.png";
import githubDarkModeImage from "@/public/logos/github-white.png";
diff --git a/admin/core/layouts/default-layout.tsx b/admin/app/(all)/(home)/layout.tsx
similarity index 65%
rename from admin/core/layouts/default-layout.tsx
rename to admin/app/(all)/(home)/layout.tsx
index 1be40ea1296..19cab04cb01 100644
--- a/admin/core/layouts/default-layout.tsx
+++ b/admin/app/(all)/(home)/layout.tsx
@@ -1,26 +1,18 @@
"use client";
-import { FC, ReactNode } from "react";
import Image from "next/image";
import Link from "next/link";
import { useTheme } from "next-themes";
-// logo/ images
+// logo assets
import PlaneBackgroundPatternDark from "public/auth/background-pattern-dark.svg";
import PlaneBackgroundPattern from "public/auth/background-pattern.svg";
import BlackHorizontalLogo from "public/plane-logos/black-horizontal-with-blue-logo.png";
import WhiteHorizontalLogo from "public/plane-logos/white-horizontal-with-blue-logo.png";
-type TDefaultLayout = {
- children: ReactNode;
- withoutBackground?: boolean;
-};
-
-export const DefaultLayout: FC
= (props) => {
- const { children, withoutBackground = false } = props;
- // hooks
+export default function RootLayout({ children }: { children: React.ReactNode }) {
const { resolvedTheme } = useTheme();
- const patternBackground = resolvedTheme === "dark" ? PlaneBackgroundPatternDark : PlaneBackgroundPattern;
+ const patternBackground = resolvedTheme === "light" ? PlaneBackgroundPattern : PlaneBackgroundPatternDark;
const logo = resolvedTheme === "light" ? BlackHorizontalLogo : WhiteHorizontalLogo;
return (
@@ -33,13 +25,11 @@ export const DefaultLayout: FC = (props) => {
- {!withoutBackground && (
-
-
-
- )}
+
+
+
{children}
);
-};
+}
diff --git a/admin/app/(all)/(home)/page.tsx b/admin/app/(all)/(home)/page.tsx
new file mode 100644
index 00000000000..80ea40ee61e
--- /dev/null
+++ b/admin/app/(all)/(home)/page.tsx
@@ -0,0 +1,62 @@
+"use client";
+
+import { observer } from "mobx-react";
+// components
+import { InstanceFailureView } from "@/components/instance/failure";
+import { InstanceLoading } from "@/components/instance/loading";
+import { InstanceSetupForm } from "@/components/instance/setup-form";
+// hooks
+import { useInstance } from "@/hooks/store";
+// components
+import { InstanceSignInForm } from "./sign-in-form";
+
+const HomePage = () => {
+ // store hooks
+ const { instance, error } = useInstance();
+
+ // if instance is not fetched, show loading
+ if (!instance && !error) {
+ return (
+
+
+
+ );
+ }
+
+ // if instance fetch fails, show failure view
+ if (error) {
+ return (
+
+
+
+ );
+ }
+
+ // if instance is fetched and setup is not done, show setup form
+ if (instance && !instance?.is_setup_done) {
+ return (
+
+
+
+ );
+ }
+
+ // if instance is fetched and setup is done, show sign in form
+ return (
+
+
+
+
+ Manage your Plane instance
+
+
+ Configure instance-wide settings to secure your instance
+
+
+
+
+
+ );
+};
+
+export default observer(HomePage);
diff --git a/admin/app/(all)/(home)/sign-in-form.tsx b/admin/app/(all)/(home)/sign-in-form.tsx
new file mode 100644
index 00000000000..12b250a93b9
--- /dev/null
+++ b/admin/app/(all)/(home)/sign-in-form.tsx
@@ -0,0 +1,178 @@
+"use client";
+
+import { FC, useEffect, useMemo, useState } from "react";
+import { useSearchParams } from "next/navigation";
+import { Eye, EyeOff } from "lucide-react";
+// plane internal packages
+import { API_BASE_URL, EAdminAuthErrorCodes, TAdminAuthErrorInfo } from "@plane/constants";
+import { AuthService } from "@plane/services";
+import { Button, Input, Spinner } from "@plane/ui";
+// components
+import { Banner } from "@/components/common/banner";
+// local components
+import { AuthBanner } from "./auth-banner";
+import { authErrorHandler } from "./auth-helpers";
+
+// service initialization
+const authService = new AuthService();
+
+// error codes
+enum EErrorCodes {
+ INSTANCE_NOT_CONFIGURED = "INSTANCE_NOT_CONFIGURED",
+ REQUIRED_EMAIL_PASSWORD = "REQUIRED_EMAIL_PASSWORD",
+ INVALID_EMAIL = "INVALID_EMAIL",
+ USER_DOES_NOT_EXIST = "USER_DOES_NOT_EXIST",
+ AUTHENTICATION_FAILED = "AUTHENTICATION_FAILED",
+}
+
+type TError = {
+ type: EErrorCodes | undefined;
+ message: string | undefined;
+};
+
+// form data
+type TFormData = {
+ email: string;
+ password: string;
+};
+
+const defaultFromData: TFormData = {
+ email: "",
+ password: "",
+};
+
+export const InstanceSignInForm: FC = () => {
+ // search params
+ const searchParams = useSearchParams();
+ const emailParam = searchParams.get("email") || undefined;
+ const errorCode = searchParams.get("error_code") || undefined;
+ const errorMessage = searchParams.get("error_message") || undefined;
+ // state
+ const [showPassword, setShowPassword] = useState(false);
+ const [csrfToken, setCsrfToken] = useState(undefined);
+ const [formData, setFormData] = useState(defaultFromData);
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ const [errorInfo, setErrorInfo] = useState(undefined);
+
+ const handleFormChange = (key: keyof TFormData, value: string | boolean) =>
+ setFormData((prev) => ({ ...prev, [key]: value }));
+
+ useEffect(() => {
+ if (csrfToken === undefined)
+ authService.requestCSRFToken().then((data) => data?.csrf_token && setCsrfToken(data.csrf_token));
+ }, [csrfToken]);
+
+ useEffect(() => {
+ if (emailParam) setFormData((prev) => ({ ...prev, email: emailParam }));
+ }, [emailParam]);
+
+ // derived values
+ const errorData: TError = useMemo(() => {
+ if (errorCode && errorMessage) {
+ switch (errorCode) {
+ case EErrorCodes.INSTANCE_NOT_CONFIGURED:
+ return { type: EErrorCodes.INSTANCE_NOT_CONFIGURED, message: errorMessage };
+ case EErrorCodes.REQUIRED_EMAIL_PASSWORD:
+ return { type: EErrorCodes.REQUIRED_EMAIL_PASSWORD, message: errorMessage };
+ case EErrorCodes.INVALID_EMAIL:
+ return { type: EErrorCodes.INVALID_EMAIL, message: errorMessage };
+ case EErrorCodes.USER_DOES_NOT_EXIST:
+ return { type: EErrorCodes.USER_DOES_NOT_EXIST, message: errorMessage };
+ case EErrorCodes.AUTHENTICATION_FAILED:
+ return { type: EErrorCodes.AUTHENTICATION_FAILED, message: errorMessage };
+ default:
+ return { type: undefined, message: undefined };
+ }
+ } else return { type: undefined, message: undefined };
+ }, [errorCode, errorMessage]);
+
+ const isButtonDisabled = useMemo(
+ () => (!isSubmitting && formData.email && formData.password ? false : true),
+ [formData.email, formData.password, isSubmitting]
+ );
+
+ useEffect(() => {
+ if (errorCode) {
+ const errorDetail = authErrorHandler(errorCode?.toString() as EAdminAuthErrorCodes);
+ if (errorDetail) {
+ setErrorInfo(errorDetail);
+ }
+ }
+ }, [errorCode]);
+
+ return (
+
+ );
+};
diff --git a/admin/app/(all)/instance.provider.tsx b/admin/app/(all)/instance.provider.tsx
new file mode 100644
index 00000000000..ac8fa74e82c
--- /dev/null
+++ b/admin/app/(all)/instance.provider.tsx
@@ -0,0 +1,23 @@
+import { FC, ReactNode } from "react";
+import { observer } from "mobx-react";
+import useSWR from "swr";
+// hooks
+import { useInstance } from "@/hooks/store";
+
+type InstanceProviderProps = {
+ children: ReactNode;
+};
+
+export const InstanceProvider: FC = observer((props) => {
+ const { children } = props;
+ // store hooks
+ const { fetchInstanceInfo } = useInstance();
+ // fetching instance details
+ useSWR("INSTANCE_DETAILS", () => fetchInstanceInfo(), {
+ revalidateOnFocus: false,
+ revalidateIfStale: false,
+ errorRetryCount: 0,
+ });
+
+ return <>{children}>;
+});
diff --git a/admin/app/(all)/layout.tsx b/admin/app/(all)/layout.tsx
new file mode 100644
index 00000000000..ddfba732a91
--- /dev/null
+++ b/admin/app/(all)/layout.tsx
@@ -0,0 +1,33 @@
+"use client";
+
+import { ThemeProvider } from "next-themes";
+import { SWRConfig } from "swr";
+// providers
+import { InstanceProvider } from "./instance.provider";
+import { StoreProvider } from "./store.provider";
+import { ToastWithTheme } from "./toast";
+import { UserProvider } from "./user.provider";
+
+const DEFAULT_SWR_CONFIG = {
+ refreshWhenHidden: false,
+ revalidateIfStale: false,
+ revalidateOnFocus: false,
+ revalidateOnMount: true,
+ refreshInterval: 600000,
+ errorRetryCount: 3,
+};
+
+export default function InstanceLayout({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
+
+
+ {children}
+
+
+
+
+ );
+}
diff --git a/admin/core/lib/store-provider.tsx b/admin/app/(all)/store.provider.tsx
similarity index 100%
rename from admin/core/lib/store-provider.tsx
rename to admin/app/(all)/store.provider.tsx
diff --git a/admin/app/(all)/toast.tsx b/admin/app/(all)/toast.tsx
new file mode 100644
index 00000000000..7d7938a9b16
--- /dev/null
+++ b/admin/app/(all)/toast.tsx
@@ -0,0 +1,10 @@
+"use client";
+
+import { useTheme } from "next-themes";
+import { Toast } from "@plane/ui";
+import { resolveGeneralTheme } from "@plane/utils";
+
+export const ToastWithTheme = () => {
+ const { resolvedTheme } = useTheme();
+ return ;
+};
diff --git a/admin/core/lib/user-provider.tsx b/admin/app/(all)/user.provider.tsx
similarity index 99%
rename from admin/core/lib/user-provider.tsx
rename to admin/app/(all)/user.provider.tsx
index 17d70262797..3a50823dcb7 100644
--- a/admin/core/lib/user-provider.tsx
+++ b/admin/app/(all)/user.provider.tsx
@@ -19,6 +19,7 @@ export const UserProvider: FC = observer(({ children }) => {
useSWR("CURRENT_USER", () => fetchCurrentUser(), {
shouldRetryOnError: false,
});
+
useSWR("INSTANCE_ADMINS", () => fetchInstanceAdmins());
useEffect(() => {
diff --git a/admin/app/layout.tsx b/admin/app/layout.tsx
index b10e9186c3c..e735723695e 100644
--- a/admin/app/layout.tsx
+++ b/admin/app/layout.tsx
@@ -1,22 +1,25 @@
-"use client";
-
import { ReactNode } from "react";
-import { ThemeProvider, useTheme } from "next-themes";
-import { SWRConfig } from "swr";
+import { Metadata } from "next";
// plane imports
-import { ADMIN_BASE_PATH, DEFAULT_SWR_CONFIG } from "@plane/constants";
-import { Toast } from "@plane/ui";
-import { resolveGeneralTheme } from "@plane/utils";
-// lib
-import { InstanceProvider } from "@/lib/instance-provider";
-import { StoreProvider } from "@/lib/store-provider";
-import { UserProvider } from "@/lib/user-provider";
+import { ADMIN_BASE_PATH } from "@plane/constants";
// styles
import "@/styles/globals.css";
-const ToastWithTheme = () => {
- const { resolvedTheme } = useTheme();
- return ;
+export const metadata: Metadata = {
+ title: "Plane | Simple, extensible, open-source project management tool.",
+ description:
+ "Open-source project management tool to manage work items, sprints, and product roadmaps with peace of mind.",
+ openGraph: {
+ title: "Plane | Simple, extensible, open-source project management tool.",
+ description:
+ "Open-source project management tool to manage work items, sprints, and product roadmaps with peace of mind.",
+ url: "https://plane.so/",
+ },
+ keywords:
+ "software development, customer feedback, software, accelerate, code management, release management, project management, work items tracking, agile, scrum, kanban, collaboration",
+ twitter: {
+ site: "@planepowers",
+ },
};
export default function RootLayout({ children }: { children: ReactNode }) {
@@ -30,18 +33,7 @@ export default function RootLayout({ children }: { children: ReactNode }) {
-
-
-
-
-
-
- {children}
-
-
-
-
-
+ {children}