Skip to content

Commit

Permalink
Merge branch 'main' into feat/8016-current-workspace-member-filter-an…
Browse files Browse the repository at this point in the history
…d-refactor
  • Loading branch information
ad-elias committed Dec 20, 2024
2 parents b466d66 + 03f8979 commit b3d1740
Show file tree
Hide file tree
Showing 109 changed files with 2,076 additions and 1,329 deletions.
10 changes: 10 additions & 0 deletions packages/twenty-front/nyc.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,21 @@ const pagesCoverage = {
exclude: ['src/generated/**/*', 'src/modules/**/*', 'src/**/*.ts'],
};

const performanceCoverage = {
branches: 35,
statements: 60,
lines: 60,
functions: 45,
exclude: ['src/generated/**/*', 'src/modules/**/*', 'src/**/*.ts'],
};

const storybookStoriesFolders = process.env.STORYBOOK_SCOPE;

module.exports =
storybookStoriesFolders === 'pages'
? pagesCoverage
: storybookStoriesFolders === 'modules'
? modulesCoverage
: storybookStoriesFolders === 'performance'
? performanceCoverage
: globalCoverage;
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { MultipleRecordsActionKeys } from '@/action-menu/actions/record-actions/multiple-records/types/MultipleRecordsActionKeys';
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries';
import {
Expand All @@ -8,13 +9,12 @@ import { contextStoreFiltersComponentState } from '@/context-store/states/contex
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
import { computeContextStoreFilters } from '@/context-store/utils/computeContextStoreFilters';
import { useDeleteFavorite } from '@/favorites/hooks/useDeleteFavorite';
import { useFavorites } from '@/favorites/hooks/useFavorites';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { DEFAULT_QUERY_PAGE_SIZE } from '@/object-record/constants/DefaultQueryPageSize';
import { DELETE_MAX_COUNT } from '@/object-record/constants/DeleteMaxCount';
import { useDeleteManyRecords } from '@/object-record/hooks/useDeleteManyRecords';
import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords';
import { FilterOperand } from '@/object-record/object-filter-dropdown/types/FilterOperand';
import { useFilterValueDependencies } from '@/object-record/record-filter/hooks/useFilterValueDependencies';
import { useRecordTable } from '@/object-record/record-table/hooks/useRecordTable';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
Expand All @@ -41,9 +41,6 @@ export const useDeleteMultipleRecordsAction = ({
objectNameSingular: objectMetadataItem.nameSingular,
});

const { sortedFavorites: favorites } = useFavorites();
const { deleteFavorite } = useDeleteFavorite();

const contextStoreNumberOfSelectedRecords = useRecoilComponentValueV2(
contextStoreNumberOfSelectedRecordsComponentState,
);
Expand All @@ -65,6 +62,16 @@ export const useDeleteMultipleRecordsAction = ({
filterValueDependencies,
);

const deletedAtFieldMetadata = objectMetadataItem.fields.find(
(field) => field.name === 'deletedAt',
);

const isDeletedFilterActive = contextStoreFilters.some(
(filter) =>
filter.fieldMetadataId === deletedAtFieldMetadata?.id &&
filter.operand === FilterOperand.IsNotEmpty,
);

const { fetchAllRecords: fetchAllRecordIds } = useLazyFetchAllRecords({
objectNameSingular: objectMetadataItem.nameSingular,
filter: graphqlFilter,
Expand All @@ -80,36 +87,19 @@ export const useDeleteMultipleRecordsAction = ({

resetTableRowSelection();

for (const recordIdToDelete of recordIdsToDelete) {
const foundFavorite = favorites?.find(
(favorite) => favorite.recordId === recordIdToDelete,
);

if (foundFavorite !== undefined) {
deleteFavorite(foundFavorite.id);
}
}

await deleteManyRecords(recordIdsToDelete, {
delayInMsBetweenRequests: 50,
});
}, [
deleteFavorite,
deleteManyRecords,
favorites,
fetchAllRecordIds,
resetTableRowSelection,
]);
await deleteManyRecords(recordIdsToDelete);
}, [deleteManyRecords, fetchAllRecordIds, resetTableRowSelection]);

const isRemoteObject = objectMetadataItem.isRemote;

const canDelete =
!isRemoteObject &&
!isDeletedFilterActive &&
isDefined(contextStoreNumberOfSelectedRecords) &&
contextStoreNumberOfSelectedRecords < DELETE_MAX_COUNT &&
contextStoreNumberOfSelectedRecords > 0;

const { isInRightDrawer, onActionExecutedCallback } =
const { isInRightDrawer, onActionStartedCallback, onActionExecutedCallback } =
useContext(ActionMenuContext);

const registerDeleteMultipleRecordsAction = ({
Expand All @@ -121,7 +111,7 @@ export const useDeleteMultipleRecordsAction = ({
addActionMenuEntry({
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: 'delete-multiple-records',
key: MultipleRecordsActionKeys.DELETE,
label: 'Delete records',
shortLabel: 'Delete',
position,
Expand All @@ -137,9 +127,14 @@ export const useDeleteMultipleRecordsAction = ({
setIsOpen={setIsDeleteRecordsModalOpen}
title={'Delete Records'}
subtitle={`Are you sure you want to delete these records? They can be recovered from the Options menu.`}
onConfirmClick={() => {
handleDeleteClick();
onActionExecutedCallback?.();
onConfirmClick={async () => {
onActionStartedCallback?.({
key: 'delete-multiple-records',
});
await handleDeleteClick();
onActionExecutedCallback?.({
key: 'delete-multiple-records',
});
if (isInRightDrawer) {
closeRightDrawer();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { IconDatabaseExport } from 'twenty-ui';

import { MultipleRecordsActionKeys } from '@/action-menu/actions/record-actions/multiple-records/types/MultipleRecordsActionKeys';
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
import {
ActionMenuEntryScope,
ActionMenuEntryType,
Expand All @@ -10,6 +12,7 @@ import {
displayedExportProgress,
useExportRecords,
} from '@/object-record/record-index/export/hooks/useExportRecords';
import { useContext } from 'react';

export const useExportMultipleRecordsAction = ({
objectMetadataItem,
Expand All @@ -25,6 +28,9 @@ export const useExportMultipleRecordsAction = ({
filename: `${objectMetadataItem.nameSingular}.csv`,
});

const { onActionStartedCallback, onActionExecutedCallback } =
useContext(ActionMenuContext);

const registerExportMultipleRecordsAction = ({
position,
}: {
Expand All @@ -33,13 +39,21 @@ export const useExportMultipleRecordsAction = ({
addActionMenuEntry({
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: 'export-multiple-records',
key: MultipleRecordsActionKeys.EXPORT,
position,
label: displayedExportProgress(progress),
shortLabel: 'Export',
Icon: IconDatabaseExport,
accent: 'default',
onClick: () => download(),
onClick: async () => {
await onActionStartedCallback?.({
key: MultipleRecordsActionKeys.EXPORT,
});
await download();
await onActionExecutedCallback?.({
key: MultipleRecordsActionKeys.EXPORT,
});
},
});
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export enum MultipleRecordsActionKeys {
DELETE = 'delete-multiple-records',
EXPORT = 'export-multiple-records',
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { IconDatabaseExport } from 'twenty-ui';

import { NoSelectionRecordActionKeys } from '@/action-menu/actions/record-actions/no-selection/types/NoSelectionRecordActionsKey';
import {
ActionMenuEntryScope,
ActionMenuEntryType,
Expand Down Expand Up @@ -33,7 +34,7 @@ export const useExportViewNoSelectionRecordAction = ({
addActionMenuEntry({
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.Global,
key: 'export-view-no-selection',
key: NoSelectionRecordActionKeys.EXPORT_VIEW,
position,
label: displayedExportProgress(progress),
Icon: IconDatabaseExport,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export enum NoSelectionRecordActionKeys {
EXPORT_VIEW = 'export-view-no-selection',
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { getActionConfig } from '@/action-menu/actions/record-actions/single-record/utils/getActionConfig';
import { ActionAvailableOn } from '@/action-menu/actions/types/actionAvailableOn';
import { ActionAvailableOn } from '@/action-menu/actions/types/ActionAvailableOn';
import { wrapActionInCallbacks } from '@/action-menu/actions/utils/wrapActionInCallbacks';
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries';
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { useEffect } from 'react';
import { useContext, useEffect } from 'react';
import { isDefined } from 'twenty-ui';

export const ShowPageSingleRecordActionMenuEntrySetterEffect = ({
Expand Down Expand Up @@ -36,6 +38,8 @@ export const ShowPageSingleRecordActionMenuEntrySetterEffect = ({
if (!isDefined(selectedRecordId)) {
throw new Error('Selected record ID is required');
}
const { onActionStartedCallback, onActionExecutedCallback } =
useContext(ActionMenuContext);

const actionMenuEntries = Object.values(actionConfig ?? {})
.filter((action) =>
Expand All @@ -48,15 +52,21 @@ export const ShowPageSingleRecordActionMenuEntrySetterEffect = ({
objectMetadataItem,
});

if (shouldBeRegistered) {
return {
if (!shouldBeRegistered) {
return undefined;
}

const wrappedAction = wrapActionInCallbacks({
action: {
...action,
onClick,
ConfirmationModal,
};
}
},
onActionStartedCallback,
onActionExecutedCallback,
});

return undefined;
return wrappedAction;
})
.filter(isDefined);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { getActionConfig } from '@/action-menu/actions/record-actions/single-record/utils/getActionConfig';
import { ActionAvailableOn } from '@/action-menu/actions/types/actionAvailableOn';
import { ActionAvailableOn } from '@/action-menu/actions/types/ActionAvailableOn';
import { wrapActionInCallbacks } from '@/action-menu/actions/utils/wrapActionInCallbacks';
import { ActionMenuContext } from '@/action-menu/contexts/ActionMenuContext';
import { useActionMenuEntries } from '@/action-menu/hooks/useActionMenuEntries';
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
import { useEffect } from 'react';
import { useContext, useEffect } from 'react';
import { isDefined } from 'twenty-ui';

export const SingleRecordActionMenuEntrySetterEffect = ({
Expand Down Expand Up @@ -37,6 +39,9 @@ export const SingleRecordActionMenuEntrySetterEffect = ({
throw new Error('Selected record ID is required');
}

const { onActionStartedCallback, onActionExecutedCallback } =
useContext(ActionMenuContext);

const actionMenuEntries = Object.values(actionConfig ?? {})
.filter((action) =>
action.availableOn?.includes(
Expand All @@ -50,15 +55,21 @@ export const SingleRecordActionMenuEntrySetterEffect = ({
objectMetadataItem,
});

if (shouldBeRegistered) {
return {
if (!shouldBeRegistered) {
return undefined;
}

const wrappedAction = wrapActionInCallbacks({
action: {
...action,
onClick,
ConfirmationModal,
};
}
},
onActionStartedCallback,
onActionExecutedCallback,
});

return undefined;
return wrappedAction;
})
.filter(isDefined);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useAddToFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useAddToFavoritesSingleRecordAction';
import { useDeleteSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useDeleteSingleRecordAction';
import { useRemoveFromFavoritesSingleRecordAction } from '@/action-menu/actions/record-actions/single-record/hooks/useRemoveFromFavoritesSingleRecordAction';
import { ActionAvailableOn } from '@/action-menu/actions/types/actionAvailableOn';
import { SingleRecordActionHook } from '@/action-menu/actions/types/singleRecordActionHook';
import { SingleRecordActionKeys } from '@/action-menu/actions/record-actions/single-record/types/SingleRecordActionsKey';
import { ActionAvailableOn } from '@/action-menu/actions/types/ActionAvailableOn';
import { SingleRecordActionHook } from '@/action-menu/actions/types/SingleRecordActionHook';
import {
ActionMenuEntry,
ActionMenuEntryScope,
Expand All @@ -19,7 +20,7 @@ export const DEFAULT_SINGLE_RECORD_ACTIONS_CONFIG_V1: Record<
addToFavoritesSingleRecord: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: 'add-to-favorites-single-record',
key: SingleRecordActionKeys.ADD_TO_FAVORITES,
label: 'Add to favorites',
position: 0,
Icon: IconHeart,
Expand All @@ -32,7 +33,7 @@ export const DEFAULT_SINGLE_RECORD_ACTIONS_CONFIG_V1: Record<
removeFromFavoritesSingleRecord: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: 'remove-from-favorites-single-record',
key: SingleRecordActionKeys.REMOVE_FROM_FAVORITES,
label: 'Remove from favorites',
position: 1,
Icon: IconHeartOff,
Expand All @@ -45,7 +46,7 @@ export const DEFAULT_SINGLE_RECORD_ACTIONS_CONFIG_V1: Record<
deleteSingleRecord: {
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
key: 'delete-single-record',
key: SingleRecordActionKeys.DELETE,
label: 'Delete',
position: 2,
Icon: IconTrash,
Expand Down
Loading

0 comments on commit b3d1740

Please sign in to comment.