fix: instance admin layout

This commit is contained in:
sriram veeraghanta 2024-05-17 20:32:40 +05:30
parent 564625ee22
commit 69ce0031d0
25 changed files with 267 additions and 195 deletions

View File

@ -1,9 +1,11 @@
"use client";
import { ReactNode } from "react"; import { ReactNode } from "react";
// layouts import { Metadata } from "next";
import { AdminLayout } from "@/layouts/admin-layout"; import { AdminLayout } from "@/layouts/admin-layout";
export const metadata: Metadata = {
title: "AI Settings - God Mode",
};
export default function AILayout({ children }: { children: ReactNode }) { export default function AILayout({ children }: { children: ReactNode }) {
return <AdminLayout>{children}</AdminLayout>; return <AdminLayout>{children}</AdminLayout>;
} }

View File

@ -1,9 +1,11 @@
"use client";
import { ReactNode } from "react"; import { ReactNode } from "react";
// layouts import { Metadata } from "next";
import { AdminLayout } from "@/layouts/admin-layout"; import { AdminLayout } from "@/layouts/admin-layout";
export const metadata: Metadata = {
title: "Authentication Settings - God Mode",
};
export default function AuthenticationLayout({ children }: { children: ReactNode }) { export default function AuthenticationLayout({ children }: { children: ReactNode }) {
return <AdminLayout>{children}</AdminLayout>; return <AdminLayout>{children}</AdminLayout>;
} }

View File

@ -1,13 +1,15 @@
"use client";
import { ReactNode } from "react"; import { ReactNode } from "react";
// layouts import { Metadata } from "next";
import { AdminLayout } from "@/layouts/admin-layout"; import { AdminLayout } from "@/layouts/admin-layout";
interface EmailLayoutProps { interface EmailLayoutProps {
children: ReactNode; children: ReactNode;
} }
export const metadata: Metadata = {
title: "Email Settings - God Mode",
};
const EmailLayout = ({ children }: EmailLayoutProps) => <AdminLayout>{children}</AdminLayout>; const EmailLayout = ({ children }: EmailLayoutProps) => <AdminLayout>{children}</AdminLayout>;
export default EmailLayout; export default EmailLayout;

View File

