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 362bb0f5c..70468788c 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 5e9c0b704..a84acd1a0 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 eda49a1b2..f8102d78d 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 d08d86d18..1a1fe346c 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 c2e2e2b89..4513e9bca 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 e2a2f3a11..b1f3c56d5 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 000000000..d26686c8c --- /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 bd2c0cdcc..97ec48976 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 3e71f784e..979f6e885 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 d721c3897..f7839e1be 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 7899b8851..bcdf71dbb 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 d399d95e0..7e711043c 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