fix: load config on runtime

This commit is contained in:
Mohamed Marrouchi 2024-09-17 17:12:20 +01:00 committed by Yassine Sallemi
parent d2555d9f94
commit aa05fe1704
7 changed files with 110 additions and 46 deletions

View File

@ -16,6 +16,11 @@ services:
- ../api/migrations:/app/migrations - ../api/migrations:/app/migrations
#- ../api/node_modules:/app/node_modules #- ../api/node_modules:/app/node_modules
command: ["npm", "run", "start:debug"] command: ["npm", "run", "start:debug"]
hexabot-frontend:
build:
context: ../
dockerfile: ./frontend/Dockerfile
mongo-express: mongo-express:
container_name: mongoUi container_name: mongoUi

View File

@ -30,7 +30,6 @@ services:
condition: service_healthy condition: service_healthy
database-init: database-init:
condition: service_completed_successfully condition: service_completed_successfully
healthcheck: healthcheck:
test: "wget --spider http://localhost:3000" test: "wget --spider http://localhost:3000"
interval: 10s interval: 10s
@ -40,12 +39,7 @@ services:
hexabot-frontend: hexabot-frontend:
container_name: frontend container_name: frontend
build: image: hexabot-ui:latest
context: ../
dockerfile: ./frontend/Dockerfile
args:
- NEXT_PUBLIC_API_ORIGIN=${NEXT_PUBLIC_API_ORIGIN}
- NEXT_PUBLIC_SSO_ENABLED=${NEXT_PUBLIC_SSO_ENABLED}
env_file: .env env_file: .env
ports: ports:
- ${APP_FRONTEND_PORT}:8080 - ${APP_FRONTEND_PORT}:8080

View File

@ -21,14 +21,6 @@ RUN \
# Rebuild the source code only when needed # Rebuild the source code only when needed
FROM base AS builder FROM base AS builder
ARG NEXT_PUBLIC_API_ORIGIN
ENV NEXT_PUBLIC_API_ORIGIN=${NEXT_PUBLIC_API_ORIGIN}
ARG NEXT_PUBLIC_SSO_ENABLED
ENV NEXT_PUBLIC_SSO_ENABLED=${NEXT_PUBLIC_SSO_ENABLED}
ENV REACT_APP_WIDGET_API_URL=${NEXT_PUBLIC_API_ORIGIN}
ENV REACT_APP_WIDGET_CHANNEL=test
ENV REACT_APP_WIDGET_TOKEN=test
WORKDIR /app WORKDIR /app
@ -57,10 +49,6 @@ ENV NODE_ENV production
# Uncomment the following line in case you want to disable telemetry during runtime. # Uncomment the following line in case you want to disable telemetry during runtime.
ENV NEXT_TELEMETRY_DISABLED 1 ENV NEXT_TELEMETRY_DISABLED 1
# Set the environment variable API_ORIGIN
ENV NEXT_PUBLIC_API_ORIGIN ${NEXT_PUBLIC_API_ORIGIN:-"http://localhost:3000"}
ENV NEXT_PUBLIC_SSO_ENABLED ${NEXT_PUBLIC_SSO_ENABLED:-"false"}
RUN addgroup --system --gid 1001 nodejs RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs RUN adduser --system --uid 1001 nextjs

View File

