Skip to content

Commit

Permalink
Merge pull request #32 from Hexastack/fix/frontend-config-runtime
Browse files Browse the repository at this point in the history
Fix: load config on runtime
  • Loading branch information
marrouchi authored Sep 20, 2024
2 parents 165fcbd + 36cd317 commit e97beb8
Show file tree
Hide file tree
Showing 20 changed files with 172 additions and 120 deletions.
5 changes: 5 additions & 0 deletions docker/docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ services:
- ../api/migrations:/app/migrations
#- ../api/node_modules:/app/node_modules
command: ["npm", "run", "start:debug"]

hexabot-frontend:
build:
context: ../
dockerfile: ./frontend/Dockerfile

mongo-express:
container_name: mongoUi
Expand Down
8 changes: 1 addition & 7 deletions docker/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ services:
condition: service_healthy
database-init:
condition: service_completed_successfully

healthcheck:
test: "wget --spider http://localhost:3000"
interval: 10s
Expand All @@ -40,12 +39,7 @@ services:

hexabot-frontend:
container_name: frontend
build:
context: ../
dockerfile: ./frontend/Dockerfile
args:
- NEXT_PUBLIC_API_ORIGIN=${NEXT_PUBLIC_API_ORIGIN}
- NEXT_PUBLIC_SSO_ENABLED=${NEXT_PUBLIC_SSO_ENABLED}
image: hexabot-ui:latest
env_file: .env
ports:
- ${APP_FRONTEND_PORT}:8080
Expand Down
12 changes: 0 additions & 12 deletions frontend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,6 @@ RUN \

# Rebuild the source code only when needed
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

Expand Down Expand Up @@ -57,10 +49,6 @@ ENV NODE_ENV production
# Uncomment the following line in case you want to disable telemetry during runtime.
ENV NEXT_TELEMETRY_DISABLED 1

Check warning on line 50 in frontend/Dockerfile

View workflow job for this annotation

GitHub Actions / build-and-push

Legacy key/value format with whitespace separator should not be used

LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format More info: https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/

# 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 adduser --system --uid 1001 nextjs

Expand Down
28 changes: 8 additions & 20 deletions frontend/next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,36 +1,24 @@
/** @type {import('next').NextConfig} */
import withTM from "next-transpile-modules";

const apiUrl = process.env.NEXT_PUBLIC_API_ORIGIN || "http://localhost:4000/";
const url = new URL(apiUrl);
const nextConfig = withTM(["hexabot-widget"])({
async rewrites() {
return [
{
source: "/config",
destination: "/api/config",
},
];
},
webpack(config, _options) {
return config;
},
publicRuntimeConfig: {
apiUrl,
ssoEnabled: process.env.NEXT_PUBLIC_SSO_ENABLED === "true",
lang: {
default: "en",
},
},
output: "standalone",
images: {
remotePatterns: [
{
protocol: "https",
hostname: url.hostname,
port: url.port,
pathname: "/attachment/**",
},
{
protocol: "http",
hostname: url.hostname,
port: url.port,
pathname: "/attachment/**",
},
],
},
});

export default nextConfig;
4 changes: 4 additions & 0 deletions frontend/src/app-components/tables/columns/renderPicture.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@ import { Grid } from "@mui/material";
import { GridRenderCellParams } from "@mui/x-data-grid";

import { getAvatarSrc } from "@/components/inbox/helpers/mapMessages";
import { useConfig } from "@/hooks/useConfig";
import { EntityType } from "@/services/types";

