diff --git a/admin/layouts/admin-layout.tsx b/admin/layouts/admin-layout.tsx index 6da565345..bcc103217 100644 --- a/admin/layouts/admin-layout.tsx +++ b/admin/layouts/admin-layout.tsx @@ -39,8 +39,8 @@ export const AdminLayout: FC = observer((props) => {
+
{children}
-
{children}
); diff --git a/space/app/layout.tsx b/space/app/layout.tsx index c62f29246..86e51266f 100644 --- a/space/app/layout.tsx +++ b/space/app/layout.tsx @@ -1,16 +1,11 @@ import { Metadata } from "next"; -// styles -import "@/styles/globals.css"; -// components -import { InstanceNotReady, InstanceFailureView } from "@/components/instance"; // helpers import { ASSET_PREFIX } from "@/helpers/common.helper"; -// lib -import { AppProvider } from "@/lib/app-providers"; -// services -import { InstanceService } from "@/services/instance.service"; - -const instanceService = new InstanceService(); +// components +import { InstanceProvider } from "@/lib/instance-provider"; +import { StoreProvider } from "@/lib/store-provider"; +// styles +import "@/styles/globals.css"; export const metadata: Metadata = { title: "Plane Deploy | Make your Plane boards public with one-click", @@ -27,9 +22,7 @@ export const metadata: Metadata = { }, }; -export default async function RootLayout({ children }: { children: React.ReactNode }) { - const instanceDetails = await instanceService.getInstanceInfo().catch(() => undefined); - +export default function RootLayout({ children }: { children: React.ReactNode }) { return ( @@ -40,21 +33,9 @@ export default async function RootLayout({ children }: { children: React.ReactNo - - {!instanceDetails ? ( - - ) : ( - <> - {instanceDetails.instance.is_setup_done ? ( - <>{children} - ) : ( -
- -
- )} - - )} -
+ + {children} + ); diff --git a/space/app/not-found.tsx b/space/app/not-found.tsx index 468f89a97..cae576319 100644 --- a/space/app/not-found.tsx +++ b/space/app/not-found.tsx @@ -4,7 +4,7 @@ import Image from "next/image"; // assets import UserLoggedInImage from "public/user-logged-in.svg"; -export default function InstanceNotFound() { +export default function NotFound() { return (
diff --git a/space/app/page.tsx b/space/app/page.tsx index e1522b14b..d03300a25 100644 --- a/space/app/page.tsx +++ b/space/app/page.tsx @@ -1,7 +1,5 @@ "use client"; -import { observer } from "mobx-react-lite"; -import useSWR from "swr"; // components import { UserLoggedIn } from "@/components/account"; import { LogoSpinner } from "@/components/common"; @@ -9,15 +7,8 @@ import { AuthView } from "@/components/views"; // hooks import { useUser } from "@/hooks/store"; -function HomePage() { - const { data: currentUser, fetchCurrentUser, isAuthenticated, isLoading } = useUser(); - - useSWR("CURRENT_USER", () => fetchCurrentUser(), { - errorRetryCount: 0, - revalidateIfStale: false, - revalidateOnFocus: false, - refreshWhenHidden: false, - }); +export default function HomePage() { + const { data: currentUser, isAuthenticated, isLoading } = useUser(); if (isLoading) return ; @@ -25,5 +16,3 @@ function HomePage() { return ; } - -export default observer(HomePage); diff --git a/space/components/account/auth-forms/auth-root.tsx b/space/components/account/auth-forms/auth-root.tsx index 273e5bbd5..5be59c5b6 100644 --- a/space/components/account/auth-forms/auth-root.tsx +++ b/space/components/account/auth-forms/auth-root.tsx @@ -43,7 +43,7 @@ export const AuthRoot: FC = observer(() => { const [errorInfo, setErrorInfo] = useState(undefined); const [isPasswordAutoset, setIsPasswordAutoset] = useState(true); // hooks - const { instance } = useInstance(); + const { config } = useInstance(); useEffect(() => { if (error_code) { @@ -67,11 +67,10 @@ export const AuthRoot: FC = observer(() => { } }, [error_code]); - const isSMTPConfigured = instance?.config?.is_smtp_configured || false; - const isMagicLoginEnabled = instance?.config?.is_magic_login_enabled || false; - const isEmailPasswordEnabled = instance?.config?.is_email_password_enabled || false; - const isOAuthEnabled = - (instance?.config && (instance?.config?.is_google_enabled || instance?.config?.is_github_enabled)) || false; + const isSMTPConfigured = config?.is_smtp_configured || false; + const isMagicLoginEnabled = config?.is_magic_login_enabled || false; + const isEmailPasswordEnabled = config?.is_email_password_enabled || false; + const isOAuthEnabled = (config && (config?.is_google_enabled || config?.is_github_enabled)) || false; // submit handler- email verification const handleEmailVerification = async (data: IEmailCheckData) => { diff --git a/space/components/account/oauth/oauth-options.tsx b/space/components/account/oauth/oauth-options.tsx index 779f53925..011c7f189 100644 --- a/space/components/account/oauth/oauth-options.tsx +++ b/space/components/account/oauth/oauth-options.tsx @@ -6,7 +6,7 @@ import { useInstance } from "@/hooks/store"; export const OAuthOptions: React.FC = observer(() => { // hooks - const { instance } = useInstance(); + const { config } = useInstance(); return ( <> @@ -16,12 +16,12 @@ export const OAuthOptions: React.FC = observer(() => {
- {instance?.config?.is_google_enabled && ( + {config?.is_google_enabled && (
)} - {instance?.config?.is_github_enabled && } + {config?.is_github_enabled && }
); diff --git a/space/hooks/store/use-instance.ts b/space/hooks/store/use-instance.ts index 62aa0baae..455bc5ca0 100644 --- a/space/hooks/store/use-instance.ts +++ b/space/hooks/store/use-instance.ts @@ -1,6 +1,6 @@ import { useContext } from "react"; // lib -import { StoreContext } from "@/lib/app-providers"; +import { StoreContext } from "@/lib/store-provider"; // store import { IInstanceStore } from "@/store/instance.store"; diff --git a/space/hooks/store/use-issue-details.tsx b/space/hooks/store/use-issue-details.tsx index 56ee48627..fc708fdbd 100644 --- a/space/hooks/store/use-issue-details.tsx +++ b/space/hooks/store/use-issue-details.tsx @@ -1,6 +1,6 @@ import { useContext } from "react"; // lib -import { StoreContext } from "@/lib/app-providers"; +import { StoreContext } from "@/lib/store-provider"; // store import { IIssueDetailStore } from "@/store/issue-detail.store"; diff --git a/space/hooks/store/use-issue-filter.ts b/space/hooks/store/use-issue-filter.ts index a80d9761b..c35b01c64 100644 --- a/space/hooks/store/use-issue-filter.ts +++ b/space/hooks/store/use-issue-filter.ts @@ -1,6 +1,6 @@ import { useContext } from "react"; // lib -import { StoreContext } from "@/lib/app-providers"; +import { StoreContext } from "@/lib/store-provider"; // store import { IIssueFilterStore } from "@/store/issue-filters.store"; diff --git a/space/hooks/store/use-issue.ts b/space/hooks/store/use-issue.ts index 8ccd95ac4..641f05acf 100644 --- a/space/hooks/store/use-issue.ts +++ b/space/hooks/store/use-issue.ts @@ -1,6 +1,6 @@ import { useContext } from "react"; // lib -import { StoreContext } from "@/lib/app-providers"; +import { StoreContext } from "@/lib/store-provider"; // store import { IIssueStore } from "@/store/issue.store"; diff --git a/space/hooks/store/use-project.ts b/space/hooks/store/use-project.ts index 0bc7d8f8a..cd3e28958 100644 --- a/space/hooks/store/use-project.ts +++ b/space/hooks/store/use-project.ts @@ -1,6 +1,6 @@ import { useContext } from "react"; // lib -import { StoreContext } from "@/lib/app-providers"; +import { StoreContext } from "@/lib/store-provider"; // store import { IProjectStore } from "@/store/project.store"; diff --git a/space/hooks/store/use-user-profile.ts b/space/hooks/store/use-user-profile.ts index 042f16c0d..253fec5d6 100644 --- a/space/hooks/store/use-user-profile.ts +++ b/space/hooks/store/use-user-profile.ts @@ -1,6 +1,6 @@ import { useContext } from "react"; // lib -import { StoreContext } from "@/lib/app-providers"; +import { StoreContext } from "@/lib/store-provider"; // store import { IProfileStore } from "@/store/profile.store"; diff --git a/space/hooks/store/use-user.ts b/space/hooks/store/use-user.ts index c935946f8..7d48e5c7f 100644 --- a/space/hooks/store/use-user.ts +++ b/space/hooks/store/use-user.ts @@ -1,6 +1,6 @@ import { useContext } from "react"; // lib -import { StoreContext } from "@/lib/app-providers"; +import { StoreContext } from "@/lib/store-provider"; // store import { IUserStore } from "@/store/user.store"; diff --git a/space/lib/instance-provider.tsx b/space/lib/instance-provider.tsx new file mode 100644 index 000000000..032bc5ae9 --- /dev/null +++ b/space/lib/instance-provider.tsx @@ -0,0 +1,63 @@ +"use client"; + +import { ReactNode } from "react"; +import { observer } from "mobx-react-lite"; +import Image from "next/image"; +import { useTheme } from "next-themes"; +import useSWR from "swr"; +// components +import { LogoSpinner } from "@/components/common"; +import { InstanceFailureView } from "@/components/instance"; +// hooks +import { useInstance, useUser } from "@/hooks/store"; +// assets +import PlaneBackgroundPatternDark from "public/auth/background-pattern-dark.svg"; +import PlaneBackgroundPattern from "public/auth/background-pattern.svg"; +import BluePlaneLogoWithoutText from "public/plane-logos/blue-without-text.png"; + +export const InstanceProvider = observer(({ children }: { children: ReactNode }) => { + const { fetchInstanceInfo, instance, error } = useInstance(); + const { fetchCurrentUser } = useUser(); + const { resolvedTheme } = useTheme(); + + const patternBackground = resolvedTheme === "dark" ? PlaneBackgroundPatternDark : PlaneBackgroundPattern; + + useSWR("INSTANCE_INFO", () => fetchInstanceInfo(), { + revalidateOnFocus: false, + revalidateIfStale: false, + errorRetryCount: 0, + }); + useSWR("CURRENT_USER", () => fetchCurrentUser()); + + if (!instance && !error) + return ( +
+ +
+ ); + + if (error) { + return ( +
+
+
+
+ Plane Logo + Plane +
+
+
+ Plane background pattern +
+
+
+ +
+
+
+
+ ); + } + + return <>{children}; +}); diff --git a/space/lib/app-providers.tsx b/space/lib/store-provider.tsx similarity index 84% rename from space/lib/app-providers.tsx rename to space/lib/store-provider.tsx index 389d68ab2..b77a981f8 100644 --- a/space/lib/app-providers.tsx +++ b/space/lib/store-provider.tsx @@ -23,12 +23,13 @@ function initializeStore(initialData = {}) { return singletonRootStore; } -export type AppProviderProps = { +export type StoreProviderProps = { children: ReactNode; - initialState: any; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + initialState?: any; }; -export const AppProvider = ({ children, initialState = {} }: AppProviderProps) => { +export const StoreProvider = ({ children, initialState = {} }: StoreProviderProps) => { const store = initializeStore(initialState); return ( diff --git a/space/lib/user-provider.tsx b/space/lib/user-provider.tsx new file mode 100644 index 000000000..1ac1c786c --- /dev/null +++ b/space/lib/user-provider.tsx @@ -0,0 +1,12 @@ +import { ReactNode } from "react"; +import { observer } from "mobx-react-lite"; +import useSWR from "swr"; +import { useUser } from "@/hooks/store"; + +export const UserProvider = observer(({ children }: { children: ReactNode }) => { + const { fetchCurrentUser } = useUser(); + + useSWR("CURRENT_USER", () => fetchCurrentUser()); + + return <>{children}; +}); diff --git a/space/lib/wrappers/auth-wrapper.tsx b/space/lib/wrappers/auth-wrapper.tsx deleted file mode 100644 index 840ce4ba2..000000000 --- a/space/lib/wrappers/auth-wrapper.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { FC, ReactNode } from "react"; -import { observer } from "mobx-react-lite"; -import { useRouter } from "next/navigation"; -import useSWR from "swr"; -import { Spinner } from "@plane/ui"; -// helpers -import { EPageTypes } from "@/helpers/authentication.helper"; -// hooks -import { useUser, useUserProfile } from "@/hooks/store"; - -type TAuthWrapper = { - children: ReactNode; - pageType?: EPageTypes; -}; - -export const AuthWrapper: FC = observer((props) => { - const router = useRouter(); - const { children, pageType = EPageTypes.AUTHENTICATED } = props; - // hooks - const { isLoading, data: currentUser, fetchCurrentUser } = useUser(); - const { data: currentUserProfile } = useUserProfile(); - - const { isLoading: isSWRLoading } = useSWR("INSTANCE_INFORMATION", () => fetchCurrentUser(), { - revalidateOnFocus: false, - }); - - if (isSWRLoading || isLoading) - return ( -
- -
- ); - - if (pageType === EPageTypes.PUBLIC) return <>{children}; - - if (pageType === EPageTypes.INIT) { - if (!currentUser?.id) return <>{children}; - else { - if ( - currentUserProfile && - currentUserProfile?.id && - Boolean(currentUserProfile?.onboarding_step?.profile_complete) - ) - return <>{children}; - else { - router.push(`/onboarding`); - return <>; - } - } - } - - if (pageType === EPageTypes.NON_AUTHENTICATED) { - if (!currentUser?.id) return <>{children}; - else { - if (currentUserProfile?.id && currentUserProfile?.onboarding_step?.profile_complete) { - router.push(`/`); - return <>; - } else { - router.push(`/onboarding`); - return <>; - } - } - } - - if (pageType === EPageTypes.ONBOARDING) { - if (!currentUser?.id) { - router.push(`/`); - return <>; - } else { - if (currentUserProfile?.id && currentUserProfile?.onboarding_step?.profile_complete) { - router.push(`/`); - return <>; - } else return <>{children}; - } - } - - if (pageType === EPageTypes.AUTHENTICATED) { - if (!currentUser?.id) return <>{children}; - else { - if (currentUserProfile?.id && currentUserProfile?.onboarding_step?.profile_complete) return <>{children}; - else { - router.push(`/onboarding`); - return <>; - } - } - } - - return <>{children}; -}); diff --git a/space/lib/wrappers/index.ts b/space/lib/wrappers/index.ts deleted file mode 100644 index d40c4c886..000000000 --- a/space/lib/wrappers/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./auth-wrapper"; diff --git a/space/services/instance.service.ts b/space/services/instance.service.ts index 7744f1f65..a11599b0c 100644 --- a/space/services/instance.service.ts +++ b/space/services/instance.service.ts @@ -1,5 +1,5 @@ // types -import type { IInstance } from "@plane/types"; +import type { IInstanceInfo } from "@plane/types"; // helpers import { API_BASE_URL } from "@/helpers/common.helper"; // services @@ -10,7 +10,7 @@ export class InstanceService extends APIService { super(API_BASE_URL); } - async getInstanceInfo(): Promise { + async getInstanceInfo(): Promise { return this.get("/api/instances/") .then((response) => response.data) .catch((error) => { diff --git a/space/store/instance.store.ts b/space/store/instance.store.ts index 98bb4cfe0..d2e6918a3 100644 --- a/space/store/instance.store.ts +++ b/space/store/instance.store.ts @@ -1,7 +1,7 @@ import set from "lodash/set"; import { observable, action, makeObservable, runInAction } from "mobx"; // types -import { IInstance } from "@plane/types"; +import { IInstance, IInstanceConfig } from "@plane/types"; // services import { InstanceService } from "@/services/instance.service"; // store types @@ -20,6 +20,7 @@ export interface IInstanceStore { // observables isLoading: boolean; instance: IInstance | undefined; + config: IInstanceConfig | undefined; error: TError | undefined; // action fetchInstanceInfo: () => Promise; @@ -29,6 +30,7 @@ export interface IInstanceStore { export class InstanceStore implements IInstanceStore { isLoading: boolean = true; instance: IInstance | undefined = undefined; + config: IInstanceConfig | undefined = undefined; error: TError | undefined = undefined; // services instanceService; @@ -38,6 +40,7 @@ export class InstanceStore implements IInstanceStore { // observable isLoading: observable.ref, instance: observable, + config: observable, error: observable, // actions fetchInstanceInfo: action, @@ -56,10 +59,11 @@ export class InstanceStore implements IInstanceStore { try { this.isLoading = true; this.error = undefined; - const instance = await this.instanceService.getInstanceInfo(); + const instanceInfo = await this.instanceService.getInstanceInfo(); runInAction(() => { this.isLoading = false; - this.instance = instance; + this.instance = instanceInfo.instance; + this.config = instanceInfo.config; }); } catch (error) { runInAction(() => { diff --git a/web/components/account/auth-forms/auth-root.tsx b/web/components/account/auth-forms/auth-root.tsx index 8b9df7632..4e4d6be24 100644 --- a/web/components/account/auth-forms/auth-root.tsx +++ b/web/components/account/auth-forms/auth-root.tsx @@ -44,7 +44,7 @@ export const AuthRoot: FC = observer((props) => { const [errorInfo, setErrorInfo] = useState(undefined); const [isPasswordAutoset, setIsPasswordAutoset] = useState(true); // hooks - const { instance } = useInstance(); + const { config } = useInstance(); useEffect(() => { if (error_code) { @@ -68,9 +68,9 @@ export const AuthRoot: FC = observer((props) => { } }, [error_code, authMode]); - const isSMTPConfigured = instance?.config?.is_smtp_configured || false; - const isMagicLoginEnabled = instance?.config?.is_magic_login_enabled || false; - const isEmailPasswordEnabled = instance?.config?.is_email_password_enabled || false; + const isSMTPConfigured = config?.is_smtp_configured || false; + const isMagicLoginEnabled = config?.is_magic_login_enabled || false; + const isEmailPasswordEnabled = config?.is_email_password_enabled || false; // submit handler- email verification const handleEmailVerification = async (data: IEmailCheckData) => { diff --git a/web/components/account/oauth/oauth-options.tsx b/web/components/account/oauth/oauth-options.tsx index 960b48adf..8541def90 100644 --- a/web/components/account/oauth/oauth-options.tsx +++ b/web/components/account/oauth/oauth-options.tsx @@ -11,10 +11,9 @@ type TOAuthOptionProps = { export const OAuthOptions: React.FC = observer((props) => { const { isSignUp = false } = props; // hooks - const { instance } = useInstance(); + const { config } = useInstance(); - const isOAuthEnabled = - (instance?.config && (instance?.config?.is_google_enabled || instance?.config?.is_github_enabled)) || false; + const isOAuthEnabled = (config && (config?.is_google_enabled || config?.is_github_enabled)) || false; if (!isOAuthEnabled) return null; @@ -28,12 +27,12 @@ export const OAuthOptions: React.FC = observer((props) => {
- {instance?.config?.is_google_enabled && ( + {config?.is_google_enabled && (
)} - {instance?.config?.is_github_enabled && } + {config?.is_github_enabled && }
); diff --git a/web/components/core/image-picker-popover.tsx b/web/components/core/image-picker-popover.tsx index 11f9e6d2d..4a080fb70 100644 --- a/web/components/core/image-picker-popover.tsx +++ b/web/components/core/image-picker-popover.tsx @@ -62,7 +62,7 @@ export const ImagePickerPopover: React.FC = observer((props) => { const router = useRouter(); const { workspaceSlug } = router.query; // store hooks - const { instance } = useInstance(); + const { config } = useInstance(); const { currentWorkspace } = useWorkspace(); const { data: unsplashImages, error: unsplashError } = useSWR( @@ -90,7 +90,7 @@ export const ImagePickerPopover: React.FC = observer((props) => { accept: { "image/*": [".png", ".jpg", ".jpeg", ".svg", ".webp"], }, - maxSize: instance?.config?.file_size_limit ?? MAX_FILE_SIZE, + maxSize: config?.file_size_limit ?? MAX_FILE_SIZE, }); const handleSubmit = async () => { diff --git a/web/components/core/modals/user-image-upload-modal.tsx b/web/components/core/modals/user-image-upload-modal.tsx index dabe3561d..03b4d4e04 100644 --- a/web/components/core/modals/user-image-upload-modal.tsx +++ b/web/components/core/modals/user-image-upload-modal.tsx @@ -30,7 +30,7 @@ export const UserImageUploadModal: React.FC = observer((props) => { const [image, setImage] = useState(null); const [isImageUploading, setIsImageUploading] = useState(false); // store hooks - const { instance } = useInstance(); + const { config } = useInstance(); const onDrop = (acceptedFiles: File[]) => setImage(acceptedFiles[0]); @@ -39,7 +39,7 @@ export const UserImageUploadModal: React.FC = observer((props) => { accept: { "image/*": [".png", ".jpg", ".jpeg", ".svg", ".webp"], }, - maxSize: instance?.config?.file_size_limit ?? MAX_FILE_SIZE, + maxSize: config?.file_size_limit ?? MAX_FILE_SIZE, multiple: false, }); diff --git a/web/components/core/modals/workspace-image-upload-modal.tsx b/web/components/core/modals/workspace-image-upload-modal.tsx index 7c21ff814..878217780 100644 --- a/web/components/core/modals/workspace-image-upload-modal.tsx +++ b/web/components/core/modals/workspace-image-upload-modal.tsx @@ -34,7 +34,7 @@ export const WorkspaceImageUploadModal: React.FC = observer((props) => { const router = useRouter(); const { workspaceSlug } = router.query; // store hooks - const { instance } = useInstance(); + const { config } = useInstance(); const { currentWorkspace } = useWorkspace(); const onDrop = (acceptedFiles: File[]) => setImage(acceptedFiles[0]); @@ -44,7 +44,7 @@ export const WorkspaceImageUploadModal: React.FC = observer((props) => { accept: { "image/*": [".png", ".jpg", ".jpeg", ".svg", ".webp"], }, - maxSize: instance?.config?.file_size_limit ?? MAX_FILE_SIZE, + maxSize: config?.file_size_limit ?? MAX_FILE_SIZE, multiple: false, }); diff --git a/web/components/integration/github/auth.tsx b/web/components/integration/github/auth.tsx index b4fb6bb57..ff2ee9550 100644 --- a/web/components/integration/github/auth.tsx +++ b/web/components/integration/github/auth.tsx @@ -14,12 +14,12 @@ type Props = { export const GithubAuth: React.FC = observer(({ workspaceIntegration, provider }) => { // store hooks - const { instance } = useInstance(); + const { config } = useInstance(); // hooks const { startAuth, isConnecting } = useIntegrationPopup({ provider, - github_app_name: instance?.config?.github_app_name || "", - slack_client_id: instance?.config?.slack_client_id || "", + github_app_name: config?.github_app_name || "", + slack_client_id: config?.slack_client_id || "", }); return ( diff --git a/web/components/integration/single-integration-card.tsx b/web/components/integration/single-integration-card.tsx index c629e7b04..2697bf6cd 100644 --- a/web/components/integration/single-integration-card.tsx +++ b/web/components/integration/single-integration-card.tsx @@ -46,7 +46,7 @@ export const SingleIntegrationCard: React.FC = observer(({ integration }) const router = useRouter(); const { workspaceSlug } = router.query; // store hooks - const { instance } = useInstance(); + const { config } = useInstance(); const { membership: { currentWorkspaceRole }, } = useUser(); @@ -55,8 +55,8 @@ export const SingleIntegrationCard: React.FC = observer(({ integration }) const { isMobile } = usePlatformOS(); const { startAuth, isConnecting: isInstalling } = useIntegrationPopup({ provider: integration.provider, - github_app_name: instance?.config?.github_app_name || "", - slack_client_id: instance?.config?.slack_client_id || "", + github_app_name: config?.github_app_name || "", + slack_client_id: config?.slack_client_id || "", }); const { data: workspaceIntegrations } = useSWR( diff --git a/web/components/integration/slack/select-channel.tsx b/web/components/integration/slack/select-channel.tsx index e2c5c0e6a..19275fc1f 100644 --- a/web/components/integration/slack/select-channel.tsx +++ b/web/components/integration/slack/select-channel.tsx @@ -22,7 +22,7 @@ const appInstallationService = new AppInstallationService(); export const SelectChannel: React.FC = observer(({ integration }) => { // store hooks - const { instance } = useInstance(); + const { config } = useInstance(); // states const [slackChannelAvailabilityToggle, setSlackChannelAvailabilityToggle] = useState(false); const [slackChannel, setSlackChannel] = useState(null); @@ -35,7 +35,7 @@ export const SelectChannel: React.FC = observer(({ integration }) => { provider: "slackChannel", stateParams: integration.id, // github_app_name: instance?.config?.github_client_id || "", - slack_client_id: instance?.config?.slack_client_id || "", + slack_client_id: config?.slack_client_id || "", }); const { data: projectIntegration } = useSWR( diff --git a/web/components/issues/attachment/attachment-upload.tsx b/web/components/issues/attachment/attachment-upload.tsx index b5061d8ef..4be4cf11b 100644 --- a/web/components/issues/attachment/attachment-upload.tsx +++ b/web/components/issues/attachment/attachment-upload.tsx @@ -21,7 +21,7 @@ type Props = { export const IssueAttachmentUpload: React.FC = observer((props) => { const { workspaceSlug, disabled = false, handleAttachmentOperations } = props; // store hooks - const { instance } = useInstance(); + const { config } = useInstance(); // states const [isLoading, setIsLoading] = useState(false); @@ -50,12 +50,12 @@ export const IssueAttachmentUpload: React.FC = observer((props) => { const { getRootProps, getInputProps, isDragActive, isDragReject, fileRejections } = useDropzone({ onDrop, - maxSize: instance?.config?.file_size_limit ?? MAX_FILE_SIZE, + maxSize: config?.file_size_limit ?? MAX_FILE_SIZE, multiple: false, disabled: isLoading || disabled, }); - const maxFileSize = instance?.config?.file_size_limit ?? MAX_FILE_SIZE; + const maxFileSize = config?.file_size_limit ?? MAX_FILE_SIZE; const fileError = fileRejections.length > 0 ? `Invalid file type or size (max ${maxFileSize / 1024 / 1024} MB)` : null; diff --git a/web/components/issues/issue-modal/form.tsx b/web/components/issues/issue-modal/form.tsx index 62b18dc15..4c608f83a 100644 --- a/web/components/issues/issue-modal/form.tsx +++ b/web/components/issues/issue-modal/form.tsx @@ -116,7 +116,7 @@ export const IssueFormRoot: FC = observer((props) => { const workspaceStore = useWorkspace(); const workspaceId = workspaceStore.getWorkspaceBySlug(workspaceSlug as string)?.id as string; const { projectId: routeProjectId } = useAppRouter(); - const { instance } = useInstance(); + const { config } = useInstance(); const { getProjectById } = useProject(); const { areEstimatesEnabledForProject } = useEstimate(); @@ -410,7 +410,7 @@ export const IssueFormRoot: FC = observer((props) => { ) : ( <>
- {issueName && issueName.trim() !== "" && instance?.config?.has_openai_configured && ( + {issueName && issueName.trim() !== "" && config?.has_openai_configured && ( )} - {instance?.config?.has_openai_configured && ( + {config?.has_openai_configured && ( = observer((props) => { // states const [gptModalOpen, setGptModal] = useState(false); // store hooks - const { instance } = useInstance(); + const { config } = useInstance(); // derived values const { archived_at, isContentEditable, isSubmitting, is_locked } = pageStore; @@ -69,7 +69,7 @@ export const PageExtraOptions: React.FC = observer((props) => { Archived at {renderFormattedDate(archived_at)}
)} - {isContentEditable && instance?.config?.has_openai_configured && ( + {isContentEditable && config?.has_openai_configured && ( = observer((props) => { const { children } = props; // store hooks - const { instance } = useInstance(); + const { config } = useInstance(); const { data: currentUser, membership: { currentProjectRole, currentWorkspaceRole }, @@ -53,8 +53,8 @@ export const AppProvider: FC = observer((props) => { currentWorkspaceId={currentWorkspace?.id} workspaceRole={currentWorkspaceRole} projectRole={currentProjectRole} - posthogAPIKey={instance?.config?.posthog_api_key || undefined} - posthogHost={instance?.config?.posthog_host || undefined} + posthogAPIKey={config?.posthog_api_key || undefined} + posthogHost={config?.posthog_host || undefined} > {children} diff --git a/web/lib/wrappers/instance-wrapper.tsx b/web/lib/wrappers/instance-wrapper.tsx index 2945bb9e2..c0343a9e1 100644 --- a/web/lib/wrappers/instance-wrapper.tsx +++ b/web/lib/wrappers/instance-wrapper.tsx @@ -32,7 +32,7 @@ export const InstanceWrapper: FC = observer((props) => { if (error && error?.status === "error") return <>{children}; // instance is not ready and setup is not done - if (instance?.instance?.is_setup_done === false) return ; + if (instance?.is_setup_done === false) return ; return <>{children}; }); diff --git a/web/services/instance.service.ts b/web/services/instance.service.ts index 0e22e58a7..450a7b735 100644 --- a/web/services/instance.service.ts +++ b/web/services/instance.service.ts @@ -1,5 +1,5 @@ // types -import type { IInstance } from "@plane/types"; +import type { IInstanceInfo } from "@plane/types"; // helpers import { API_BASE_URL } from "@/helpers/common.helper"; // services @@ -18,7 +18,7 @@ export class InstanceService extends APIService { }); } - async getInstanceInfo(): Promise { + async getInstanceInfo(): Promise { return this.get("/api/instances/") .then((response) => response.data) .catch((error) => { diff --git a/web/store/instance.store.ts b/web/store/instance.store.ts index aedd96e03..ca813ca17 100644 --- a/web/store/instance.store.ts +++ b/web/store/instance.store.ts @@ -1,6 +1,6 @@ import { observable, action, makeObservable, runInAction } from "mobx"; // types -import { IInstance } from "@plane/types"; +import { IInstance, IInstanceConfig } from "@plane/types"; // services import { InstanceService } from "@/services/instance.service"; @@ -17,6 +17,7 @@ export interface IInstanceStore { // issues isLoading: boolean; instance: IInstance | undefined; + config: IInstanceConfig | undefined; error: TError | undefined; // action fetchInstanceInfo: () => Promise; @@ -25,6 +26,7 @@ export interface IInstanceStore { export class InstanceStore implements IInstanceStore { isLoading: boolean = true; instance: IInstance | undefined = undefined; + config: IInstanceConfig | undefined = undefined; error: TError | undefined = undefined; // services instanceService; @@ -34,6 +36,7 @@ export class InstanceStore implements IInstanceStore { // observable isLoading: observable.ref, instance: observable, + config: observable, error: observable, // actions fetchInstanceInfo: action, @@ -49,10 +52,11 @@ export class InstanceStore implements IInstanceStore { try { this.isLoading = true; this.error = undefined; - const instance = await this.instanceService.getInstanceInfo(); + const instanceInfo = await this.instanceService.getInstanceInfo(); runInAction(() => { this.isLoading = false; - this.instance = instance; + this.instance = instanceInfo.instance; + this.config = instanceInfo.config; }); } catch (error) { runInAction(() => {