@ -13,7 +13,7 @@ import { ControllerInput } from "@/components/common";
import { useInstance } from "@/hooks/store"; import { useInstance } from "@/hooks/store";
export interface IGeneralConfigurationForm { export interface IGeneralConfigurationForm {
instance: IInstance["instance"]; instance: IInstance;
instanceAdmins: IInstanceAdmin[]; instanceAdmins: IInstanceAdmin[];
} }
@ -26,15 +26,15 @@ export const GeneralConfigurationForm: FC<IGeneralConfigurationForm> = observer(
handleSubmit, handleSubmit,
control, control,
formState: { errors, isSubmitting }, formState: { errors, isSubmitting },
} = useForm<Partial<IInstance["instance"]>>({ } = useForm<Partial<IInstance>>({
defaultValues: { defaultValues: {
instance_name: instance?.instance_name, instance_name: instance?.instance_name,
is_telemetry_enabled: instance?.is_telemetry_enabled, is_telemetry_enabled: instance?.is_telemetry_enabled,
}, },
}); });
const onSubmit = async (formData: Partial<IInstance["instance"]>) => { const onSubmit = async (formData: Partial<IInstance>) => {
const payload: Partial<IInstance["instance"]> = { ...formData }; const payload: Partial<IInstance> = { ...formData };
console.log("payload", payload); console.log("payload", payload);

View File

@ -1,6 +1,5 @@
import { ReactNode } from "react"; import { ReactNode } from "react";
import { Metadata } from "next"; import { Metadata } from "next";
// components
import { AdminLayout } from "@/layouts/admin-layout"; import { AdminLayout } from "@/layouts/admin-layout";
export const metadata: Metadata = { export const metadata: Metadata = {

View File

@ -7,7 +7,7 @@ import { GeneralConfigurationForm } from "./form";
function GeneralPage() { function GeneralPage() {
const { instance, instanceAdmins } = useInstance(); const { instance, instanceAdmins } = useInstance();
console.log("instance", instanceAdmins); console.log("instance", instance);
return ( return (
<> <>
<div className="relative container mx-auto w-full h-full p-8 py-4 space-y-6 flex flex-col"> <div className="relative container mx-auto w-full h-full p-8 py-4 space-y-6 flex flex-col">
@ -19,8 +19,8 @@ function GeneralPage() {
</div> </div>
</div> </div>
<div className="flex-grow overflow-hidden overflow-y-auto"> <div className="flex-grow overflow-hidden overflow-y-auto">
{instance?.instance && instanceAdmins && ( {instance && instanceAdmins && (
<GeneralConfigurationForm instance={instance.instance} instanceAdmins={instanceAdmins} /> <GeneralConfigurationForm instance={instance} instanceAdmins={instanceAdmins} />
)} )}
</div> </div>
</div> </div>

View File

@ -1,11 +1,15 @@
import { ReactNode } from "react"; import { ReactNode } from "react";
// layouts import { Metadata } from "next";
import { AdminLayout } from "@/layouts/admin-layout"; import { AdminLayout } from "@/layouts/admin-layout";
interface ImageLayoutProps { interface ImageLayoutProps {
children: ReactNode; children: ReactNode;
} }
export const metadata: Metadata = {
title: "Images Settings - God Mode",
};
const ImageLayout = ({ children }: ImageLayoutProps) => <AdminLayout>{children}</AdminLayout>; const ImageLayout = ({ children }: ImageLayoutProps) => <AdminLayout>{children}</AdminLayout>;
export default ImageLayout; export default ImageLayout;

View File

@ -1,40 +1,20 @@
"use client";
import { ReactNode } from "react"; import { ReactNode } from "react";
import { Metadata } from "next"; import { ThemeProvider } from "next-themes";
// components import { SWRConfig } from "swr";
import { InstanceFailureView, InstanceSetupForm } from "@/components/instance"; // constants
import { SWR_CONFIG } from "@/constants/swr-config";
// helpers // helpers
import { ASSET_PREFIX } from "@/helpers/common.helper"; import { ASSET_PREFIX } from "@/helpers/common.helper";
// layout
import { DefaultLayout } from "@/layouts/default-layout";
// lib // 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 // styles
import "./globals.css"; 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 ( return (
<html lang="en"> <html lang="en">
<head> <head>
@ -45,28 +25,18 @@ export default async function RootLayout({ children }: { children: ReactNode })
<link rel="shortcut icon" href={`${ASSET_PREFIX}/favicon/favicon.ico`} /> <link rel="shortcut icon" href={`${ASSET_PREFIX}/favicon/favicon.ico`} />
</head> </head>
<body className={`antialiased`}> <body className={`antialiased`}>
<AppProvider initialState={{ instance: instanceDetails }}> <ThemeProvider themes={["light", "dark"]} defaultTheme="system" enableSystem>
{instanceDetails ? ( <SWRConfig value={SWR_CONFIG}>
<> <StoreProvider>
{instanceDetails?.instance?.is_setup_done ? ( <InstanceProvider>
<>{children}</> <UserProvider>{children}</UserProvider>
) : ( </InstanceProvider>
<DefaultLayout> </StoreProvider>
<div className="relative w-screen min-h-screen overflow-y-auto px-5 py-10 mx-auto flex justify-center items-center"> </SWRConfig>
<InstanceSetupForm /> </ThemeProvider>
</div>
</DefaultLayout>
)}
</>
) : (
<DefaultLayout>
<div className="relative w-screen min-h-[500px] overflow-y-auto px-5 mx-auto flex justify-center items-center">
<InstanceFailureView />
</div>
</DefaultLayout>
)}
</AppProvider>
</body> </body>
</html> </html>
); );
} }
export default RootLayout;

View File

@ -1,7 +1,26 @@
import { Metadata } from "next";
// components
import { InstanceSignInForm } from "@/components/login"; import { InstanceSignInForm } from "@/components/login";
// layouts // layouts
import { DefaultLayout } from "@/layouts/default-layout"; 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() { export default async function LoginPage() {
return ( return (
<DefaultLayout> <DefaultLayout>

View File

@ -6,3 +6,4 @@ export * from "./password-strength-meter";
export * from "./banner"; export * from "./banner";
export * from "./empty-state"; export * from "./empty-state";
export * from "./logo-spinner"; export * from "./logo-spinner";
export * from "./toast";

View File

@ -11,7 +11,7 @@ export const LogoSpinner = () => {
return ( return (
<div className="flex items-center justify-center"> <div className="flex items-center justify-center">
<Image src={logoSrc} alt="logo" className="w-[82px] h-[82px] mr-2" /> <Image src={logoSrc} alt="logo" className="w-[82px] h-[82px] mr-2" priority={false} />
</div> </div>
); );
}; };

View File

@ -43,7 +43,7 @@ export const PasswordStrengthMeter: React.FC<Props> = (props: Props) => {
]; ];
return ( return (
<div className="w-full p-1"> <div className="w-full">
<div className="flex w-full gap-1.5"> <div className="flex w-full gap-1.5">
{bars.map((color, index) => ( {bars.map((color, index) => (
<div key={index} className={cn("w-full h-1 rounded-full", color)} /> <div key={index} className={cn("w-full h-1 rounded-full", color)} />

View File

@ -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 <ToastComponent theme={resolveGeneralTheme(theme)} />;
};

View File

@ -17,11 +17,11 @@ import TakeoffIconDark from "/public/logos/takeoff-icon-dark.svg";
export const NewUserPopup: React.FC = observer(() => { export const NewUserPopup: React.FC = observer(() => {
// hooks // hooks
const { isNewUserPopup, toggleNewUserPopup } = useTheme(); const { isNewUserPopup, toggleNewUserPopup } = useTheme();
const { instance } = useInstance(); const { config } = useInstance();
// theme // theme
const { resolvedTheme } = nextUseTheme(); 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 <></>; if (!isNewUserPopup) return <></>;
return ( return (

View File

@ -1,6 +1,6 @@
import { useContext } from "react"; import { useContext } from "react";
// store // store
import { StoreContext } from "@/lib/app-providers"; import { StoreContext } from "@/lib/store-provider";
import { IInstanceStore } from "@/store/instance.store"; import { IInstanceStore } from "@/store/instance.store";
export const useInstance = (): IInstanceStore => { export const useInstance = (): IInstanceStore => {

View File

@ -1,6 +1,6 @@
import { useContext } from "react"; import { useContext } from "react";
// store // store
import { StoreContext } from "@/lib/app-providers"; import { StoreContext } from "@/lib/store-provider";
import { IThemeStore } from "@/store/theme.store"; import { IThemeStore } from "@/store/theme.store";
export const useTheme = (): IThemeStore => { export const useTheme = (): IThemeStore => {

View File

@ -1,6 +1,6 @@
import { useContext } from "react"; import { useContext } from "react";
// store // store
import { StoreContext } from "@/lib/app-providers"; import { StoreContext } from "@/lib/store-provider";
import { IUserStore } from "@/store/user.store"; import { IUserStore } from "@/store/user.store";
export const useUser = (): IUserStore => { export const useUser = (): IUserStore => {

View File

@ -2,14 +2,13 @@
import { FC, ReactNode, useEffect } from "react"; import { FC, ReactNode, useEffect } from "react";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import useSWR from "swr";
// components // components
import { InstanceSidebar } from "@/components/admin-sidebar"; import { InstanceSidebar } from "@/components/admin-sidebar";
import { InstanceHeader } from "@/components/auth-header"; import { InstanceHeader } from "@/components/auth-header";
import { LogoSpinner } from "@/components/common"; import { LogoSpinner } from "@/components/common";
import { NewUserPopup } from "@/components/new-user-popup"; import { NewUserPopup } from "@/components/new-user-popup";
// hooks // hooks
import { useInstance, useUser } from "@/hooks/store"; import { useUser } from "@/hooks/store";
type TAdminLayout = { type TAdminLayout = {
children: ReactNode; children: ReactNode;
@ -19,15 +18,7 @@ export const AdminLayout: FC<TAdminLayout> = observer((props) => {
const { children } = props; const { children } = props;
// router // router
const router = useRouter(); const router = useRouter();
// hooks const { isUserLoggedIn } = useUser();
const { fetchInstanceAdmins } = useInstance();
const { fetchCurrentUser, isUserLoggedIn } = useUser();
useSWR("INSTANCE_ADMINS", () => fetchInstanceAdmins());
useSWR("CURRENT_USER", () => fetchCurrentUser(), {
shouldRetryOnError: false,
});
useEffect(() => { useEffect(() => {
if (isUserLoggedIn === false) { if (isUserLoggedIn === false) {
@ -48,8 +39,8 @@ export const AdminLayout: FC<TAdminLayout> = observer((props) => {
<InstanceSidebar /> <InstanceSidebar />
<main className="relative flex h-full w-full flex-col overflow-hidden bg-custom-background-100"> <main className="relative flex h-full w-full flex-col overflow-hidden bg-custom-background-100">
<InstanceHeader /> <InstanceHeader />
<div className="h-full w-full overflow-hidden">{children}</div>
</main> </main>
<div className="h-full w-full overflow-hidden">{children}</div>
<NewUserPopup /> <NewUserPopup />
</div> </div>
); );

View File

@ -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<IAppWrapper> = 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 (
<Suspense>
<Toast theme={resolveGeneralTheme(theme)} />
<SWRConfig value={SWR_CONFIG}>{children}</SWRConfig>
</Suspense>
);
});

View File

@ -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<InstanceProviderProps> = 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 (
<div className="flex h-screen min-h-[500px] w-full justify-center items-center">
<LogoSpinner />
</div>
);
if (error) {
return (
<DefaultLayout>
<div className="relative w-screen min-h-[500px] overflow-y-auto px-5 mx-auto flex justify-center items-center">
<InstanceFailureView />
</div>
</DefaultLayout>
);
}
if (!instance?.is_setup_done) {
return (
<DefaultLayout>
<div className="relative w-screen min-h-screen overflow-y-auto px-5 py-10 mx-auto flex justify-center items-center">
<InstanceSetupForm />
</div>
</DefaultLayout>
);
}
return <>{children}</>;
});

View File

@ -1,11 +1,8 @@
"use client"; "use client";
import { ReactNode, createContext } from "react"; import { ReactNode, createContext } from "react";
import { ThemeProvider } from "next-themes";
// store // store
import { RootStore } from "@/store/root.store"; import { RootStore } from "@/store/root.store";
// store initialization
import { AppWrapper } from "./app-wrapper";
let rootStore = new RootStore(); let rootStore = new RootStore();
@ -25,19 +22,13 @@ function initializeStore(initialData = {}) {
return singletonRootStore; return singletonRootStore;
} }
export type AppProviderProps = { export type StoreProviderProps = {
children: ReactNode; 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); const store = initializeStore(initialState);
return <StoreContext.Provider value={store}>{children}</StoreContext.Provider>;
return (
<ThemeProvider themes={["light", "dark"]} defaultTheme="system" enableSystem>
<StoreContext.Provider value={store}>
<AppWrapper>{children}</AppWrapper>
</StoreContext.Provider>
</ThemeProvider>
);
}; };

View File

@ -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<IUserProvider> = 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}</>;
});

View File

@ -1,5 +1,11 @@
// types // types
import type { IFormattedInstanceConfiguration, IInstance, IInstanceAdmin, IInstanceConfiguration } from "@plane/types"; import type {
IFormattedInstanceConfiguration,
IInstance,
IInstanceAdmin,
IInstanceConfiguration,
IInstanceInfo,
} from "@plane/types";
// helpers // helpers
import { API_BASE_URL } from "@/helpers/common.helper"; import { API_BASE_URL } from "@/helpers/common.helper";
import { APIService } from "@/services/api.service"; import { APIService } from "@/services/api.service";
@ -9,8 +15,8 @@ export class InstanceService extends APIService {
super(API_BASE_URL); super(API_BASE_URL);
} }
async getInstanceInfo(): Promise<IInstance> { async getInstanceInfo(): Promise<IInstanceInfo> {
return this.get<IInstance>("/api/instances/") return this.get<IInstanceInfo>("/api/instances/")
.then((response) => response.data) .then((response) => response.data)
.catch((error) => { .catch((error) => {
throw error?.response?.data; throw error?.response?.data;
@ -25,8 +31,8 @@ export class InstanceService extends APIService {
}); });
} }
async updateInstanceInfo(data: Partial<IInstance["instance"]>): Promise<IInstance["instance"]> { async updateInstanceInfo(data: Partial<IInstance>): Promise<IInstance> {
return this.patch<Partial<IInstance["instance"]>, IInstance["instance"]>("/api/instances/", data) return this.patch<Partial<IInstance>, IInstance>("/api/instances/", data)
.then((response) => response?.data) .then((response) => response?.data)
.catch((error) => { .catch((error) => {
throw error?.response?.data; throw error?.response?.data;

View File

@ -1,6 +1,13 @@
import set from "lodash/set"; import set from "lodash/set";
import { observable, action, computed, makeObservable, runInAction } from "mobx"; 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 // helpers
import { EInstanceStatus, TInstanceStatus } from "@/helpers"; import { EInstanceStatus, TInstanceStatus } from "@/helpers";
// services // services
@ -11,16 +18,18 @@ import { RootStore } from "@/store/root.store";
export interface IInstanceStore { export interface IInstanceStore {
// issues // issues
isLoading: boolean; isLoading: boolean;
error: any;
instanceStatus: TInstanceStatus | undefined; instanceStatus: TInstanceStatus | undefined;
instance: IInstance | undefined; instance: IInstance | undefined;
config: IInstanceConfig | undefined;
instanceAdmins: IInstanceAdmin[] | undefined; instanceAdmins: IInstanceAdmin[] | undefined;
instanceConfigurations: IInstanceConfiguration[] | undefined; instanceConfigurations: IInstanceConfiguration[] | undefined;
// computed // computed
formattedConfig: IFormattedInstanceConfiguration | undefined; formattedConfig: IFormattedInstanceConfiguration | undefined;
// action // action
hydrate: (data: any) => void; hydrate: (data: IInstanceInfo) => void;
fetchInstanceInfo: () => Promise<IInstance | undefined>; fetchInstanceInfo: () => Promise<IInstanceInfo | undefined>;
updateInstanceInfo: (data: Partial<IInstance["instance"]>) => Promise<IInstance["instance"] | undefined>; updateInstanceInfo: (data: Partial<IInstance>) => Promise<IInstance | undefined>;
fetchInstanceAdmins: () => Promise<IInstanceAdmin[] | undefined>; fetchInstanceAdmins: () => Promise<IInstanceAdmin[] | undefined>;
fetchInstanceConfigurations: () => Promise<IInstanceConfiguration[] | undefined>; fetchInstanceConfigurations: () => Promise<IInstanceConfiguration[] | undefined>;
updateInstanceConfigurations: (data: Partial<IFormattedInstanceConfiguration>) => Promise<IInstanceConfiguration[]>; updateInstanceConfigurations: (data: Partial<IFormattedInstanceConfiguration>) => Promise<IInstanceConfiguration[]>;
@ -28,8 +37,10 @@ export interface IInstanceStore {
export class InstanceStore implements IInstanceStore { export class InstanceStore implements IInstanceStore {
isLoading: boolean = true; isLoading: boolean = true;
error: any = undefined;
instanceStatus: TInstanceStatus | undefined = undefined; instanceStatus: TInstanceStatus | undefined = undefined;
instance: IInstance | undefined = undefined; instance: IInstance | undefined = undefined;
config: IInstanceConfig | undefined = undefined;
instanceAdmins: IInstanceAdmin[] | undefined = undefined; instanceAdmins: IInstanceAdmin[] | undefined = undefined;
instanceConfigurations: IInstanceConfiguration[] | undefined = undefined; instanceConfigurations: IInstanceConfiguration[] | undefined = undefined;
// service // service
@ -39,6 +50,7 @@ export class InstanceStore implements IInstanceStore {
makeObservable(this, { makeObservable(this, {
// observable // observable
isLoading: observable.ref, isLoading: observable.ref,
error: observable.ref,
instanceStatus: observable, instanceStatus: observable,
instance: observable, instance: observable,
instanceAdmins: observable, instanceAdmins: observable,
@ -57,8 +69,11 @@ export class InstanceStore implements IInstanceStore {
this.instanceService = new InstanceService(); this.instanceService = new InstanceService();
} }
hydrate = (data: any) => { hydrate = (data: IInstanceInfo) => {
if (data) this.instance = data; if (data) {
this.instance = data.instance;
this.config = data.config;
}
}; };
/** /**
@ -80,17 +95,22 @@ export class InstanceStore implements IInstanceStore {
fetchInstanceInfo = async () => { fetchInstanceInfo = async () => {
try { try {
if (this.instance === undefined) this.isLoading = true; 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 // 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(() => { runInAction(() => {
console.log("instanceInfo: ", instanceInfo);
this.isLoading = false; this.isLoading = false;
this.instance = instance; this.instance = instanceInfo.instance;
this.config = instanceInfo.config;
}); });
return instance; return instanceInfo;
} catch (error) { } catch (error) {
console.error("Error fetching the instance info"); console.error("Error fetching the instance info");
this.isLoading = false; this.isLoading = false;
this.error = { message: "Failed to fetch the instance info" };
this.instanceStatus = { this.instanceStatus = {
status: EInstanceStatus.ERROR, status: EInstanceStatus.ERROR,
}; };
@ -100,10 +120,10 @@ export class InstanceStore implements IInstanceStore {
/** /**
* @description updating instance information * @description updating instance information
* @param {Partial<IInstance["instance"]>} data * @param {Partial<IInstance>} data
* @returns void * @returns void
*/ */
updateInstanceInfo = async (data: Partial<IInstance["instance"]>) => { updateInstanceInfo = async (data: Partial<IInstance>) => {
try { try {
const instanceResponse = await this.instanceService.updateInstanceInfo(data); const instanceResponse = await this.instanceService.updateInstanceInfo(data);
if (instanceResponse) { if (instanceResponse) {

View File

@ -6,47 +6,51 @@ import {
TInstanceAuthenticationKeys, TInstanceAuthenticationKeys,
} from "./"; } from "./";
export interface IInstanceInfo {
instance: IInstance;
config: IInstanceConfig;
}
export interface IInstance { export interface IInstance {
instance: { id: string;
id: string; created_at: string;
created_at: string; updated_at: string;
updated_at: string; instance_name: string | undefined;
instance_name: string | undefined; whitelist_emails: string | undefined;
whitelist_emails: string | undefined; instance_id: string | undefined;
instance_id: string | undefined; license_key: string | undefined;
license_key: string | undefined; api_key: string | undefined;
api_key: string | undefined; version: string | undefined;
version: string | undefined; last_checked_at: string | undefined;
last_checked_at: string | undefined; namespace: string | undefined;
namespace: string | undefined; is_telemetry_enabled: boolean;
is_telemetry_enabled: boolean; is_support_required: boolean;
is_support_required: boolean; is_activated: boolean;
is_activated: boolean; is_setup_done: boolean;
is_setup_done: boolean; is_signup_screen_visited: boolean;
is_signup_screen_visited: boolean; user_count: number | undefined;
user_count: number | undefined; is_verified: boolean;
is_verified: boolean; created_by: string | undefined;
created_by: string | undefined; updated_by: string | undefined;
updated_by: string | undefined; workspaces_exist: boolean;
workspaces_exist: boolean; }
};
config: { export interface IInstanceConfig {
is_google_enabled: boolean; is_google_enabled: boolean;
is_github_enabled: boolean; is_github_enabled: boolean;
is_magic_login_enabled: boolean; is_magic_login_enabled: boolean;
is_email_password_enabled: boolean; is_email_password_enabled: boolean;
github_app_name: string | undefined; github_app_name: string | undefined;
slack_client_id: string | undefined; slack_client_id: string | undefined;
posthog_api_key: string | undefined; posthog_api_key: string | undefined;
posthog_host: string | undefined; posthog_host: string | undefined;
has_unsplash_configured: boolean; has_unsplash_configured: boolean;
has_openai_configured: boolean; has_openai_configured: boolean;
file_size_limit: number | undefined; file_size_limit: number | undefined;
is_smtp_configured: boolean; is_smtp_configured: boolean;
app_base_url: string | undefined; app_base_url: string | undefined;
space_base_url: string | undefined; space_base_url: string | undefined;
admin_base_url: string | undefined; admin_base_url: string | undefined;
};
} }
export interface IInstanceAdmin { export interface IInstanceAdmin {