diff --git a/admin/app/ai/layout.tsx b/admin/app/ai/layout.tsx index e3fd537bc..0a0bacac1 100644 --- a/admin/app/ai/layout.tsx +++ b/admin/app/ai/layout.tsx @@ -1,9 +1,11 @@ -"use client"; - import { ReactNode } from "react"; -// layouts +import { Metadata } from "next"; import { AdminLayout } from "@/layouts/admin-layout"; +export const metadata: Metadata = { + title: "AI Settings - God Mode", +}; + export default function AILayout({ children }: { children: ReactNode }) { return {children}; } diff --git a/admin/app/authentication/layout.tsx b/admin/app/authentication/layout.tsx index 2568859db..64506ddb4 100644 --- a/admin/app/authentication/layout.tsx +++ b/admin/app/authentication/layout.tsx @@ -1,9 +1,11 @@ -"use client"; - import { ReactNode } from "react"; -// layouts +import { Metadata } from "next"; import { AdminLayout } from "@/layouts/admin-layout"; +export const metadata: Metadata = { + title: "Authentication Settings - God Mode", +}; + export default function AuthenticationLayout({ children }: { children: ReactNode }) { return {children}; } diff --git a/admin/app/email/layout.tsx b/admin/app/email/layout.tsx index 626c5d557..64f019ec9 100644 --- a/admin/app/email/layout.tsx +++ b/admin/app/email/layout.tsx @@ -1,13 +1,15 @@ -"use client"; - import { ReactNode } from "react"; -// layouts +import { Metadata } from "next"; import { AdminLayout } from "@/layouts/admin-layout"; interface EmailLayoutProps { children: ReactNode; } +export const metadata: Metadata = { + title: "Email Settings - God Mode", +}; + const EmailLayout = ({ children }: EmailLayoutProps) => {children}; export default EmailLayout; diff --git a/admin/app/general/form.tsx b/admin/app/general/form.tsx index 09079028d..5646084e2 100644 --- a/admin/app/general/form.tsx +++ b/admin/app/general/form.tsx @@ -13,7 +13,7 @@ import { ControllerInput } from "@/components/common"; import { useInstance } from "@/hooks/store"; export interface IGeneralConfigurationForm { - instance: IInstance["instance"]; + instance: IInstance; instanceAdmins: IInstanceAdmin[]; } @@ -26,15 +26,15 @@ export const GeneralConfigurationForm: FC = observer( handleSubmit, control, formState: { errors, isSubmitting }, - } = useForm>({ + } = useForm>({ defaultValues: { instance_name: instance?.instance_name, is_telemetry_enabled: instance?.is_telemetry_enabled, }, }); - const onSubmit = async (formData: Partial) => { - const payload: Partial = { ...formData }; + const onSubmit = async (formData: Partial) => { + const payload: Partial = { ...formData }; console.log("payload", payload); diff --git a/admin/app/general/layout.tsx b/admin/app/general/layout.tsx index 371264e92..fabbe3640 100644 --- a/admin/app/general/layout.tsx +++ b/admin/app/general/layout.tsx @@ -1,6 +1,5 @@ import { ReactNode } from "react"; import { Metadata } from "next"; -// components import { AdminLayout } from "@/layouts/admin-layout"; export const metadata: Metadata = { diff --git a/admin/app/general/page.tsx b/admin/app/general/page.tsx index 399482ea6..bab2a94fc 100644 --- a/admin/app/general/page.tsx +++ b/admin/app/general/page.tsx @@ -7,7 +7,7 @@ import { GeneralConfigurationForm } from "./form"; function GeneralPage() { const { instance, instanceAdmins } = useInstance(); - console.log("instance", instanceAdmins); + console.log("instance", instance); return ( <>
@@ -19,8 +19,8 @@ function GeneralPage() {
- {instance?.instance && instanceAdmins && ( - + {instance && instanceAdmins && ( + )}
diff --git a/admin/app/image/layout.tsx b/admin/app/image/layout.tsx index 039c10202..18e9343b5 100644 --- a/admin/app/image/layout.tsx +++ b/admin/app/image/layout.tsx @@ -1,11 +1,15 @@ import { ReactNode } from "react"; -// layouts +import { Metadata } from "next"; import { AdminLayout } from "@/layouts/admin-layout"; interface ImageLayoutProps { children: ReactNode; } +export const metadata: Metadata = { + title: "Images Settings - God Mode", +}; + const ImageLayout = ({ children }: ImageLayoutProps) => {children}; export default ImageLayout; diff --git a/admin/app/layout.tsx b/admin/app/layout.tsx index e2879a565..865eb23f9 100644 --- a/admin/app/layout.tsx +++ b/admin/app/layout.tsx @@ -1,40 +1,20 @@ +"use client"; + import { ReactNode } from "react"; -import { Metadata } from "next"; -// components -import { InstanceFailureView, InstanceSetupForm } from "@/components/instance"; +import { ThemeProvider } from "next-themes"; +import { SWRConfig } from "swr"; +// constants +import { SWR_CONFIG } from "@/constants/swr-config"; // helpers import { ASSET_PREFIX } from "@/helpers/common.helper"; -// layout -import { DefaultLayout } from "@/layouts/default-layout"; // lib -import { AppProvider } from "@/lib/app-providers"; +import { InstanceProvider } from "@/lib/instance-provider"; +import { StoreProvider } from "@/lib/store-provider"; +import { UserProvider } from "@/lib/user-provider"; // styles import "./globals.css"; -// services -import { InstanceService } from "@/services/instance.service"; - -const instanceService = new InstanceService(); - -export const metadata: Metadata = { - title: "Plane | Simple, extensible, open-source project management tool.", - description: - "Open-source project management tool to manage issues, 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 issues, 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, issue tracking, agile, scrum, kanban, collaboration", - twitter: { - site: "@planepowers", - }, -}; - -export default async function RootLayout({ children }: { children: ReactNode }) { - const instanceDetails = await instanceService.getInstanceInfo().catch(() => null); +function RootLayout({ children }: { children: ReactNode }) { return ( @@ -45,28 +25,18 @@ export default async function RootLayout({ children }: { children: ReactNode }) - - {instanceDetails ? ( - <> - {instanceDetails?.instance?.is_setup_done ? ( - <>{children} - ) : ( - -
- -
-
- )} - - ) : ( - -
- -
-
- )} -
+ + + + + {children} + + + + ); } + +export default RootLayout; diff --git a/admin/app/page.tsx b/admin/app/page.tsx index c7e6b975e..b402fc44d 100644 --- a/admin/app/page.tsx +++ b/admin/app/page.tsx @@ -1,7 +1,26 @@ +import { Metadata } from "next"; +// components import { InstanceSignInForm } from "@/components/login"; // layouts import { DefaultLayout } from "@/layouts/default-layout"; +export const metadata: Metadata = { + title: "Plane | Simple, extensible, open-source project management tool.", + description: + "Open-source project management tool to manage issues, 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 issues, 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, issue tracking, agile, scrum, kanban, collaboration", + twitter: { + site: "@planepowers", + }, +}; + export default async function LoginPage() { return ( diff --git a/admin/components/common/index.ts b/admin/components/common/index.ts index 005711a62..c810cac69 100644 --- a/admin/components/common/index.ts +++ b/admin/components/common/index.ts @@ -6,3 +6,4 @@ export * from "./password-strength-meter"; export * from "./banner"; export * from "./empty-state"; export * from "./logo-spinner"; +export * from "./toast"; diff --git a/admin/components/common/logo-spinner.tsx b/admin/components/common/logo-spinner.tsx index 69bb9423d..621b685b8 100644 --- a/admin/components/common/logo-spinner.tsx +++ b/admin/components/common/logo-spinner.tsx @@ -11,7 +11,7 @@ export const LogoSpinner = () => { return (
- logo + logo
); }; diff --git a/admin/components/common/password-strength-meter.tsx b/admin/components/common/password-strength-meter.tsx index 5cdba30b7..004a927b2 100644 --- a/admin/components/common/password-strength-meter.tsx +++ b/admin/components/common/password-strength-meter.tsx @@ -43,7 +43,7 @@ export const PasswordStrengthMeter: React.FC = (props: Props) => { ]; return ( -
+
{bars.map((color, index) => (
diff --git a/admin/components/common/toast.tsx b/admin/components/common/toast.tsx new file mode 100644 index 000000000..fe4983db6 --- /dev/null +++ b/admin/components/common/toast.tsx @@ -0,0 +1,11 @@ +import { useTheme } from "next-themes"; +// ui +import { Toast as ToastComponent } from "@plane/ui"; +// helpers +import { resolveGeneralTheme } from "@/helpers/common.helper"; + +export const Toast = () => { + const { theme } = useTheme(); + + return ; +}; diff --git a/admin/components/new-user-popup.tsx b/admin/components/new-user-popup.tsx index 6b4cea340..73a405d4a 100644 --- a/admin/components/new-user-popup.tsx +++ b/admin/components/new-user-popup.tsx @@ -17,11 +17,11 @@ import TakeoffIconDark from "/public/logos/takeoff-icon-dark.svg"; export const NewUserPopup: React.FC = observer(() => { // hooks const { isNewUserPopup, toggleNewUserPopup } = useTheme(); - const { instance } = useInstance(); + const { config } = useInstance(); // theme const { resolvedTheme } = nextUseTheme(); - const redirectionLink = `${instance?.config?.app_base_url ? `${instance?.config?.app_base_url}/create-workspace` : `/god-mode/`}`; + const redirectionLink = `${config?.app_base_url ? `${config?.app_base_url}/create-workspace` : `/god-mode/`}`; if (!isNewUserPopup) return <>; return ( diff --git a/admin/hooks/store/use-instance.tsx b/admin/hooks/store/use-instance.tsx index 15fdaf84f..cf2edc39f 100644 --- a/admin/hooks/store/use-instance.tsx +++ b/admin/hooks/store/use-instance.tsx @@ -1,6 +1,6 @@ import { useContext } from "react"; // store -import { StoreContext } from "@/lib/app-providers"; +import { StoreContext } from "@/lib/store-provider"; import { IInstanceStore } from "@/store/instance.store"; export const useInstance = (): IInstanceStore => { diff --git a/admin/hooks/store/use-theme.tsx b/admin/hooks/store/use-theme.tsx index 95d2aa05e..bad89cfee 100644 --- a/admin/hooks/store/use-theme.tsx +++ b/admin/hooks/store/use-theme.tsx @@ -1,6 +1,6 @@ import { useContext } from "react"; // store -import { StoreContext } from "@/lib/app-providers"; +import { StoreContext } from "@/lib/store-provider"; import { IThemeStore } from "@/store/theme.store"; export const useTheme = (): IThemeStore => { diff --git a/admin/hooks/store/use-user.tsx b/admin/hooks/store/use-user.tsx index c8cb45250..823003144 100644 --- a/admin/hooks/store/use-user.tsx +++ b/admin/hooks/store/use-user.tsx @@ -1,6 +1,6 @@ import { useContext } from "react"; // store -import { StoreContext } from "@/lib/app-providers"; +import { StoreContext } from "@/lib/store-provider"; import { IUserStore } from "@/store/user.store"; export const useUser = (): IUserStore => { diff --git a/admin/layouts/admin-layout.tsx b/admin/layouts/admin-layout.tsx index f7f828954..6da565345 100644 --- a/admin/layouts/admin-layout.tsx +++ b/admin/layouts/admin-layout.tsx @@ -2,14 +2,13 @@ import { FC, ReactNode, useEffect } from "react"; import { observer } from "mobx-react-lite"; import { useRouter } from "next/navigation"; -import useSWR from "swr"; // components import { InstanceSidebar } from "@/components/admin-sidebar"; import { InstanceHeader } from "@/components/auth-header"; import { LogoSpinner } from "@/components/common"; import { NewUserPopup } from "@/components/new-user-popup"; // hooks -import { useInstance, useUser } from "@/hooks/store"; +import { useUser } from "@/hooks/store"; type TAdminLayout = { children: ReactNode; @@ -19,15 +18,7 @@ export const AdminLayout: FC = observer((props) => { const { children } = props; // router const router = useRouter(); - // hooks - const { fetchInstanceAdmins } = useInstance(); - const { fetchCurrentUser, isUserLoggedIn } = useUser(); - - useSWR("INSTANCE_ADMINS", () => fetchInstanceAdmins()); - - useSWR("CURRENT_USER", () => fetchCurrentUser(), { - shouldRetryOnError: false, - }); + const { isUserLoggedIn } = useUser(); useEffect(() => { if (isUserLoggedIn === false) { @@ -48,8 +39,8 @@ export const AdminLayout: FC = observer((props) => {
-
{children}
+
{children}
); diff --git a/admin/lib/app-wrapper.tsx b/admin/lib/app-wrapper.tsx deleted file mode 100644 index daf030a5c..000000000 --- a/admin/lib/app-wrapper.tsx +++ /dev/null @@ -1,36 +0,0 @@ -"use client"; - -import { FC, ReactNode, useEffect, Suspense } from "react"; -import { observer } from "mobx-react-lite"; -import { SWRConfig } from "swr"; -// ui -import { Toast } from "@plane/ui"; -// constants -import { SWR_CONFIG } from "@/constants/swr-config"; -// helpers -import { resolveGeneralTheme } from "@/helpers/common.helper"; -// hooks -import { useTheme, useUser } from "@/hooks/store"; - -interface IAppWrapper { - children: ReactNode; -} - -export const AppWrapper: FC = observer(({ children }) => { - // hooks - const { theme, isSidebarCollapsed, toggleSidebar } = useTheme(); - const { currentUser } = useUser(); - - useEffect(() => { - const localValue = localStorage && localStorage.getItem("god_mode_sidebar_collapsed"); - const localBoolValue = localValue ? (localValue === "true" ? true : false) : false; - if (isSidebarCollapsed === undefined && localBoolValue != isSidebarCollapsed) toggleSidebar(localBoolValue); - }, [isSidebarCollapsed, currentUser, toggleSidebar]); - - return ( - - - {children} - - ); -}); diff --git a/admin/lib/instance-provider.tsx b/admin/lib/instance-provider.tsx new file mode 100644 index 000000000..194fea4dc --- /dev/null +++ b/admin/lib/instance-provider.tsx @@ -0,0 +1,55 @@ +import { FC, ReactNode } from "react"; +import { observer } from "mobx-react-lite"; +import useSWR from "swr"; +// components +import { LogoSpinner } from "@/components/common"; +import { InstanceSetupForm, InstanceFailureView } from "@/components/instance"; +// hooks +import { useInstance } from "@/hooks/store"; +// layout +import { DefaultLayout } from "@/layouts/default-layout"; + +type InstanceProviderProps = { + children: ReactNode; +}; + +export const InstanceProvider: FC = observer((props) => { + const { children } = props; + // store hooks + const { instance, error, fetchInstanceInfo } = useInstance(); + // fetching instance details + useSWR("INSTANCE_DETAILS", () => fetchInstanceInfo(), { + revalidateOnFocus: false, + revalidateIfStale: false, + errorRetryCount: 0, + }); + + if (!instance && !error) + return ( +
+ +
+ ); + + if (error) { + return ( + +
+ +
+
+ ); + } + + if (!instance?.is_setup_done) { + return ( + +
+ +
+
+ ); + } + + return <>{children}; +}); diff --git a/admin/lib/app-providers.tsx b/admin/lib/store-provider.tsx similarity index 63% rename from admin/lib/app-providers.tsx rename to admin/lib/store-provider.tsx index c52b4455e..842513860 100644 --- a/admin/lib/app-providers.tsx +++ b/admin/lib/store-provider.tsx @@ -1,11 +1,8 @@ "use client"; import { ReactNode, createContext } from "react"; -import { ThemeProvider } from "next-themes"; // store import { RootStore } from "@/store/root.store"; -// store initialization -import { AppWrapper } from "./app-wrapper"; let rootStore = new RootStore(); @@ -25,19 +22,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 ( - - - {children} - - - ); + return {children}; }; diff --git a/admin/lib/user-provider.tsx b/admin/lib/user-provider.tsx new file mode 100644 index 000000000..d8448d13e --- /dev/null +++ b/admin/lib/user-provider.tsx @@ -0,0 +1,31 @@ +"use client"; + +import { FC, ReactNode, useEffect } from "react"; +import { observer } from "mobx-react-lite"; +import useSWR from "swr"; +// hooks +import { useInstance, useTheme, useUser } from "@/hooks/store"; + +interface IUserProvider { + children: ReactNode; +} + +export const UserProvider: FC = observer(({ children }) => { + // hooks + const { isSidebarCollapsed, toggleSidebar } = useTheme(); + const { currentUser, fetchCurrentUser } = useUser(); + const { fetchInstanceAdmins } = useInstance(); + + useSWR("CURRENT_USER", () => fetchCurrentUser(), { + shouldRetryOnError: false, + }); + useSWR("INSTANCE_ADMINS", () => fetchInstanceAdmins()); + + useEffect(() => { + const localValue = localStorage && localStorage.getItem("god_mode_sidebar_collapsed"); + const localBoolValue = localValue ? (localValue === "true" ? true : false) : false; + if (isSidebarCollapsed === undefined && localBoolValue != isSidebarCollapsed) toggleSidebar(localBoolValue); + }, [isSidebarCollapsed, currentUser, toggleSidebar]); + + return <>{children}; +}); diff --git a/admin/services/instance.service.ts b/admin/services/instance.service.ts index 13431a834..feb94ceea 100644 --- a/admin/services/instance.service.ts +++ b/admin/services/instance.service.ts @@ -1,5 +1,11 @@ // types -import type { IFormattedInstanceConfiguration, IInstance, IInstanceAdmin, IInstanceConfiguration } from "@plane/types"; +import type { + IFormattedInstanceConfiguration, + IInstance, + IInstanceAdmin, + IInstanceConfiguration, + IInstanceInfo, +} from "@plane/types"; // helpers import { API_BASE_URL } from "@/helpers/common.helper"; import { APIService } from "@/services/api.service"; @@ -9,8 +15,8 @@ export class InstanceService extends APIService { super(API_BASE_URL); } - async getInstanceInfo(): Promise { - return this.get("/api/instances/") + async getInstanceInfo(): Promise { + return this.get("/api/instances/") .then((response) => response.data) .catch((error) => { throw error?.response?.data; @@ -25,8 +31,8 @@ export class InstanceService extends APIService { }); } - async updateInstanceInfo(data: Partial): Promise { - return this.patch, IInstance["instance"]>("/api/instances/", data) + async updateInstanceInfo(data: Partial): Promise { + return this.patch, IInstance>("/api/instances/", data) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; diff --git a/admin/store/instance.store.ts b/admin/store/instance.store.ts index e168b15b6..a99cd808c 100644 --- a/admin/store/instance.store.ts +++ b/admin/store/instance.store.ts @@ -1,6 +1,13 @@ import set from "lodash/set"; import { observable, action, computed, makeObservable, runInAction } from "mobx"; -import { IInstance, IInstanceAdmin, IInstanceConfiguration, IFormattedInstanceConfiguration } from "@plane/types"; +import { + IInstance, + IInstanceAdmin, + IInstanceConfiguration, + IFormattedInstanceConfiguration, + IInstanceInfo, + IInstanceConfig, +} from "@plane/types"; // helpers import { EInstanceStatus, TInstanceStatus } from "@/helpers"; // services @@ -11,16 +18,18 @@ import { RootStore } from "@/store/root.store"; export interface IInstanceStore { // issues isLoading: boolean; + error: any; instanceStatus: TInstanceStatus | undefined; instance: IInstance | undefined; + config: IInstanceConfig | undefined; instanceAdmins: IInstanceAdmin[] | undefined; instanceConfigurations: IInstanceConfiguration[] | undefined; // computed formattedConfig: IFormattedInstanceConfiguration | undefined; // action - hydrate: (data: any) => void; - fetchInstanceInfo: () => Promise; - updateInstanceInfo: (data: Partial) => Promise; + hydrate: (data: IInstanceInfo) => void; + fetchInstanceInfo: () => Promise; + updateInstanceInfo: (data: Partial) => Promise; fetchInstanceAdmins: () => Promise; fetchInstanceConfigurations: () => Promise; updateInstanceConfigurations: (data: Partial) => Promise; @@ -28,8 +37,10 @@ export interface IInstanceStore { export class InstanceStore implements IInstanceStore { isLoading: boolean = true; + error: any = undefined; instanceStatus: TInstanceStatus | undefined = undefined; instance: IInstance | undefined = undefined; + config: IInstanceConfig | undefined = undefined; instanceAdmins: IInstanceAdmin[] | undefined = undefined; instanceConfigurations: IInstanceConfiguration[] | undefined = undefined; // service @@ -39,6 +50,7 @@ export class InstanceStore implements IInstanceStore { makeObservable(this, { // observable isLoading: observable.ref, + error: observable.ref, instanceStatus: observable, instance: observable, instanceAdmins: observable, @@ -57,8 +69,11 @@ export class InstanceStore implements IInstanceStore { this.instanceService = new InstanceService(); } - hydrate = (data: any) => { - if (data) this.instance = data; + hydrate = (data: IInstanceInfo) => { + if (data) { + this.instance = data.instance; + this.config = data.config; + } }; /** @@ -80,17 +95,22 @@ export class InstanceStore implements IInstanceStore { fetchInstanceInfo = async () => { try { if (this.instance === undefined) this.isLoading = true; - const instance = await this.instanceService.getInstanceInfo(); + this.error = undefined; + const instanceInfo = await this.instanceService.getInstanceInfo(); // handling the new user popup toggle - if (this.instance === undefined && !instance?.instance?.workspaces_exist) this.store.theme.toggleNewUserPopup(); + if (this.instance === undefined && !instanceInfo?.instance?.workspaces_exist) + this.store.theme.toggleNewUserPopup(); runInAction(() => { + console.log("instanceInfo: ", instanceInfo); this.isLoading = false; - this.instance = instance; + this.instance = instanceInfo.instance; + this.config = instanceInfo.config; }); - return instance; + return instanceInfo; } catch (error) { console.error("Error fetching the instance info"); this.isLoading = false; + this.error = { message: "Failed to fetch the instance info" }; this.instanceStatus = { status: EInstanceStatus.ERROR, }; @@ -100,10 +120,10 @@ export class InstanceStore implements IInstanceStore { /** * @description updating instance information - * @param {Partial} data + * @param {Partial} data * @returns void */ - updateInstanceInfo = async (data: Partial) => { + updateInstanceInfo = async (data: Partial) => { try { const instanceResponse = await this.instanceService.updateInstanceInfo(data); if (instanceResponse) { diff --git a/packages/types/src/instance/base.d.ts b/packages/types/src/instance/base.d.ts index efc47b15d..d51978c06 100644 --- a/packages/types/src/instance/base.d.ts +++ b/packages/types/src/instance/base.d.ts @@ -6,47 +6,51 @@ import { TInstanceAuthenticationKeys, } from "./"; +export interface IInstanceInfo { + instance: IInstance; + config: IInstanceConfig; +} + export interface IInstance { - instance: { - id: string; - created_at: string; - updated_at: string; - instance_name: string | undefined; - whitelist_emails: string | undefined; - instance_id: string | undefined; - license_key: string | undefined; - api_key: string | undefined; - version: string | undefined; - last_checked_at: string | undefined; - namespace: string | undefined; - is_telemetry_enabled: boolean; - is_support_required: boolean; - is_activated: boolean; - is_setup_done: boolean; - is_signup_screen_visited: boolean; - user_count: number | undefined; - is_verified: boolean; - created_by: string | undefined; - updated_by: string | undefined; - workspaces_exist: boolean; - }; - config: { - is_google_enabled: boolean; - is_github_enabled: boolean; - is_magic_login_enabled: boolean; - is_email_password_enabled: boolean; - github_app_name: string | undefined; - slack_client_id: string | undefined; - posthog_api_key: string | undefined; - posthog_host: string | undefined; - has_unsplash_configured: boolean; - has_openai_configured: boolean; - file_size_limit: number | undefined; - is_smtp_configured: boolean; - app_base_url: string | undefined; - space_base_url: string | undefined; - admin_base_url: string | undefined; - }; + id: string; + created_at: string; + updated_at: string; + instance_name: string | undefined; + whitelist_emails: string | undefined; + instance_id: string | undefined; + license_key: string | undefined; + api_key: string | undefined; + version: string | undefined; + last_checked_at: string | undefined; + namespace: string | undefined; + is_telemetry_enabled: boolean; + is_support_required: boolean; + is_activated: boolean; + is_setup_done: boolean; + is_signup_screen_visited: boolean; + user_count: number | undefined; + is_verified: boolean; + created_by: string | undefined; + updated_by: string | undefined; + workspaces_exist: boolean; +} + +export interface IInstanceConfig { + is_google_enabled: boolean; + is_github_enabled: boolean; + is_magic_login_enabled: boolean; + is_email_password_enabled: boolean; + github_app_name: string | undefined; + slack_client_id: string | undefined; + posthog_api_key: string | undefined; + posthog_host: string | undefined; + has_unsplash_configured: boolean; + has_openai_configured: boolean; + file_size_limit: number | undefined; + is_smtp_configured: boolean; + app_base_url: string | undefined; + space_base_url: string | undefined; + admin_base_url: string | undefined; } export interface IInstanceAdmin {