From f0b3090a7398ad88ba60952e11fe334359df17cd Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Mon, 13 May 2024 10:54:47 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F(frontend)=20frontend=20envir?= =?UTF-8?q?onment=20free?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Until now, the front had to know at build time the url of the backend and the webrtc server to be able to communicate with them. It is not optimal because it means that we need multiple docker image (1 per environment) to have the app working, it is not very flexible. This commit will make the frontend "environment free" by determining these urls at runtime. --- src/frontend/apps/impress/.env.development | 3 ++- src/frontend/apps/impress/.env.production | 3 +-- src/frontend/apps/impress/.env.test | 1 + .../impress/src/api/__tests__/fetchApi.test.tsx | 13 +++++-------- src/frontend/apps/impress/src/api/fetchApi.ts | 4 ++-- .../apps/impress/src/core/auth/useAuthStore.tsx | 6 +++--- src/frontend/apps/impress/src/core/conf.ts | 11 +++++++++++ src/frontend/apps/impress/src/core/index.ts | 2 ++ src/frontend/apps/impress/src/custom-next.d.ts | 1 + .../src/features/pads/pad/stores/usePadStore.tsx | 4 +++- .../pads/pads-panel/__tests__/PanelPads.test.tsx | 14 +++++++------- src/helm/env.d/dev/values.impress.yaml.gotmpl | 3 ++- 12 files changed, 40 insertions(+), 25 deletions(-) create mode 100644 src/frontend/apps/impress/src/core/conf.ts diff --git a/src/frontend/apps/impress/.env.development b/src/frontend/apps/impress/.env.development index 362bb0f5..70468788 100644 --- a/src/frontend/apps/impress/.env.development +++ b/src/frontend/apps/impress/.env.development @@ -1,2 +1,3 @@ -NEXT_PUBLIC_API_URL=http://localhost:8071/api/v1.0/ +NEXT_PUBLIC_API_ORIGIN=http://localhost:8071 +NEXT_PUBLIC_API_URL=/api/v1.0/ NEXT_PUBLIC_SIGNALING_URL=ws://localhost:4444 diff --git a/src/frontend/apps/impress/.env.production b/src/frontend/apps/impress/.env.production index 5e9c0b70..a84acd1a 100644 --- a/src/frontend/apps/impress/.env.production +++ b/src/frontend/apps/impress/.env.production @@ -1,2 +1 @@ -NEXT_PUBLIC_API_URL=https://impress-staging.beta.numerique.gouv.fr/api/v1.0/ -NEXT_PUBLIC_SIGNALING_URL=wss://impress-staging.beta.numerique.gouv.fr/ws +NEXT_PUBLIC_API_URL=/api/v1.0/ diff --git a/src/frontend/apps/impress/.env.test b/src/frontend/apps/impress/.env.test index eda49a1b..f8102d78 100644 --- a/src/frontend/apps/impress/.env.test +++ b/src/frontend/apps/impress/.env.test @@ -1 +1,2 @@ +NEXT_PUBLIC_API_ORIGIN=http://test.jest NEXT_PUBLIC_API_URL=/api/ diff --git a/src/frontend/apps/impress/src/api/__tests__/fetchApi.test.tsx b/src/frontend/apps/impress/src/api/__tests__/fetchApi.test.tsx index d08d86d1..1a1fe346 100644 --- a/src/frontend/apps/impress/src/api/__tests__/fetchApi.test.tsx +++ b/src/frontend/apps/impress/src/api/__tests__/fetchApi.test.tsx @@ -5,22 +5,19 @@ import { useAuthStore } from '@/core/auth'; describe('fetchAPI', () => { beforeEach(() => { - process.env.NEXT_PUBLIC_API_URL = 'http://some.api.url/api/v1.0/'; fetchMock.restore(); }); it('adds correctly the basename', () => { - fetchMock.mock('http://some.api.url/api/v1.0/some/url', 200); + fetchMock.mock('http://test.jest/api/some/url', 200); void fetchAPI('some/url'); - expect(fetchMock.lastUrl()).toEqual( - 'http://some.api.url/api/v1.0/some/url', - ); + expect(fetchMock.lastUrl()).toEqual('http://test.jest/api/some/url'); }); it('adds the credentials automatically', () => { - fetchMock.mock('http://some.api.url/api/v1.0/some/url', 200); + fetchMock.mock('http://test.jest/api/some/url', 200); void fetchAPI('some/url', { body: 'some body' }); @@ -45,14 +42,14 @@ describe('fetchAPI', () => { useAuthStore.setState({ userData: { email: 'test@test.com', id: '1234' } }); - fetchMock.mock('http://some.api.url/api/v1.0/some/url', 401); + fetchMock.mock('http://test.jest/api/some/url', 401); await fetchAPI('some/url'); expect(useAuthStore.getState().userData).toBeUndefined(); expect(mockReplace).toHaveBeenCalledWith( - 'http://some.api.url/api/v1.0/authenticate/', + 'http://test.jest/api/authenticate/', ); }); }); diff --git a/src/frontend/apps/impress/src/api/fetchApi.ts b/src/frontend/apps/impress/src/api/fetchApi.ts index c2e2e2b8..4513e9bc 100644 --- a/src/frontend/apps/impress/src/api/fetchApi.ts +++ b/src/frontend/apps/impress/src/api/fetchApi.ts @@ -1,4 +1,4 @@ -import { login, useAuthStore } from '@/core/auth'; +import { baseApiUrl, login, useAuthStore } from '@/core'; /** * Retrieves the CSRF token from the document's cookies. @@ -14,7 +14,7 @@ function getCSRFToken() { } export const fetchAPI = async (input: string, init?: RequestInit) => { - const apiUrl = `${process.env.NEXT_PUBLIC_API_URL}${input}`; + const apiUrl = `${baseApiUrl()}${input}`; const { logout } = useAuthStore.getState(); const csrfToken = getCSRFToken(); diff --git a/src/frontend/apps/impress/src/core/auth/useAuthStore.tsx b/src/frontend/apps/impress/src/core/auth/useAuthStore.tsx index e2a2f3a1..b1f3c56d 100644 --- a/src/frontend/apps/impress/src/core/auth/useAuthStore.tsx +++ b/src/frontend/apps/impress/src/core/auth/useAuthStore.tsx @@ -1,11 +1,11 @@ import { create } from 'zustand'; +import { baseApiUrl } from '@/core/conf'; + import { User, getMe } from './api'; export const login = () => { - window.location.replace( - new URL('authenticate/', process.env.NEXT_PUBLIC_API_URL).href, - ); + window.location.replace(new URL('authenticate/', baseApiUrl()).href); }; interface AuthStore { diff --git a/src/frontend/apps/impress/src/core/conf.ts b/src/frontend/apps/impress/src/core/conf.ts new file mode 100644 index 00000000..d26686c8 --- /dev/null +++ b/src/frontend/apps/impress/src/core/conf.ts @@ -0,0 +1,11 @@ +export const baseApiUrl = () => { + const origin = + process.env.NEXT_PUBLIC_API_ORIGIN || + (typeof window !== 'undefined' ? window.location.origin : ''); + + return `${origin}${process.env.NEXT_PUBLIC_API_URL}`; +}; + +export const signalingUrl = () => + process.env.NEXT_PUBLIC_SIGNALING_URL || + (typeof window !== 'undefined' ? `wss://${window.location.host}/ws` : ''); diff --git a/src/frontend/apps/impress/src/core/index.ts b/src/frontend/apps/impress/src/core/index.ts index bd2c0cdc..97ec4897 100644 --- a/src/frontend/apps/impress/src/core/index.ts +++ b/src/frontend/apps/impress/src/core/index.ts @@ -1 +1,3 @@ export * from './AppProvider'; +export * from './auth'; +export * from './conf'; diff --git a/src/frontend/apps/impress/src/custom-next.d.ts b/src/frontend/apps/impress/src/custom-next.d.ts index 3e71f784..979f6e88 100644 --- a/src/frontend/apps/impress/src/custom-next.d.ts +++ b/src/frontend/apps/impress/src/custom-next.d.ts @@ -19,6 +19,7 @@ declare module '*.svg?url' { namespace NodeJS { interface ProcessEnv { + NEXT_PUBLIC_API_ORIGIN?: string; NEXT_PUBLIC_API_URL?: string; NEXT_PUBLIC_SIGNALING_URL?: string; } diff --git a/src/frontend/apps/impress/src/features/pads/pad/stores/usePadStore.tsx b/src/frontend/apps/impress/src/features/pads/pad/stores/usePadStore.tsx index d721c389..f7839e1b 100644 --- a/src/frontend/apps/impress/src/features/pads/pad/stores/usePadStore.tsx +++ b/src/frontend/apps/impress/src/features/pads/pad/stores/usePadStore.tsx @@ -3,6 +3,8 @@ import { WebrtcProvider } from 'y-webrtc'; import * as Y from 'yjs'; import { create } from 'zustand'; +import { signalingUrl } from '@/core'; + import { Pad } from '../types'; export interface PadStore { @@ -24,7 +26,7 @@ export const usePadStore = create((set) => ({ padsStore: initialState.padsStore, createProvider: (padId: string) => { const provider = new WebrtcProvider(padId, new Y.Doc(), { - signaling: [process.env.NEXT_PUBLIC_SIGNALING_URL || ''], + signaling: [signalingUrl()], }); set(({ padsStore }) => { diff --git a/src/frontend/apps/impress/src/features/pads/pads-panel/__tests__/PanelPads.test.tsx b/src/frontend/apps/impress/src/features/pads/pads-panel/__tests__/PanelPads.test.tsx index 7899b885..bcdf71db 100644 --- a/src/frontend/apps/impress/src/features/pads/pads-panel/__tests__/PanelPads.test.tsx +++ b/src/frontend/apps/impress/src/features/pads/pads-panel/__tests__/PanelPads.test.tsx @@ -23,7 +23,7 @@ describe('PanelPads', () => { }); it('renders with no pad to display', async () => { - fetchMock.mock(`/api/documents/?page=1&ordering=-created_at`, { + fetchMock.mock(`end:/api/documents/?page=1&ordering=-created_at`, { count: 0, results: [], }); @@ -40,7 +40,7 @@ describe('PanelPads', () => { }); it('renders an empty pad', async () => { - fetchMock.mock(`/api/documents/?page=1&ordering=-created_at`, { + fetchMock.mock(`end:/api/documents/?page=1&ordering=-created_at`, { count: 1, results: [ { @@ -59,7 +59,7 @@ describe('PanelPads', () => { }); it('renders a pad with only 1 member', async () => { - fetchMock.mock(`/api/documents/?page=1&ordering=-created_at`, { + fetchMock.mock(`end:/api/documents/?page=1&ordering=-created_at`, { count: 1, results: [ { @@ -83,7 +83,7 @@ describe('PanelPads', () => { }); it('renders a non-empty pad', async () => { - fetchMock.mock(`/api/documents/?page=1&ordering=-created_at`, { + fetchMock.mock(`end:/api/documents/?page=1&ordering=-created_at`, { count: 1, results: [ { @@ -111,7 +111,7 @@ describe('PanelPads', () => { }); it('renders the error', async () => { - fetchMock.mock(`/api/documents/?page=1&ordering=-created_at`, { + fetchMock.mock(`end:/api/documents/?page=1&ordering=-created_at`, { status: 500, }); @@ -127,7 +127,7 @@ describe('PanelPads', () => { }); it('renders with pad panel open', async () => { - fetchMock.mock(`/api/documents/?page=1&ordering=-created_at`, { + fetchMock.mock(`end:/api/documents/?page=1&ordering=-created_at`, { count: 1, results: [], }); @@ -142,7 +142,7 @@ describe('PanelPads', () => { }); it('closes and opens the pad panel', async () => { - fetchMock.mock(`/api/documents/?page=1&ordering=-created_at`, { + fetchMock.mock(`end:/api/documents/?page=1&ordering=-created_at`, { count: 1, results: [], }); diff --git a/src/helm/env.d/dev/values.impress.yaml.gotmpl b/src/helm/env.d/dev/values.impress.yaml.gotmpl index d399d95e..7e711043 100644 --- a/src/helm/env.d/dev/values.impress.yaml.gotmpl +++ b/src/helm/env.d/dev/values.impress.yaml.gotmpl @@ -50,7 +50,8 @@ backend: frontend: envVars: PORT: 8080 - NEXT_PUBLIC_API_URL: https://impress.127.0.0.1.nip.io/api/v1.0/ + NEXT_PUBLIC_API_ORIGIN: https://impress.127.0.0.1.nip.io + NEXT_PUBLIC_API_URL: /api/v1.0/ NEXT_PUBLIC_SIGNALING_URL: wss://impress.127.0.0.1.nip.io/ws replicas: 1