Add Twenty Shared & Fix profile image rendering (#8841)
PR Summary: 1. Added `Twenty Shared` Package to centralize utilitiies as mentioned in #8942 2. Optimization of `getImageAbsoluteURI.ts` to handle edge cases  --------- Co-authored-by: Antoine Moreaux <moreaux.antoine@gmail.com> Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
committed by
GitHub
parent
4e329d08b0
commit
08a9db2df6
15
packages/twenty-shared/.eslintrc.cjs
Normal file
15
packages/twenty-shared/.eslintrc.cjs
Normal file
@ -0,0 +1,15 @@
|
||||
module.exports = {
|
||||
extends: ['../../.eslintrc.cjs'],
|
||||
ignorePatterns: ['!**/*'],
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.ts', '*.tsx'],
|
||||
parserOptions: {
|
||||
project: ['packages/twenty-shared/tsconfig.{json,*.json}'],
|
||||
},
|
||||
rules: {
|
||||
'@nx/dependency-checks': 'error',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
1
packages/twenty-shared/.gitignore
vendored
Normal file
1
packages/twenty-shared/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
dist
|
||||
39
packages/twenty-shared/jest.config.ts
Normal file
39
packages/twenty-shared/jest.config.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { JestConfigWithTsJest, pathsToModuleNameMapper } from 'ts-jest';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const tsConfig = require('./tsconfig.json');
|
||||
|
||||
const jestConfig: JestConfigWithTsJest = {
|
||||
displayName: 'twenty-ui',
|
||||
preset: '../../jest.preset.js',
|
||||
testEnvironment: 'jsdom',
|
||||
transformIgnorePatterns: ['../../node_modules/'],
|
||||
transform: {
|
||||
'^.+\\.[tj]sx?$': [
|
||||
'@swc/jest',
|
||||
{
|
||||
jsc: {
|
||||
parser: { syntax: 'typescript', tsx: true },
|
||||
transform: { react: { runtime: 'automatic' } },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
moduleNameMapper: {
|
||||
'\\.(jpg|jpeg|png|gif|webp|svg|svg\\?react)$':
|
||||
'<rootDir>/__mocks__/imageMock.js',
|
||||
...pathsToModuleNameMapper(tsConfig.compilerOptions.paths),
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||
extensionsToTreatAsEsm: ['.ts', '.tsx'],
|
||||
coverageDirectory: './coverage',
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
statements: 100,
|
||||
lines: 100,
|
||||
functions: 100,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default jestConfig;
|
||||
20
packages/twenty-shared/package.json
Normal file
20
packages/twenty-shared/package.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "twenty-shared",
|
||||
"version": "0.40.0-canary",
|
||||
"license": "AGPL-3.0",
|
||||
"main": "./dist/index.js",
|
||||
"scripts": {
|
||||
"build": "npx vite build"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.17.1",
|
||||
"npm": "please-use-yarn",
|
||||
"yarn": "^4.0.2"
|
||||
}
|
||||
}
|
||||
38
packages/twenty-shared/project.json
Normal file
38
packages/twenty-shared/project.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "twenty-shared",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "packages/twenty-shared/src",
|
||||
"projectType": "library",
|
||||
"tags": ["scope:shared"],
|
||||
"targets": {
|
||||
"build": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"options": {
|
||||
"outputPath": "{projectRoot}/dist"
|
||||
}
|
||||
},
|
||||
"typecheck": {},
|
||||
"test": {},
|
||||
"lint": {
|
||||
"options": {
|
||||
"lintFilePatterns": [
|
||||
"{projectRoot}/src/**/*.{ts,tsx,json}",
|
||||
"{projectRoot}/package.json"
|
||||
],
|
||||
"reportUnusedDisableDirectives": "error"
|
||||
},
|
||||
"configurations": {
|
||||
"fix": {}
|
||||
}
|
||||
},
|
||||
"fmt": {
|
||||
"options": {
|
||||
"files": "src"
|
||||
},
|
||||
"configurations": {
|
||||
"fix": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1
packages/twenty-shared/src/index.ts
Normal file
1
packages/twenty-shared/src/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './utils/image/getImageAbsoluteURI';
|
||||
@ -0,0 +1,38 @@
|
||||
import { getImageAbsoluteURI } from '../getImageAbsoluteURI';
|
||||
|
||||
describe('getImageAbsoluteURI', () => {
|
||||
it('should return baseUrl if imageUrl is empty string', () => {
|
||||
const imageUrl = '';
|
||||
const baseUrl = 'http://localhost:3000';
|
||||
const result = getImageAbsoluteURI({ imageUrl, baseUrl });
|
||||
expect(result).toBe('http://localhost:3000/files/');
|
||||
});
|
||||
|
||||
it('should return absolute url if the imageUrl is an absolute url', () => {
|
||||
const imageUrl = 'https://XXX';
|
||||
const baseUrl = 'http://localhost:3000';
|
||||
const result = getImageAbsoluteURI({ imageUrl, baseUrl });
|
||||
expect(result).toBe(imageUrl);
|
||||
});
|
||||
|
||||
it('should return fully formed url if imageUrl is a relative url starting with /', () => {
|
||||
const imageUrl = '/path/pic.png';
|
||||
const baseUrl = 'http://localhost:3000';
|
||||
const result = getImageAbsoluteURI({ imageUrl, baseUrl });
|
||||
expect(result).toBe('http://localhost:3000/files/path/pic.png');
|
||||
});
|
||||
|
||||
it('should return fully formed url if imageUrl is a relative url nost starting with slash', () => {
|
||||
const imageUrl = 'pic.png';
|
||||
const baseUrl = 'http://localhost:3000';
|
||||
const result = getImageAbsoluteURI({ imageUrl, baseUrl });
|
||||
expect(result).toBe('http://localhost:3000/files/pic.png');
|
||||
});
|
||||
|
||||
it('should handle queryParameters in the imageUrl', () => {
|
||||
const imageUrl = '/pic.png?token=XXX';
|
||||
const baseUrl = 'http://localhost:3000';
|
||||
const result = getImageAbsoluteURI({ imageUrl, baseUrl });
|
||||
expect(result).toBe('http://localhost:3000/files/pic.png?token=XXX');
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,19 @@
|
||||
type getImageAbsoluteURIProps = {
|
||||
imageUrl: string;
|
||||
baseUrl: string;
|
||||
};
|
||||
|
||||
export const getImageAbsoluteURI = ({
|
||||
imageUrl,
|
||||
baseUrl,
|
||||
}: getImageAbsoluteURIProps): string => {
|
||||
if (imageUrl.startsWith('https:') || imageUrl.startsWith('http:')) {
|
||||
return imageUrl;
|
||||
}
|
||||
|
||||
if (imageUrl.startsWith('/')) {
|
||||
return new URL(`/files${imageUrl}`, baseUrl).toString();
|
||||
}
|
||||
|
||||
return new URL(`/files/${imageUrl}`, baseUrl).toString();
|
||||
};
|
||||
24
packages/twenty-shared/tsconfig.json
Normal file
24
packages/twenty-shared/tsconfig.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": false,
|
||||
"esModuleInterop": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
"types": ["vite/client"],
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"twenty-shared": ["packages/twenty-shared/dist"]
|
||||
}
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
],
|
||||
"extends": "../../tsconfig.base.json"
|
||||
}
|
||||
22
packages/twenty-shared/tsconfig.lib.json
Normal file
22
packages/twenty-shared/tsconfig.lib.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../.cache/tsc",
|
||||
"types": [
|
||||
"node",
|
||||
"vite/client"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.test.ts",
|
||||
"**/*.spec.tsx",
|
||||
"**/*.test.tsx",
|
||||
"**/*.spec.js",
|
||||
"**/*.test.js",
|
||||
"**/*.spec.jsx",
|
||||
"**/*.test.jsx"
|
||||
],
|
||||
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"],
|
||||
|
||||
}
|
||||
17
packages/twenty-shared/tsconfig.spec.json
Normal file
17
packages/twenty-shared/tsconfig.spec.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"types": ["jest", "node"]
|
||||
},
|
||||
"include": [
|
||||
"**/__mocks__/**/*",
|
||||
"jest.config.ts",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.spec.tsx",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.test.tsx",
|
||||
"vite.config.ts"
|
||||
]
|
||||
}
|
||||
33
packages/twenty-shared/vite.config.ts
Normal file
33
packages/twenty-shared/vite.config.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import * as path from 'path';
|
||||
import { defineConfig } from 'vite';
|
||||
import dts from 'vite-plugin-dts';
|
||||
import tsconfigPaths from 'vite-tsconfig-paths';
|
||||
|
||||
export default defineConfig({
|
||||
root: __dirname,
|
||||
cacheDir: '../../node_modules/.vite/packages/twenty-shared',
|
||||
|
||||
plugins: [
|
||||
tsconfigPaths(),
|
||||
dts({
|
||||
entryRoot: 'src',
|
||||
tsconfigPath: path.join(__dirname, 'tsconfig.lib.json'),
|
||||
}),
|
||||
],
|
||||
|
||||
// Configuration for building your library.
|
||||
// See: https://vitejs.dev/guide/build.html#library-mode
|
||||
build: {
|
||||
outDir: './dist',
|
||||
reportCompressedSize: true,
|
||||
commonjsOptions: {
|
||||
transformMixedEsModules: true,
|
||||
},
|
||||
lib: {
|
||||
entry: 'src/index.ts',
|
||||
name: 'twenty-shared',
|
||||
fileName: 'index',
|
||||
formats: ['es', 'cjs'],
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user