export const buildRenderPicture = (
entityType: EntityType.USER | EntityType.SUBSCRIBER,
) =>
function RenderPicture(params: GridRenderCellParams) {
const { apiUrl } = useConfig();

return (
<Grid
container
Expand All @@ -28,6 +31,7 @@ export const buildRenderPicture = (
>
<img
src={getAvatarSrc(
apiUrl,
entityType,
entityType === EntityType.USER
? params.row.id
Expand Down
10 changes: 8 additions & 2 deletions frontend/src/components/inbox/components/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import { useTranslation } from "react-i18next";

import { useCreate } from "@/hooks/crud/useCreate";
import { useAuth } from "@/hooks/useAuth";
import { useConfig } from "@/hooks/useConfig";
import { EntityType } from "@/services/types";


import { ChatActions } from "./ChatActions";
import { ChatHeader } from "./ChatHeader";
import {
Expand All @@ -35,6 +35,7 @@ import { useChat } from "../hooks/ChatContext";
import { useInfinitedLiveMessages } from "../hooks/useInfiniteLiveMessages";

export function Chat() {
const { apiUrl } = useConfig();
const { t, i18n } = useTranslation();
const { subscriber } = useChat();
const { user } = useAuth();
Expand Down Expand Up @@ -69,7 +70,11 @@ export function Chat() {
<ConversationHeader>
<Avatar
name={subscriber?.first_name}
src={getAvatarSrc(EntityType.SUBSCRIBER, subscriber.foreign_id)}
src={getAvatarSrc(
apiUrl,
EntityType.SUBSCRIBER,
subscriber.foreign_id,
)}
/>
<ConversationHeader.Content>
<ChatHeader />
Expand Down Expand Up @@ -118,6 +123,7 @@ export function Chat() {
i18n.language,
)}`}
src={getAvatarSrc(
apiUrl,
message.sender
? EntityType.SUBSCRIBER
: EntityType.USER,
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/components/inbox/components/ChatActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ import { Input } from "@/app-components/inputs/Input";
import { useFind } from "@/hooks/crud/useFind";
import { useUpdate } from "@/hooks/crud/useUpdate";
import { useAuth } from "@/hooks/useAuth";
import { useConfig } from "@/hooks/useConfig";
import { EntityType } from "@/services/types";

import { getAvatarSrc } from "../helpers/mapMessages";
import { useChat } from "../hooks/ChatContext";

export const ChatActions = () => {
const { apiUrl } = useConfig();
const { t } = useTranslation();
const { subscriber: activeChat } = useChat();
const [takeoverBy, setTakeoverBy] = useState<string>(
Expand Down Expand Up @@ -57,7 +59,7 @@ export const ChatActions = () => {
<Avatar
size="sm"
name={user.first_name}
src={getAvatarSrc(EntityType.USER, user.id)}
src={getAvatarSrc(apiUrl, EntityType.USER, user.id)}
/>
</Grid>
<Grid>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import InboxIcon from "@mui/icons-material/MoveToInbox";
import { Chip, debounce, Grid } from "@mui/material";
import { useTranslation } from "react-i18next";

import { useConfig } from "@/hooks/useConfig";
import { Title } from "@/layout/content/Title";
import { EntityType } from "@/services/types";

Expand All @@ -29,6 +30,7 @@ export const SubscribersList = (props: {
searchPayload: any;
assignedTo: AssignedTo;
}) => {
const { apiUrl } = useConfig();
const { t, i18n } = useTranslation();
const chat = useChat();
const { fetchNextPage, isFetching, subscribers, hasNextPage } =
Expand Down Expand Up @@ -58,6 +60,7 @@ export const SubscribersList = (props: {
>
<Avatar
src={getAvatarSrc(
apiUrl,
EntityType.SUBSCRIBER,
conversation.foreign_id,
)}
Expand Down
12 changes: 4 additions & 8 deletions frontend/src/components/inbox/helpers/mapMessages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,16 @@ import { Message, MessageModel } from "@chatscope/chat-ui-kit-react";
import MenuRoundedIcon from "@mui/icons-material/MenuRounded";
import ReplyIcon from "@mui/icons-material/Reply";
import { Chip, Grid } from "@mui/material";
import getConfig from "next/config";
import { ReactNode } from "react";

import { ROUTES } from "@/services/api.class";
import { EntityType } from "@/services/types";
import { IMessage, IMessageFull } from "@/types/message.types";
import { buildURL } from "@/utils/URL";

import { AttachmentViewer } from "../components/AttachmentViewer";
import { Carousel } from "../components/Carousel";

const { publicRuntimeConfig } = getConfig();

function hasSameSender(
m1: IMessage | IMessageFull,
m2: IMessage | IMessageFull,
Expand Down Expand Up @@ -133,13 +131,11 @@ export function getMessageContent(
* @description Returns the avatar of the subscriber
*/
export function getAvatarSrc(
apiUrl: string,
entity: EntityType.USER | EntityType.SUBSCRIBER,
id?: string,
) {
//remove trailing slash
return `${String(publicRuntimeConfig.apiUrl).replace(/\/$/, "")}${
ROUTES[entity]
}/${id || "bot"}/profile_pic`;
return buildURL(apiUrl, `${ROUTES[entity]}/${id || "bot"}/profile_pic`);
}

export function getMessagePosition(
Expand Down Expand Up @@ -186,4 +182,4 @@ export function getMessagePosition(

// Default case (should not reach here)
return "single";
}
}
6 changes: 3 additions & 3 deletions frontend/src/components/nlp/components/NlpSample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import {
MenuItem,
} from "@mui/material";
import { GridColDef } from "@mui/x-data-grid";
import getConfig from "next/config";
import { useState } from "react";
import { useTranslation } from "react-i18next";

Expand All @@ -38,6 +37,7 @@ import { DataGrid } from "@/app-components/tables/DataGrid";
import { useDelete } from "@/hooks/crud/useDelete";
import { useFind } from "@/hooks/crud/useFind";
import { useGetFromCache } from "@/hooks/crud/useGet";
import { useConfig } from "@/hooks/useConfig";
import { getDisplayDialogs, useDialog } from "@/hooks/useDialog";
import { useHasPermission } from "@/hooks/useHasPermission";
import { useSearch } from "@/hooks/useSearch";
Expand All @@ -56,14 +56,14 @@ import { buildURL } from "@/utils/URL";
import { NlpImportDialog } from "../NlpImportDialog";
import { NlpSampleDialog } from "../NlpSampleDialog";

const { publicRuntimeConfig } = getConfig();
const NLP_SAMPLE_TYPE_COLORS = {
test: "#e6a23c",
train: "#67c23a",
inbox: "#909399",
};

export default function NlpSample() {
const { apiUrl } = useConfig();
const { toast } = useToast();
const { t } = useTranslation();
const [dataset, setDataSet] = useState("");
Expand Down Expand Up @@ -287,7 +287,7 @@ export default function NlpSample() {
<Button
variant="contained"
href={buildURL(
publicRuntimeConfig.apiUrl,
apiUrl,
`nlpsample/export${dataset ? `?type=${dataset}` : ""}`,
)}
startIcon={<DownloadIcon />}
Expand Down
11 changes: 5 additions & 6 deletions frontend/src/components/users/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { faUsers } from "@fortawesome/free-solid-svg-icons";
import PersonAddAlt1Icon from "@mui/icons-material/PersonAddAlt1";
import { Button, Grid, Paper } from "@mui/material";
import { GridColDef } from "@mui/x-data-grid";
import getConfig from "next/config";
import { useTranslation } from "react-i18next";

import { ChipEntity } from "@/app-components/displays/ChipEntity";
Expand All @@ -25,6 +24,7 @@ import { buildRenderPicture } from "@/app-components/tables/columns/renderPictur
import { DataGrid } from "@/app-components/tables/DataGrid";
import { useFind } from "@/hooks/crud/useFind";
import { useUpdate } from "@/hooks/crud/useUpdate";
import { useConfig } from "@/hooks/useConfig";
import { getDisplayDialogs, useDialog } from "@/hooks/useDialog";
import { useHasPermission } from "@/hooks/useHasPermission";
import { useSearch } from "@/hooks/useSearch";
Expand All @@ -39,9 +39,8 @@ import { getDateTimeFormatter } from "@/utils/date";
import { EditUserDialog } from "./EditUserDialog";
import { InvitationDialog } from "./InvitationDialog";

const { publicRuntimeConfig } = getConfig();

export const Users = () => {
const { ssoEnabled } = useConfig();
const { t } = useTranslation();
const { toast } = useToast();
const { mutateAsync: updateUser } = useUpdate(EntityType.USER, {
Expand Down Expand Up @@ -157,7 +156,7 @@ export const Users = () => {
},
});
}}
disabled={publicRuntimeConfig.ssoEnabled}
disabled={ssoEnabled}
>
{t(params.row.state ? "label.enabled" : "label.disabled")}
</Button>
Expand Down Expand Up @@ -188,7 +187,7 @@ export const Users = () => {
valueGetter: (params) =>
t("datetime.updated_at", getDateTimeFormatter(params)),
},
...(!publicRuntimeConfig.ssoEnabled ? [actionColumns] : []),
...(!ssoEnabled ? [actionColumns] : []),
];

return (
Expand All @@ -207,7 +206,7 @@ export const Users = () => {
<Grid item>
<FilterTextfield onChange={onSearch} />
</Grid>
{!publicRuntimeConfig.ssoEnabled &&
{!ssoEnabled &&
hasPermission(EntityType.USER, PermissionAction.CREATE) ? (
<Grid item>
<Button
Expand Down
7 changes: 3 additions & 4 deletions frontend/src/hooks/useApiClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
*/

import axios from "axios";
import getConfig from "next/config";
import { stringify } from "qs";
import React, { createContext, ReactNode, useContext, useMemo } from "react";
import { useTranslation } from "react-i18next";
Expand All @@ -18,17 +17,17 @@ import { EntityType } from "@/services/types";
import { IBaseSchema } from "@/types/base.types";

import { useLogoutRedirection } from "./useAuth";
import { useConfig } from "./useConfig";
import { useToast } from "./useToast";

const { publicRuntimeConfig } = getConfig();

export const useAxiosInstance = () => {
const { apiUrl } = useConfig();
const { logoutRedirection } = useLogoutRedirection();
const { toast } = useToast();
const { t } = useTranslation();
const axiosInstance = useMemo(() => {
const instance = axios.create({
baseURL: publicRuntimeConfig.apiUrl,
baseURL: apiUrl,
withCredentials: true,
});
// Added the same Query String (de)Serializer as NestJS,
Expand Down
Loading

0 comments on commit e97beb8

Please sign in to comment.