Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement contextual actions for the workflows #8814

Merged
merged 51 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
85941d1
create activate workflow action effect
bosiraphael Oct 29, 2024
d1740cd
add ActivateWorkflowActionEffect to setter
bosiraphael Oct 29, 2024
d9eb528
Add see executions action
bosiraphael Oct 29, 2024
1702bad
add deactivate option
bosiraphael Oct 29, 2024
9c33f73
update dependency array
bosiraphael Oct 30, 2024
7770145
Merge branch 'main' into implement-contextual-actions-for-the-workflows
bosiraphael Nov 27, 2024
09b2c3d
use hooks
bosiraphael Nov 27, 2024
a218ea1
fix see workflow executions
bosiraphael Nov 27, 2024
7f690ae
modify icon
bosiraphael Nov 27, 2024
c490e9b
refactor action hooks
bosiraphael Nov 27, 2024
18f2380
create useSeeWorkflowActiveVersionSingleRecordAction
bosiraphael Nov 27, 2024
8e68e19
add useSeeWorkflowActiveVersionSingleRecordAction
bosiraphael Nov 28, 2024
8eb2e7f
show see workflow active version conditionnally if it's a draft
bosiraphael Nov 28, 2024
0f2a0b9
add useActivateWorkflowDraftSingleRecordAction
bosiraphael Nov 28, 2024
ad2f580
add useDiscardWorkflowDraftSingleRecordAction
bosiraphael Nov 28, 2024
8e7c5c7
refactor single record actions
bosiraphael Nov 28, 2024
27d5d7e
create test workflow action
bosiraphael Nov 28, 2024
53f1f83
Merge branch 'main' of github.com:twentyhq/twenty into implement-cont…
bosiraphael Nov 28, 2024
2c0c7e3
Refactor single record actions
bosiraphael Nov 28, 2024
5b91b32
add action for workflow versions
bosiraphael Nov 29, 2024
e898a9e
remove console log
bosiraphael Nov 29, 2024
742ae30
Merge branch 'main' into implement-contextual-actions-for-the-workflows
bosiraphael Nov 29, 2024
2f899f5
fix after merge
bosiraphael Nov 29, 2024
98b912a
renaming
bosiraphael Nov 29, 2024
08b05a9
create use as draft action
bosiraphael Nov 29, 2024
2157cd8
do not show use as draft if draft
bosiraphael Nov 29, 2024
4fc0ddd
add discard draft workflow version action
bosiraphael Nov 29, 2024
0c9bcd6
fix
bosiraphael Nov 29, 2024
b4dc811
add see executions action
bosiraphael Nov 29, 2024
adcab24
test should be fixed
bosiraphael Nov 29, 2024
b1a9a88
Merge branch 'main' of github.com:twentyhq/twenty into implement-cont…
bosiraphael Dec 2, 2024
5aa2579
fix incorrect condition
bosiraphael Dec 2, 2024
dda2da5
remove redundant check
bosiraphael Dec 2, 2024
cede6a8
Fix chek
bosiraphael Dec 2, 2024
07b8efb
Fix tests
charlesBochet Dec 2, 2024
202f216
remove unnecessary code
bosiraphael Dec 2, 2024
3b260b2
Merge branch 'implement-contextual-actions-for-the-workflows' of gith…
bosiraphael Dec 2, 2024
ff748ec
fix check
bosiraphael Dec 2, 2024
9111d8e
fixes
bosiraphael Dec 2, 2024
7af4387
add single-record in action key
bosiraphael Dec 2, 2024
ea03b24
add tests
bosiraphael Dec 2, 2024
9db7f6f
add test
bosiraphael Dec 2, 2024
29d02ef
add test
bosiraphael Dec 2, 2024
84ed324
add test
bosiraphael Dec 2, 2024
1a1e5b4
fix position
bosiraphael Dec 2, 2024
97db9ea
add constant NUMBER_OF_STANDARD_SINGLE_RECORD_ACTIONS_ON_ALL_OBJECTS
bosiraphael Dec 2, 2024
b6ddd93
add test
bosiraphael Dec 2, 2024
14bf0ab
add test
bosiraphael Dec 2, 2024
6d4b451
Merge branch 'main' into implement-contextual-actions-for-the-workflows
bosiraphael Dec 3, 2024
ee096cf
modifications after review
bosiraphael Dec 3, 2024
7415e0e
fix tests
bosiraphael Dec 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { MultipleRecordsActionMenuEntrySetterEffect } from '@/action-menu/actions/record-actions/multiple-records/components/MultipleRecordsActionMenuEntrySetterEffect';
import { NoSelectionActionMenuEntrySetterEffect } from '@/action-menu/actions/record-actions/no-selection/components/NoSelectionActionMenuEntrySetterEffect';
import { SingleRecordActionMenuEntrySetterEffect } from '@/action-menu/actions/record-actions/single-record/components/SingleRecordActionMenuEntrySetterEffect';
import { SingleRecordActionMenuEntrySetter } from '@/action-menu/actions/record-actions/single-record/components/SingleRecordActionMenuEntrySetter';
import { WorkflowRunRecordActionMenuEntrySetterEffect } from '@/action-menu/actions/record-actions/workflow-run-record-actions/components/WorkflowRunRecordActionMenuEntrySetter';
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
Expand Down Expand Up @@ -32,30 +32,35 @@ const ActionEffects = ({
objectId: objectMetadataItemId,
});

