Decouple twenty-ui Avatar from app server-URL config (#21968)

Makes `twenty-ui`'s `Avatar` render the `avatarUrl` it receives instead
of building it from `window._env_`/`window.location` at module load, so
the library no longer depends on the app environment. URL resolution
moves to `twenty-front` via a `getAbsoluteImageUrl` helper applied at
the call sites.

Part of making twenty-ui a standalone library.
This commit is contained in:
Raphaël Bosi
2026-06-22 18:38:00 +02:00
committed by GitHub
parent e59e102448
commit 5f22908588
47 changed files with 198 additions and 115 deletions
@@ -0,0 +1,31 @@
import { getAbsoluteImageUrl } from '~/utils/image/getAbsoluteImageUrl';
jest.mock('~/config', () => ({
REACT_APP_SERVER_BASE_URL: 'https://example.com',
}));
describe('getAbsoluteImageUrl', () => {
it('returns undefined for nullish or empty input', () => {
expect(getAbsoluteImageUrl(undefined)).toBeUndefined();
expect(getAbsoluteImageUrl(null)).toBeUndefined();
expect(getAbsoluteImageUrl('')).toBeUndefined();
});
it('returns absolute http(s) URLs unchanged', () => {
expect(getAbsoluteImageUrl('https://cdn.example.com/avatar.png')).toBe(
'https://cdn.example.com/avatar.png',
);
expect(getAbsoluteImageUrl('http://cdn.example.com/avatar.png')).toBe(
'http://cdn.example.com/avatar.png',
);
});
it('resolves relative paths against the server base URL under /files', () => {
expect(getAbsoluteImageUrl('avatars/avatar.png')).toBe(
'https://example.com/files/avatars/avatar.png',
);
expect(getAbsoluteImageUrl('/avatars/avatar.png')).toBe(
'https://example.com/files/avatars/avatar.png',
);
});
});
@@ -0,0 +1,11 @@
import { isNonEmptyString } from '@sniptt/guards';
import { getImageAbsoluteURI } from 'twenty-shared/utils';
import { REACT_APP_SERVER_BASE_URL } from '~/config';
export const getAbsoluteImageUrl = (
imageUrl?: string | null,
): string | undefined =>
isNonEmptyString(imageUrl)
? getImageAbsoluteURI({ imageUrl, baseUrl: REACT_APP_SERVER_BASE_URL })
: undefined;