download record sample - Import (#12489)

<img width="400" alt="Screenshot 2025-06-10 at 18 14 17"
src="https://github.com/user-attachments/assets/05591b46-c36d-45c6-a236-3469c29d7420"
/>


closes https://github.com/twentyhq/core-team-issues/issues/915

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Etienne
2025-06-16 16:01:27 +02:00
committed by GitHub
parent 79b8c4660c
commit c16ba6a7d7
32 changed files with 753 additions and 481 deletions
@@ -0,0 +1,24 @@
import { escapeCSVValue } from '@/spreadsheet-import/utils/escapeCSVValue';
describe('escapeCSVValue', () => {
it('should escape values with commas, quotes, newlines and carriage returns', () => {
expect(escapeCSVValue('test,test')).toBe('"test,test"');
});
it('should escape array or JSON values', () => {
expect(escapeCSVValue(['test', 'test'])).toBe('"[""test"",""test""]"');
expect(escapeCSVValue({ test: 'test' })).toBe('"{""test"":""test""}"');
});
it('should escape null values', () => {
expect(escapeCSVValue(null)).toBe('');
});
it('should escape simple string value', () => {
expect(escapeCSVValue('test')).toBe('test');
});
it('should escape simple number value', () => {
expect(escapeCSVValue(1)).toBe('1');
});
});
@@ -1,65 +0,0 @@
import { SpreadsheetImportField } from '@/spreadsheet-import/types';
import { generateExampleRow } from '@/spreadsheet-import/utils/generateExampleRow';
import { FieldMetadataType } from 'twenty-shared/types';
describe('generateExampleRow', () => {
const defaultField: SpreadsheetImportField<'defaultField'> = {
key: 'defaultField',
Icon: null,
label: 'label',
fieldType: {
type: 'input',
},
fieldMetadataType: FieldMetadataType.TEXT,
};
it('should generate an example row from input field type', () => {
const fields: SpreadsheetImportField<'defaultField'>[] = [defaultField];
const result = generateExampleRow(fields);
expect(result).toStrictEqual([{ defaultField: 'Text' }]);
});
it('should generate an example row from checkbox field type', () => {
const fields: SpreadsheetImportField<'defaultField'>[] = [
{
...defaultField,
fieldType: { type: 'checkbox' },
fieldMetadataType: FieldMetadataType.BOOLEAN,
},
];
const result = generateExampleRow(fields);
expect(result).toStrictEqual([{ defaultField: 'Boolean' }]);
});
it('should generate an example row from select field type', () => {
const fields: SpreadsheetImportField<'defaultField'>[] = [
{
...defaultField,
fieldType: { type: 'select', options: [] },
fieldMetadataType: FieldMetadataType.SELECT,
},
];
const result = generateExampleRow(fields);
expect(result).toStrictEqual([{ defaultField: 'Options' }]);
});
it('should generate an example row with provided example values for fields', () => {
const fields: SpreadsheetImportField<'defaultField'>[] = [
{
...defaultField,
example: 'Example',
fieldMetadataType: FieldMetadataType.TEXT,
},
];
const result = generateExampleRow(fields);
expect(result).toStrictEqual([{ defaultField: 'Example' }]);
});
});
@@ -0,0 +1,18 @@
import { isString } from '@sniptt/guards';
export const escapeCSVValue = (value: any) => {
if (value == null) return '';
const stringValue = isString(value) ? value : JSON.stringify(value);
if (
stringValue.includes(',') ||
stringValue.includes('"') ||
stringValue.includes('\n') ||
stringValue.includes('\r')
) {
return `"${stringValue.replace(/"/g, '""')}"`;
}
return stringValue;
};
@@ -1,26 +0,0 @@
import {
SpreadsheetImportField,
SpreadsheetImportFields,
} from '@/spreadsheet-import/types';
const titleMap: Record<
SpreadsheetImportField<string>['fieldType']['type'],
string
> = {
checkbox: 'Boolean',
select: 'Options',
multiSelect: 'Options',
input: 'Text',
};
export const generateExampleRow = <T extends string>(
fields: SpreadsheetImportFields<T>,
) => [
fields.reduce(
(acc, field) => {
acc[field.key as T] = field.example || titleMap[field.fieldType.type];
return acc;
},
{} as Record<T, string>,
),
];