Compare commits

...

4 Commits

Author SHA1 Message Date
Weiko bd130a8b9f upgrade package json 2024-09-30 16:22:40 +02:00
Weiko 5f1d3615c0 increase export feature page size (#7341)
## Context
Now that we have improved performances, we can increase the export
feature page size from 30 to 200 (and probably above if results are
good). This should be ok since we are only querying the first level of
an object and omit relations.
I've moved this value to a constant.
2024-09-30 15:58:20 +02:00
Charles Bochet 3ca31f95a7 Support Emails and Phones in spreadsheet import 2024-09-28 16:04:15 +02:00
Charles Bochet 4630680d1b Fast follows on v0.30 2024-09-28 15:28:17 +02:00
13 changed files with 101 additions and 13 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "twenty-emails",
"version": "0.30.0",
"version": "0.30.2",
"description": "",
"author": "",
"private": true,
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "twenty-front",
"version": "0.30.0",
"version": "0.30.2",
"private": true,
"type": "module",
"scripts": {
@@ -179,7 +179,6 @@ export const CommandMenu = () => {
'emails',
['primaryEmail'],
),
{ phone: { ilike: `%${commandMenuSearch}%` } },
])
: undefined,
limit: 3,
@@ -0,0 +1 @@
export const EXPORT_TABLE_DATA_DEFAULT_PAGE_SIZE = 200;
@@ -2,6 +2,7 @@ import { json2csv } from 'json-2-csv';
import { useMemo } from 'react';
import { FieldMetadata } from '@/object-record/record-field/types/FieldMetadata';
import { EXPORT_TABLE_DATA_DEFAULT_PAGE_SIZE } from '@/object-record/record-index/options/constants/ExportTableDataDefaultPageSize';
import { useProcessRecordsForCSVExport } from '@/object-record/record-index/options/hooks/useProcessRecordsForCSVExport';
import {
useTableData,
@@ -142,7 +143,7 @@ export const useExportTableData = ({
filename,
maximumRequests = 100,
objectNameSingular,
pageSize = 30,
pageSize = EXPORT_TABLE_DATA_DEFAULT_PAGE_SIZE,
recordIndexId,
viewType,
}: UseExportTableDataOptions) => {
@@ -9,6 +9,7 @@ import { ObjectRecord } from '@/object-record/types/ObjectRecord';
import { isDefined } from '~/utils/isDefined';
import { useRecordBoardStates } from '@/object-record/record-board/hooks/internal/useRecordBoardStates';
import { EXPORT_TABLE_DATA_DEFAULT_PAGE_SIZE } from '@/object-record/record-index/options/constants/ExportTableDataDefaultPageSize';
import { useRecordIndexOptionsForBoard } from '@/object-record/record-index/options/hooks/useRecordIndexOptionsForBoard';
import { ViewType } from '@/views/types/ViewType';
import { useFindManyParams } from '../../hooks/useLoadRecordIndexTable';
@@ -43,7 +44,7 @@ export const useTableData = ({
delayMs,
maximumRequests = 100,
objectNameSingular,
pageSize = 30,
pageSize = EXPORT_TABLE_DATA_DEFAULT_PAGE_SIZE,
recordIndexId,
callback,
viewType = ViewType.Table,
@@ -1,8 +1,10 @@
import {
FieldAddressValue,
FieldCurrencyValue,
FieldEmailsValue,
FieldFullNameValue,
FieldLinksValue,
FieldPhonesValue,
} from '@/object-record/record-field/types/FieldMetadata';
import { CompositeFieldLabels } from '@/object-record/spreadsheet-import/types/CompositeFieldLabels';
import { FieldMetadataType } from '~/generated-metadata/graphql';
@@ -30,6 +32,13 @@ export const COMPOSITE_FIELD_IMPORT_LABELS = {
primaryLinkUrlLabel: 'Link URL',
primaryLinkLabelLabel: 'Link Label',
} satisfies Partial<CompositeFieldLabels<FieldLinksValue>>,
[FieldMetadataType.Emails]: {
primaryEmailLabel: 'Email',
} satisfies Partial<CompositeFieldLabels<FieldEmailsValue>>,
[FieldMetadataType.Phones]: {
primaryPhoneCountryCodeLabel: 'Phone country code',
primaryPhoneNumberLabel: 'Phone number',
} satisfies Partial<CompositeFieldLabels<FieldPhonesValue>>,
[FieldMetadataType.Actor]: {
sourceLabel: 'Source',
},
@@ -15,6 +15,7 @@ export const useBuildAvailableFieldsForImport = () => {
) => {
const availableFieldsForImport: AvailableFieldForImport[] = [];
// Todo: refactor this to avoid this else if syntax with duplicated code
for (const fieldMetadataItem of fieldMetadataItems) {
if (fieldMetadataItem.type === FieldMetadataType.FullName) {
const { firstNameLabel, lastNameLabel } =
@@ -155,6 +156,42 @@ export const useBuildAvailableFieldsForImport = () => {
fieldMetadataItem.label,
),
});
} else if (fieldMetadataItem.type === FieldMetadataType.Emails) {
Object.entries(
COMPOSITE_FIELD_IMPORT_LABELS[FieldMetadataType.Emails],
).forEach(([_, fieldLabel]) => {
availableFieldsForImport.push({
icon: getIcon(fieldMetadataItem.icon),
label: `${fieldLabel} (${fieldMetadataItem.label})`,
key: `${fieldLabel} (${fieldMetadataItem.name})`,
fieldType: {
type: 'input',
},
fieldValidationDefinitions:
getSpreadSheetFieldValidationDefinitions(
fieldMetadataItem.type,
`${fieldLabel} (${fieldMetadataItem.label})`,
),
});
});
} else if (fieldMetadataItem.type === FieldMetadataType.Phones) {
Object.entries(
COMPOSITE_FIELD_IMPORT_LABELS[FieldMetadataType.Phones],
).forEach(([_, fieldLabel]) => {
availableFieldsForImport.push({
icon: getIcon(fieldMetadataItem.icon),
label: `${fieldLabel} (${fieldMetadataItem.label})`,
key: `${fieldLabel} (${fieldMetadataItem.name})`,
fieldType: {
type: 'input',
},
fieldValidationDefinitions:
getSpreadSheetFieldValidationDefinitions(
fieldMetadataItem.type,
`${fieldLabel} (${fieldMetadataItem.label})`,
),
});
});
} else {
availableFieldsForImport.push({
icon: getIcon(fieldMetadataItem.icon),
@@ -1,7 +1,9 @@
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
import {
FieldAddressValue,
FieldEmailsValue,
FieldLinksValue,
FieldPhonesValue,
} from '@/object-record/record-field/types/FieldMetadata';
import { COMPOSITE_FIELD_IMPORT_LABELS } from '@/object-record/spreadsheet-import/constants/CompositeFieldImportLabels';
import { ImportedStructuredRow } from '@/spreadsheet-import/types';
@@ -31,6 +33,8 @@ export const buildRecordFromImportedStructuredRow = (
CURRENCY: { amountMicrosLabel, currencyCodeLabel },
FULL_NAME: { firstNameLabel, lastNameLabel },
LINKS: { primaryLinkLabelLabel, primaryLinkUrlLabel },
EMAILS: { primaryEmailLabel },
PHONES: { primaryPhoneNumberLabel, primaryPhoneCountryCodeLabel },
} = COMPOSITE_FIELD_IMPORT_LABELS;
for (const field of fields) {
@@ -129,14 +133,48 @@ export const buildRecordFromImportedStructuredRow = (
}
break;
}
case FieldMetadataType.Link:
if (importedFieldValue !== undefined) {
case FieldMetadataType.Phones: {
if (
isDefined(
importedStructuredRow[
`${primaryPhoneCountryCodeLabel} (${field.name})`
] ||
importedStructuredRow[
`${primaryPhoneNumberLabel} (${field.name})`
],
)
) {
recordToBuild[field.name] = {
label: field.name,
url: importedFieldValue || null,
};
primaryPhoneCountryCode: castToString(
importedStructuredRow[
`${primaryPhoneCountryCodeLabel} (${field.name})`
],
),
primaryPhoneNumber: castToString(
importedStructuredRow[
`${primaryPhoneNumberLabel} (${field.name})`
],
),
additionalPhones: null,
} satisfies FieldPhonesValue;
}
break;
}
case FieldMetadataType.Emails: {
if (
isDefined(
importedStructuredRow[`${primaryEmailLabel} (${field.name})`],
)
) {
recordToBuild[field.name] = {
primaryEmail: castToString(
importedStructuredRow[`${primaryEmailLabel} (${field.name})`],
),
additionalEmails: null,
} satisfies FieldEmailsValue;
}
break;
}
case FieldMetadataType.Relation:
if (
isDefined(importedFieldValue) &&
@@ -50,6 +50,8 @@ export const sanitizeRecordInput = ({
return undefined;
}
// Todo: we should check that the fieldValue is a valid value
// (e.g. a string for a string field, following the right composite structure for composite fields)
return [fieldName, fieldValue];
})
.filter(isDefined),
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "twenty-server",
"version": "0.30.0",
"version": "0.30.2",
"description": "",
"author": "",
"private": true,
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "twenty-ui",
"version": "0.30.0",
"version": "0.30.2",
"type": "module",
"main": "./src/index.ts",
"exports": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "twenty-website",
"version": "0.30.0",
"version": "0.30.2",
"private": true,
"scripts": {
"nx": "NX_DEFAULT_PROJECT=twenty-website node ../../node_modules/nx/bin/nx.js",