♻️(frontend) frontend environment free
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.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
NEXT_PUBLIC_API_ORIGIN=http://test.jest
|
||||
NEXT_PUBLIC_API_URL=/api/
|
||||
|
||||
@@ -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/',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
11
src/frontend/apps/impress/src/core/conf.ts
Normal file
11
src/frontend/apps/impress/src/core/conf.ts
Normal file
@@ -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` : '');
|
||||
@@ -1 +1,3 @@
|
||||
export * from './AppProvider';
|
||||
export * from './auth';
|
||||
export * from './conf';
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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<PadStore>((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 }) => {
|
||||
|
||||
@@ -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: [],
|
||||
});
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user