const contextStoreNumberOfSelectedRecords = useRecoilComponentValueV2(
contextStoreNumberOfSelectedRecordsComponentState,
const contextStoreTargetedRecordsRule = useRecoilComponentValueV2(
contextStoreTargetedRecordsRuleComponentState,
);

const isWorkflowEnabled = useIsFeatureEnabled('IS_WORKFLOW_ENABLED');

return (
<>
{contextStoreNumberOfSelectedRecords === 0 && (
<NoSelectionActionMenuEntrySetterEffect
objectMetadataItem={objectMetadataItem}
/>
)}
{contextStoreNumberOfSelectedRecords === 1 && (
<SingleRecordActionMenuEntrySetterEffect
objectMetadataItem={objectMetadataItem}
/>
)}
{contextStoreNumberOfSelectedRecords === 1 && isWorkflowEnabled && (
<WorkflowRunRecordActionMenuEntrySetterEffect
objectMetadataItem={objectMetadataItem}
/>
)}
{contextStoreNumberOfSelectedRecords > 1 && (
{contextStoreTargetedRecordsRule.mode === 'selection' &&
contextStoreTargetedRecordsRule.selectedRecordIds.length === 0 && (
<NoSelectionActionMenuEntrySetterEffect
objectMetadataItem={objectMetadataItem}
/>
)}
{contextStoreTargetedRecordsRule.mode === 'selection' &&
contextStoreTargetedRecordsRule.selectedRecordIds.length === 1 && (
<>
<SingleRecordActionMenuEntrySetter
objectMetadataItem={objectMetadataItem}
/>
{isWorkflowEnabled && (
<WorkflowRunRecordActionMenuEntrySetterEffect
objectMetadataItem={objectMetadataItem}
/>
)}
</>
)}
{(contextStoreTargetedRecordsRule.mode === 'exclusion' ||
contextStoreTargetedRecordsRule.selectedRecordIds.length > 1) && (
<MultipleRecordsActionMenuEntrySetterEffect
objectMetadataItem={objectMetadataItem}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState';
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { expect } from '@storybook/test';
import { renderHook } from '@testing-library/react';
import { act } from 'react';
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { useDeleteMultipleRecordsAction } from '../useDeleteMultipleRecordsAction';

jest.mock('@/object-record/hooks/useDeleteManyRecords', () => ({
useDeleteManyRecords: () => ({
deleteManyRecords: jest.fn(),
}),
}));
jest.mock('@/favorites/hooks/useDeleteFavorite', () => ({
useDeleteFavorite: () => ({
deleteFavorite: jest.fn(),
}),
}));
jest.mock('@/favorites/hooks/useFavorites', () => ({
useFavorites: () => ({
sortedFavorites: [],
}),
}));
jest.mock('@/object-record/record-table/hooks/useRecordTable', () => ({
useRecordTable: () => ({
resetTableRowSelection: jest.fn(),
}),
}));

const companyMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
(item) => item.nameSingular === 'company',
)!;

const JestMetadataAndApolloMocksWrapper = getJestMetadataAndApolloMocksWrapper({
apolloMocks: [],
onInitializeRecoilSnapshot: ({ set }) => {
set(
contextStoreNumberOfSelectedRecordsComponentState.atomFamily({
instanceId: '1',
}),
3,
);
},
});

describe('useDeleteMultipleRecordsAction', () => {
const wrapper = ({ children }: { children: React.ReactNode }) => (
<JestMetadataAndApolloMocksWrapper>
<ContextStoreComponentInstanceContext.Provider
value={{
instanceId: '1',
}}
>
<ActionMenuComponentInstanceContext.Provider
value={{
instanceId: '1',
}}
>
{children}
</ActionMenuComponentInstanceContext.Provider>
</ContextStoreComponentInstanceContext.Provider>
</JestMetadataAndApolloMocksWrapper>
);

it('should register delete action', () => {
const { result } = renderHook(
() => {
const actionMenuEntries = useRecoilComponentValueV2(
actionMenuEntriesComponentState,
);

return {
actionMenuEntries,
useDeleteMultipleRecordsAction: useDeleteMultipleRecordsAction({
objectMetadataItem: companyMockObjectMetadataItem,
}),
};
},
{ wrapper },
);

act(() => {
result.current.useDeleteMultipleRecordsAction.registerDeleteMultipleRecordsAction(
{ position: 1 },
);
});

expect(result.current.actionMenuEntries.size).toBe(1);
expect(
result.current.actionMenuEntries.get('delete-multiple-records'),
).toBeDefined();
expect(
result.current.actionMenuEntries.get('delete-multiple-records')?.position,
).toBe(1);
});

it('should unregister delete action', () => {
const { result } = renderHook(
() => {
const actionMenuEntries = useRecoilComponentValueV2(
actionMenuEntriesComponentState,
);

return {
actionMenuEntries,
useDeleteMultipleRecordsAction: useDeleteMultipleRecordsAction({
objectMetadataItem: companyMockObjectMetadataItem,
}),
};
},
{ wrapper },
);

act(() => {
result.current.useDeleteMultipleRecordsAction.registerDeleteMultipleRecordsAction(
{ position: 1 },
);
});

expect(result.current.actionMenuEntries.size).toBe(1);

act(() => {
result.current.useDeleteMultipleRecordsAction.unregisterDeleteMultipleRecordsAction();
});

expect(result.current.actionMenuEntries.size).toBe(0);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { actionMenuEntriesComponentState } from '@/action-menu/states/actionMenuEntriesComponentState';
import { ActionMenuComponentInstanceContext } from '@/action-menu/states/contexts/ActionMenuComponentInstanceContext';
import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext';
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
import { expect } from '@storybook/test';
import { renderHook } from '@testing-library/react';
import { act } from 'react';
import { JestObjectMetadataItemSetter } from '~/testing/jest/JestObjectMetadataItemSetter';
import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksWrapper';
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
import { useExportMultipleRecordsAction } from '../useExportMultipleRecordsAction';

const companyMockObjectMetadataItem = generatedMockObjectMetadataItems.find(
(item) => item.nameSingular === 'company',
)!;

const JestMetadataAndApolloMocksWrapper = getJestMetadataAndApolloMocksWrapper({
apolloMocks: [],
});

describe('useExportMultipleRecordsAction', () => {
const wrapper = ({ children }: { children: React.ReactNode }) => (
<JestMetadataAndApolloMocksWrapper>
<JestObjectMetadataItemSetter>
<ContextStoreComponentInstanceContext.Provider
value={{
instanceId: '1',
}}
>
<ActionMenuComponentInstanceContext.Provider
value={{
instanceId: '1',
}}
>
{children}
</ActionMenuComponentInstanceContext.Provider>
</ContextStoreComponentInstanceContext.Provider>
</JestObjectMetadataItemSetter>
</JestMetadataAndApolloMocksWrapper>
);

it('should register export multiple records action', () => {
const { result } = renderHook(
() => {
const actionMenuEntries = useRecoilComponentValueV2(
actionMenuEntriesComponentState,
);

return {
actionMenuEntries,
useExportMultipleRecordsAction: useExportMultipleRecordsAction({
objectMetadataItem: companyMockObjectMetadataItem,
}),
};
},
{ wrapper },
);

act(() => {
result.current.useExportMultipleRecordsAction.registerExportMultipleRecordsAction(
{ position: 1 },
);
});

expect(result.current.actionMenuEntries.size).toBe(1);
expect(
result.current.actionMenuEntries.get('export-multiple-records'),
).toBeDefined();
expect(
result.current.actionMenuEntries.get('export-multiple-records')?.position,
).toBe(1);
});

it('should unregister export multiple records action', () => {
const { result } = renderHook(
() => {
const actionMenuEntries = useRecoilComponentValueV2(
actionMenuEntriesComponentState,
);

return {
actionMenuEntries,
useExportMultipleRecordsAction: useExportMultipleRecordsAction({
objectMetadataItem: companyMockObjectMetadataItem,
}),
};
},
{ wrapper },
);

act(() => {
result.current.useExportMultipleRecordsAction.registerExportMultipleRecordsAction(
{ position: 1 },
);
});

expect(result.current.actionMenuEntries.size).toBe(1);

act(() => {
result.current.useExportMultipleRecordsAction.unregisterExportMultipleRecordsAction();
});

expect(result.current.actionMenuEntries.size).toBe(0);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,8 @@ import { useCallback, useContext, useState } from 'react';
import { IconTrash, isDefined } from 'twenty-ui';

export const useDeleteMultipleRecordsAction = ({
position,
objectMetadataItem,
}: {
position: number;
objectMetadataItem: ObjectMetadataItem;
}) => {
const { addActionMenuEntry, removeActionMenuEntry } = useActionMenuEntries();
Expand Down Expand Up @@ -106,7 +104,11 @@ export const useDeleteMultipleRecordsAction = ({
const { isInRightDrawer, onActionExecutedCallback } =
useContext(ActionMenuContext);

const registerDeleteMultipleRecordsAction = () => {
const registerDeleteMultipleRecordsAction = ({
position,
}: {
position: number;
}) => {
if (canDelete) {
addActionMenuEntry({
type: ActionMenuEntryType.Standard,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@ import {
} from '@/object-record/record-index/export/hooks/useExportRecords';

export const useExportMultipleRecordsAction = ({
position,
objectMetadataItem,
}: {
position: number;
objectMetadataItem: ObjectMetadataItem;
}) => {
const { addActionMenuEntry, removeActionMenuEntry } = useActionMenuEntries();
Expand All @@ -27,7 +25,11 @@ export const useExportMultipleRecordsAction = ({
filename: `${objectMetadataItem.nameSingular}.csv`,
});

const registerExportMultipleRecordsAction = () => {
const registerExportMultipleRecordsAction = ({
position,
}: {
position: number;
}) => {
addActionMenuEntry({
type: ActionMenuEntryType.Standard,
scope: ActionMenuEntryScope.RecordSelection,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useDeleteMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useDeleteMultipleRecordsAction';
import { useExportViewNoSelectionRecordAction } from '@/action-menu/actions/record-actions/no-selection/hooks/useExportMultipleRecordsAction';
import { useExportMultipleRecordsAction } from '@/action-menu/actions/record-actions/multiple-records/hooks/useExportMultipleRecordsAction';
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';

export const useMultipleRecordsActions = ({
Expand All @@ -11,26 +11,24 @@ export const useMultipleRecordsActions = ({
registerDeleteMultipleRecordsAction,
unregisterDeleteMultipleRecordsAction,
} = useDeleteMultipleRecordsAction({
position: 0,
objectMetadataItem,
});

const {
registerExportViewNoSelectionRecordsAction,
unregisterExportViewNoSelectionRecordsAction,
} = useExportViewNoSelectionRecordAction({
position: 1,
registerExportMultipleRecordsAction,
unregisterExportMultipleRecordsAction,
} = useExportMultipleRecordsAction({
objectMetadataItem,
});

const registerMultipleRecordsActions = () => {
registerDeleteMultipleRecordsAction();
registerExportViewNoSelectionRecordsAction();
registerDeleteMultipleRecordsAction({ position: 1 });
registerExportMultipleRecordsAction({ position: 2 });
};

const unregisterMultipleRecordsActions = () => {
unregisterDeleteMultipleRecordsAction();
unregisterExportViewNoSelectionRecordsAction();
unregisterExportMultipleRecordsAction();
bosiraphael marked this conversation as resolved.
Show resolved Hide resolved
};

return {
Expand Down
Loading
Loading