@ -4,6 +4,14 @@ import withTM from "next-transpile-modules";
const apiUrl = process.env.NEXT_PUBLIC_API_ORIGIN || "http://localhost:4000/"; const apiUrl = process.env.NEXT_PUBLIC_API_ORIGIN || "http://localhost:4000/";
const url = new URL(apiUrl); const url = new URL(apiUrl);
const nextConfig = withTM(["hexabot-widget"])({ const nextConfig = withTM(["hexabot-widget"])({
async rewrites() {
return [
{
source: "/config",
destination: "/api/config",
},
];
},
webpack(config, _options) { webpack(config, _options) {
return config; return config;
}, },

View File

@ -0,0 +1,50 @@
import { createContext, useContext, useEffect, useState } from "react";
const ConfigContext = createContext(null);
export interface IConfig {
NEXT_PUBLIC_API_ORIGIN: string;
NEXT_PUBLIC_SSO_ENABLED: boolean;
REACT_APP_WIDGET_API_URL: string;
REACT_APP_WIDGET_CHANNEL: string;
REACT_APP_WIDGET_TOKEN: string;
}
export const ConfigProvider = ({ children }) => {
const [config, setConfig] = useState(null);
useEffect(() => {
const fetchConfig = async () => {
try {
const res = await fetch("/config");
const data = await res.json();
setConfig(data);
} catch (error) {
// eslint-disable-next-line no-console
console.error("Failed to fetch configuration:", error);
}
};
fetchConfig();
}, []);
if (!config) {
// You can return a loader here if you want
return null;
}
return (
<ConfigContext.Provider value={config}>{children}</ConfigContext.Provider>
);
};
export const useConfig = () => {
const context = useContext(ConfigContext);
if (!context) {
throw new Error("useConfig must be used within a ConfigProvider");
}
return context;
};

View File

@ -20,6 +20,7 @@ import { ReactQueryDevtools } from "react-query/devtools";
import { SnackbarCloseButton } from "@/app-components/displays/Toast/CloseButton"; import { SnackbarCloseButton } from "@/app-components/displays/Toast/CloseButton";
import { ApiClientProvider } from "@/hooks/useApiClient"; import { ApiClientProvider } from "@/hooks/useApiClient";
import { AuthProvider } from "@/hooks/useAuth"; import { AuthProvider } from "@/hooks/useAuth";
import { ConfigProvider } from "@/hooks/useConfig";
import { PermissionProvider } from "@/hooks/useHasPermission"; import { PermissionProvider } from "@/hooks/useHasPermission";
import { SettingsProvider } from "@/hooks/useSetting"; import { SettingsProvider } from "@/hooks/useSetting";
import { ToastProvider } from "@/hooks/useToast"; import { ToastProvider } from "@/hooks/useToast";
@ -69,33 +70,35 @@ const App = ({ Component, pageProps }: TAppPropsWithLayout) => {
/> />
</Head> </Head>
<main className={roboto.className}> <main className={roboto.className}>
<ThemeProvider theme={theme}> <ConfigProvider>
<ToastProvider <ThemeProvider theme={theme}>
maxSnack={3} <ToastProvider
anchorOrigin={{ vertical: "top", horizontal: "center" }} maxSnack={3}
action={(snackbarKey) => ( anchorOrigin={{ vertical: "top", horizontal: "center" }}
<SnackbarCloseButton snackbarKey={snackbarKey} /> action={(snackbarKey) => (
)} <SnackbarCloseButton snackbarKey={snackbarKey} />
> )}
<StyledEngineProvider injectFirst> >
<QueryClientProvider client={queryClient}> <StyledEngineProvider injectFirst>
<CssBaseline /> <QueryClientProvider client={queryClient}>
<ApiClientProvider> <CssBaseline />
<AuthProvider> <ApiClientProvider>
<PermissionProvider> <AuthProvider>
<SettingsProvider> <PermissionProvider>
<SocketProvider> <SettingsProvider>
{getLayout(<Component {...pageProps} />)} <SocketProvider>
</SocketProvider> {getLayout(<Component {...pageProps} />)}
</SettingsProvider> </SocketProvider>
</PermissionProvider> </SettingsProvider>
</AuthProvider> </PermissionProvider>
</ApiClientProvider> </AuthProvider>
<ReactQueryDevtools initialIsOpen={false} /> </ApiClientProvider>
</QueryClientProvider> <ReactQueryDevtools initialIsOpen={false} />
</StyledEngineProvider> </QueryClientProvider>
</ToastProvider> </StyledEngineProvider>
</ThemeProvider> </ToastProvider>
</ThemeProvider>
</ConfigProvider>
</main> </main>
</> </>
); );

View File

@ -0,0 +1,16 @@
import type { NextApiRequest, NextApiResponse } from "next";
type ResponseData = {
apiUrl: string;
ssoEnabled: boolean;
};
export default function handler(
req: NextApiRequest,
res: NextApiResponse<ResponseData>,
) {
res.status(200).json({
apiUrl: process.env.NEXT_PUBLIC_API_ORIGIN || "http://localhost:3000",
ssoEnabled: process.env.NEXT_PUBLIC_SSO_ENABLED === "true" || false,
});
}